/** * runloop_check_fast_forward_button: * @fastforward_pressed : is fastforward key pressed? * @hold_pressed : is fastforward key pressed and held? * @old_hold_pressed : was fastforward key pressed and held the last frame? * * Checks if the fast forward key has been pressed for this frame. * **/ static void runloop_check_fast_forward_button(bool fastforward_pressed, bool hold_pressed, bool old_hold_pressed) { /* To avoid continous switching if we hold the button down, we require * that the button must go from pressed to unpressed back to pressed * to be able to toggle between then. */ if (fastforward_pressed) { if (input_driver_is_nonblock_state()) input_driver_unset_nonblock_state(); else input_driver_set_nonblock_state(); } else if (old_hold_pressed != hold_pressed) { if (hold_pressed) input_driver_set_nonblock_state(); else input_driver_unset_nonblock_state(); } else return; driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); }
/** * driver_set_nonblock_state: * * Sets audio and video drivers to nonblock state (if enabled). * * If nonblock state is false, sets * blocking state for both audio and video drivers instead. **/ void driver_set_nonblock_state(void) { bool enable = input_driver_is_nonblock_state(); /* Only apply non-block-state for video if we're using vsync. */ if (video_driver_is_active() && video_driver_get_ptr(false)) { settings_t *settings = config_get_ptr(); bool video_nonblock = enable; if ( !settings->bools.video_vsync || rarch_ctl(RARCH_CTL_IS_NONBLOCK_FORCED, NULL)) video_nonblock = true; video_driver_set_nonblock_state(video_nonblock); } audio_driver_set_nonblocking_state(enable); }
/** * runloop_iterate: * * Run Libretro core in RetroArch for one frame. * * Returns: 0 on success, 1 if we have to wait until * button input in order to wake up the loop, * -1 if we forcibly quit out of the RetroArch iteration loop. **/ int runloop_iterate(unsigned *sleep_ms) { unsigned i; event_cmd_state_t cmd; retro_time_t current, target, to_sleep_ms; static retro_input_t last_input = {0}; event_cmd_state_t *cmd_ptr = &cmd; static retro_time_t frame_limit_minimum_time = 0.0; static retro_time_t frame_limit_last_time = 0.0; settings_t *settings = config_get_ptr(); cmd.state[1] = last_input; cmd.state[0] = input_keys_pressed(); last_input = cmd.state[0]; runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_TIME_LAST, NULL); if (runloop_ctl(RUNLOOP_CTL_SHOULD_SET_FRAME_LIMIT, NULL)) { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); float fastforward_ratio = (settings->fastforward_ratio == 0.0f) ? 1.0f : settings->fastforward_ratio; frame_limit_last_time = cpu_features_get_time_usec(); frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio)); runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_LIMIT, NULL); } if (input_driver_is_flushing_input()) { input_driver_unset_flushing_input(); if (cmd.state[0].state) { cmd.state[0].state = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL)) BIT64_SET(cmd.state[0].state, RARCH_PAUSE_TOGGLE); input_driver_set_flushing_input(); } } if (runloop_frame_time.callback) { /* Updates frame timing if frame timing callback is in use by the core. * Limits frame time if fast forward ratio throttle is enabled. */ retro_time_t current = cpu_features_get_time_usec(); retro_time_t delta = current - runloop_frame_time_last; bool is_locked_fps = (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL) || input_driver_is_nonblock_state()) | !!recording_driver_get_data_ptr(); if (!runloop_frame_time_last || is_locked_fps) delta = runloop_frame_time.reference; if (!is_locked_fps && runloop_ctl(RUNLOOP_CTL_IS_SLOWMOTION, NULL)) delta /= settings->slowmotion_ratio; runloop_frame_time_last = current; if (is_locked_fps) runloop_frame_time_last = 0; runloop_frame_time.callback(delta); } cmd.state[2].state = cmd.state[0].state & ~cmd.state[1].state; /* trigger */ if (runloop_cmd_triggered(cmd_ptr, RARCH_OVERLAY_NEXT)) command_event(CMD_EVENT_OVERLAY_NEXT, NULL); if (runloop_cmd_triggered(cmd_ptr, RARCH_FULLSCREEN_TOGGLE_KEY)) { bool fullscreen_toggled = !runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL); #ifdef HAVE_MENU fullscreen_toggled = fullscreen_toggled || menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL); #endif if (fullscreen_toggled) command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); } if (runloop_cmd_triggered(cmd_ptr, RARCH_GRAB_MOUSE_TOGGLE)) command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); #ifdef HAVE_MENU if (runloop_cmd_menu_press(cmd_ptr) || rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (rarch_ctl(RARCH_CTL_IS_INITED, NULL) && !rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); } else rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); } #endif #ifdef HAVE_OVERLAY runloop_iterate_linefeed_overlay(settings); #endif if (runloop_iterate_time_to_exit( runloop_cmd_press(cmd_ptr, RARCH_QUIT_KEY)) != 1) { frame_limit_last_time = 0.0; return -1; } #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { int ret = runloop_iterate_menu((enum menu_action) menu_input_frame_retropad(cmd.state[0], cmd.state[2]), sleep_ms); if (ret == -1) goto end; return ret; } #endif if (!runloop_check_state(&cmd, &runloop_shader_dir)) { /* RetroArch has been paused. */ core_poll(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) autosave_lock(); #endif #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_PRE_FRAME, NULL); #endif if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_START, NULL); camera_driver_ctl(RARCH_CAMERA_CTL_POLL, NULL); /* Update binds for analog dpad modes. */ for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_push_analog_dpad(settings->input.binds[i], settings->input.analog_dpad_mode[i]); input_push_analog_dpad(settings->input.autoconf_binds[i], settings->input.analog_dpad_mode[i]); } if ((settings->video.frame_delay > 0) && !input_driver_is_nonblock_state()) retro_sleep(settings->video.frame_delay); core_run(); #ifdef HAVE_CHEEVOS cheevos_test(); #endif for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(settings->input.binds[i]); input_pop_analog_dpad(settings->input.autoconf_binds[i]); } if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_END, NULL); #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL); #endif #if defined(HAVE_THREADS) autosave_unlock(); #endif if (!settings->fastforward_ratio) return 0; #ifdef HAVE_MENU end: #endif current = cpu_features_get_time_usec(); target = frame_limit_last_time + frame_limit_minimum_time; to_sleep_ms = (target - current) / 1000; if (to_sleep_ms > 0) { *sleep_ms = (unsigned)to_sleep_ms; /* Combat jitter a bit. */ frame_limit_last_time += frame_limit_minimum_time; return 1; } frame_limit_last_time = cpu_features_get_time_usec(); return 0; }
/** * drivers_init: * @flags : Bitmask of drivers to initialize. * * Initializes drivers. * @flags determines which drivers get initialized. **/ void drivers_init(int flags) { bool video_is_threaded = false; if (flags & DRIVER_VIDEO_MASK) video_driver_unset_own_driver(); if (flags & DRIVER_AUDIO_MASK) audio_driver_unset_own_driver(); if (flags & DRIVER_INPUT_MASK) input_driver_unset_own_driver(); if (flags & DRIVER_CAMERA_MASK) camera_driver_ctl(RARCH_CAMERA_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_LOCATION_MASK) location_driver_ctl(RARCH_LOCATION_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_WIFI_MASK) wifi_driver_ctl(RARCH_WIFI_CTL_UNSET_OWN_DRIVER, NULL); #ifdef HAVE_MENU /* By default, we want the menu to persist through driver reinits. */ menu_driver_ctl(RARCH_MENU_CTL_SET_OWN_DRIVER, NULL); #endif if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK)) driver_adjust_system_rates(); if (flags & DRIVER_VIDEO_MASK) { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); video_driver_monitor_reset(); video_driver_init(&video_is_threaded); if (!video_driver_is_video_cache_context_ack() && hwr->context_reset) hwr->context_reset(); video_driver_unset_video_cache_context_ack(); rarch_ctl(RARCH_CTL_SET_FRAME_TIME_LAST, NULL); } if (flags & DRIVER_AUDIO_MASK) { audio_driver_init(); audio_driver_new_devices_list(); } /* Only initialize camera driver if we're ever going to use it. */ if ((flags & DRIVER_CAMERA_MASK) && camera_driver_ctl(RARCH_CAMERA_CTL_IS_ACTIVE, NULL)) camera_driver_ctl(RARCH_CAMERA_CTL_INIT, NULL); /* Only initialize location driver if we're ever going to use it. */ if ((flags & DRIVER_LOCATION_MASK) && location_driver_ctl(RARCH_LOCATION_CTL_IS_ACTIVE, NULL)) init_location(); core_info_init_current_core(); #ifdef HAVE_MENU if (flags & DRIVER_VIDEO_MASK) { if (flags & DRIVER_MENU_MASK) menu_driver_init(video_is_threaded); } #endif if (flags & (DRIVER_VIDEO_MASK | DRIVER_AUDIO_MASK)) { /* Keep non-throttled state as good as possible. */ if (input_driver_is_nonblock_state()) driver_set_nonblock_state(); } if (flags & DRIVER_LED_MASK) { led_driver_init(); } if (flags & DRIVER_MIDI_MASK) midi_driver_init(); }
static enum runloop_state runloop_check_state( settings_t *settings, uint64_t current_input, uint64_t old_input, unsigned *sleep_ms) { static bool old_focus = true; #ifdef HAVE_OVERLAY static char prev_overlay_restore = false; bool osk_enable = input_driver_is_onscreen_keyboard_enabled(); #endif #ifdef HAVE_NETWORKING bool tmp = false; #endif bool focused = true; uint64_t trigger_input = current_input & ~old_input; bool pause_pressed = runloop_cmd_triggered(trigger_input, RARCH_PAUSE_TOGGLE); if (input_driver_is_flushing_input()) { input_driver_unset_flushing_input(); if (current_input) { current_input = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (runloop_paused) BIT64_SET(current_input, RARCH_PAUSE_TOGGLE); input_driver_set_flushing_input(); } } if (runloop_cmd_triggered(trigger_input, RARCH_OVERLAY_NEXT)) command_event(CMD_EVENT_OVERLAY_NEXT, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY)) { bool fullscreen_toggled = !runloop_paused; #ifdef HAVE_MENU fullscreen_toggled = fullscreen_toggled || menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL); #endif if (fullscreen_toggled) command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); } if (runloop_cmd_triggered(trigger_input, RARCH_GRAB_MOUSE_TOGGLE)) command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL); #ifdef HAVE_OVERLAY if (osk_enable && !input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED, NULL)) { input_driver_unset_onscreen_keyboard_enabled(); prev_overlay_restore = true; command_event(CMD_EVENT_OVERLAY_DEINIT, NULL); } else if (!osk_enable && input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED, NULL)) { input_driver_set_onscreen_keyboard_enabled(); prev_overlay_restore = false; command_event(CMD_EVENT_OVERLAY_INIT, NULL); } else if (prev_overlay_restore) { if (!settings->input.overlay_hide_in_menu) command_event(CMD_EVENT_OVERLAY_INIT, NULL); prev_overlay_restore = false; } #endif if (runloop_iterate_time_to_exit( runloop_cmd_press(current_input, RARCH_QUIT_KEY)) != 1) return RUNLOOP_STATE_QUIT; #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { menu_ctx_iterate_t iter; bool skip = false; #ifdef HAVE_OVERLAY skip = osk_enable && input_keyboard_return_pressed(); #endif if (!skip) { enum menu_action action = (enum menu_action)menu_event(current_input, trigger_input); bool focused = settings->pause_nonactive ? video_driver_is_focused() : true; focused = focused && !ui_companion_is_on_foreground(); iter.action = action; if (!menu_driver_ctl(RARCH_MENU_CTL_ITERATE, &iter)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); if (focused || !runloop_idle) menu_driver_ctl(RARCH_MENU_CTL_RENDER, NULL); if (!focused) return RUNLOOP_STATE_SLEEP; if (action == MENU_ACTION_QUIT) return RUNLOOP_STATE_QUIT; } } #endif if (runloop_idle) return RUNLOOP_STATE_SLEEP; #ifdef HAVE_MENU if (menu_event_keyboard_is_set(RETROK_F1) == 1) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (rarch_ctl(RARCH_CTL_IS_INITED, NULL) && !rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); menu_event_keyboard_set(false, RETROK_F1); } } } else if ((!menu_event_keyboard_is_set(RETROK_F1) && runloop_cmd_menu_press(current_input, old_input, trigger_input)) || rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (rarch_ctl(RARCH_CTL_IS_INITED, NULL) && !rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); } else { menu_display_toggle_set_reason(MENU_TOGGLE_REASON_USER); rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); } } else menu_event_keyboard_set(false, RETROK_F1); if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (!settings->menu.throttle_framerate && !settings->fastforward_ratio) return RUNLOOP_STATE_MENU_ITERATE; return RUNLOOP_STATE_END; } #endif if (settings->pause_nonactive) focused = video_driver_is_focused(); if (runloop_cmd_triggered(trigger_input, RARCH_SCREENSHOT)) command_event(CMD_EVENT_TAKE_SCREENSHOT, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_MUTE)) command_event(CMD_EVENT_AUDIO_MUTE_TOGGLE, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_OSK)) { if (input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_IS_LINEFEED_ENABLED, NULL)) input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_UNSET_LINEFEED_ENABLED, NULL); else input_keyboard_ctl( RARCH_INPUT_KEYBOARD_CTL_SET_LINEFEED_ENABLED, NULL); } if (runloop_cmd_press(current_input, RARCH_VOLUME_UP)) command_event(CMD_EVENT_VOLUME_UP, NULL); else if (runloop_cmd_press(current_input, RARCH_VOLUME_DOWN)) command_event(CMD_EVENT_VOLUME_DOWN, NULL); #ifdef HAVE_NETWORKING tmp = runloop_cmd_triggered(trigger_input, RARCH_NETPLAY_FLIP); netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, &tmp); tmp = runloop_cmd_triggered(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY); netplay_driver_ctl(RARCH_NETPLAY_CTL_FULLSCREEN_TOGGLE, &tmp); #endif /* Check if libretro pause key was pressed. If so, pause or * unpause the libretro core. */ /* FRAMEADVANCE will set us into pause mode. */ pause_pressed |= !runloop_paused && runloop_cmd_triggered(trigger_input, RARCH_FRAMEADVANCE); if (focused && pause_pressed) command_event(CMD_EVENT_PAUSE_TOGGLE, NULL); else if (focused && !old_focus) command_event(CMD_EVENT_UNPAUSE, NULL); else if (!focused && old_focus) command_event(CMD_EVENT_PAUSE, NULL); old_focus = focused; if (!focused) return RUNLOOP_STATE_SLEEP; if (runloop_paused) { /* check pause state */ bool check_is_oneshot = runloop_cmd_triggered(trigger_input, RARCH_FRAMEADVANCE) || runloop_cmd_press(current_input, RARCH_REWIND); if (runloop_cmd_triggered(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY)) { command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); if (!runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL)) video_driver_cached_frame(); } if (!check_is_oneshot) return RUNLOOP_STATE_SLEEP; } /* To avoid continous switching if we hold the button down, we require * that the button must go from pressed to unpressed back to pressed * to be able to toggle between then. */ if (runloop_cmd_triggered(trigger_input, RARCH_FAST_FORWARD_KEY)) { if (input_driver_is_nonblock_state()) input_driver_unset_nonblock_state(); else input_driver_set_nonblock_state(); driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); } else if ((runloop_cmd_pressed(old_input, RARCH_FAST_FORWARD_HOLD_KEY) != runloop_cmd_press(current_input, RARCH_FAST_FORWARD_HOLD_KEY))) { if (runloop_cmd_press(current_input, RARCH_FAST_FORWARD_HOLD_KEY)) input_driver_set_nonblock_state(); else input_driver_unset_nonblock_state(); driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); } /* Checks if the state increase/decrease keys have been pressed * for this frame. */ if (runloop_cmd_triggered(trigger_input, RARCH_STATE_SLOT_PLUS)) { char msg[128]; msg[0] = '\0'; settings->state_slot++; snprintf(msg, sizeof(msg), "%s: %d", msg_hash_to_str(MSG_STATE_SLOT), settings->state_slot); runloop_msg_queue_push(msg, 2, 180, true); RARCH_LOG("%s\n", msg); } else if (runloop_cmd_triggered(trigger_input, RARCH_STATE_SLOT_MINUS)) { char msg[128]; msg[0] = '\0'; if (settings->state_slot > 0) settings->state_slot--; snprintf(msg, sizeof(msg), "%s: %d", msg_hash_to_str(MSG_STATE_SLOT), settings->state_slot); runloop_msg_queue_push(msg, 2, 180, true); RARCH_LOG("%s\n", msg); } if (runloop_cmd_triggered(trigger_input, RARCH_SAVE_STATE_KEY)) command_event(CMD_EVENT_SAVE_STATE, NULL); else if (runloop_cmd_triggered(trigger_input, RARCH_LOAD_STATE_KEY)) command_event(CMD_EVENT_LOAD_STATE, NULL); #ifdef HAVE_CHEEVOS if (!settings->cheevos.hardcore_mode_enable) #endif state_manager_check_rewind(runloop_cmd_press(current_input, RARCH_REWIND)); runloop_slowmotion = runloop_cmd_press(current_input, RARCH_SLOWMOTION); if (runloop_slowmotion) { /* Checks if slowmotion toggle/hold was being pressed and/or held. */ if (settings->video.black_frame_insertion) { if (!runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL)) video_driver_cached_frame(); } if (state_manager_frame_is_reversed()) runloop_msg_queue_push(msg_hash_to_str(MSG_SLOW_MOTION_REWIND), 2, 30, true); else runloop_msg_queue_push(msg_hash_to_str(MSG_SLOW_MOTION), 2, 30, true); } if (runloop_cmd_triggered(trigger_input, RARCH_MOVIE_RECORD_TOGGLE)) bsv_movie_check(); if (runloop_cmd_triggered(trigger_input, RARCH_SHADER_NEXT) || runloop_cmd_triggered(trigger_input, RARCH_SHADER_PREV)) dir_check_shader( runloop_cmd_triggered(trigger_input, RARCH_SHADER_NEXT), runloop_cmd_triggered(trigger_input, RARCH_SHADER_PREV)); if (runloop_cmd_triggered(trigger_input, RARCH_DISK_EJECT_TOGGLE)) command_event(CMD_EVENT_DISK_EJECT_TOGGLE, NULL); else if (runloop_cmd_triggered(trigger_input, RARCH_DISK_NEXT)) command_event(CMD_EVENT_DISK_NEXT, NULL); else if (runloop_cmd_triggered(trigger_input, RARCH_DISK_PREV)) command_event(CMD_EVENT_DISK_PREV, NULL); if (runloop_cmd_triggered(trigger_input, RARCH_RESET)) command_event(CMD_EVENT_RESET, NULL); cheat_manager_state_checks( runloop_cmd_triggered(trigger_input, RARCH_CHEAT_INDEX_PLUS), runloop_cmd_triggered(trigger_input, RARCH_CHEAT_INDEX_MINUS), runloop_cmd_triggered(trigger_input, RARCH_CHEAT_TOGGLE)); return RUNLOOP_STATE_ITERATE; }
/** * runloop_iterate: * * Run Libretro core in RetroArch for one frame. * * Returns: 0 on success, 1 if we have to wait until * button input in order to wake up the loop, * -1 if we forcibly quit out of the RetroArch iteration loop. **/ int runloop_iterate(unsigned *sleep_ms) { unsigned i; retro_time_t current, target, to_sleep_ms; static uint64_t last_input = 0; enum runloop_state runloop_status = RUNLOOP_STATE_NONE; static retro_time_t frame_limit_minimum_time = 0.0; static retro_time_t frame_limit_last_time = 0.0; settings_t *settings = config_get_ptr(); uint64_t current_input = menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL) ? input_menu_keys_pressed() : input_keys_pressed(); uint64_t old_input = last_input; last_input = current_input; if (runloop_frame_time_last_enable) { runloop_frame_time_last = 0; runloop_frame_time_last_enable = false; } if (runloop_set_frame_limit) { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); float fastforward_ratio = (settings->fastforward_ratio == 0.0f) ? 1.0f : settings->fastforward_ratio; frame_limit_last_time = cpu_features_get_time_usec(); frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio)); runloop_set_frame_limit = false; } if (runloop_frame_time.callback) { /* Updates frame timing if frame timing callback is in use by the core. * Limits frame time if fast forward ratio throttle is enabled. */ retro_time_t current = cpu_features_get_time_usec(); retro_time_t delta = current - runloop_frame_time_last; bool is_locked_fps = (runloop_paused || input_driver_is_nonblock_state()) | !!recording_driver_get_data_ptr(); if (!runloop_frame_time_last || is_locked_fps) delta = runloop_frame_time.reference; if (!is_locked_fps && runloop_slowmotion) delta /= settings->slowmotion_ratio; runloop_frame_time_last = current; if (is_locked_fps) runloop_frame_time_last = 0; runloop_frame_time.callback(delta); } runloop_status = runloop_check_state(settings, current_input, old_input, sleep_ms); switch (runloop_status) { case RUNLOOP_STATE_QUIT: frame_limit_last_time = 0.0; command_event(CMD_EVENT_QUIT, NULL); return -1; case RUNLOOP_STATE_SLEEP: case RUNLOOP_STATE_END: case RUNLOOP_STATE_MENU_ITERATE: core_poll(); #ifdef HAVE_NETWORKING /* FIXME: This is an ugly way to tell Netplay this... */ netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL); #endif if (runloop_status == RUNLOOP_STATE_SLEEP) *sleep_ms = 10; if (runloop_status == RUNLOOP_STATE_END) goto end; if (runloop_status == RUNLOOP_STATE_MENU_ITERATE) return 0; return 1; case RUNLOOP_STATE_ITERATE: case RUNLOOP_STATE_NONE: default: break; } autosave_lock(); if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_START, NULL); camera_driver_ctl(RARCH_CAMERA_CTL_POLL, NULL); /* Update binds for analog dpad modes. */ for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_push_analog_dpad(settings->input.binds[i], settings->input.analog_dpad_mode[i]); input_push_analog_dpad(settings->input.autoconf_binds[i], settings->input.analog_dpad_mode[i]); } if ((settings->video.frame_delay > 0) && !input_driver_is_nonblock_state()) retro_sleep(settings->video.frame_delay); core_run(); #ifdef HAVE_CHEEVOS cheevos_test(); #endif for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(settings->input.binds[i]); input_pop_analog_dpad(settings->input.autoconf_binds[i]); } if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_END, NULL); autosave_unlock(); if (!settings->fastforward_ratio) return 0; end: current = cpu_features_get_time_usec(); target = frame_limit_last_time + frame_limit_minimum_time; to_sleep_ms = (target - current) / 1000; if (to_sleep_ms > 0) { *sleep_ms = (unsigned)to_sleep_ms; /* Combat jitter a bit. */ frame_limit_last_time += frame_limit_minimum_time; return 1; } frame_limit_last_time = cpu_features_get_time_usec(); return 0; }
/** * init_drivers: * @flags : Bitmask of drivers to initialize. * * Initializes drivers. * @flags determines which drivers get initialized. **/ static void init_drivers(int flags) { if (flags & DRIVER_VIDEO) video_driver_unset_own_driver(); if (flags & DRIVER_AUDIO) audio_driver_unset_own_driver(); if (flags & DRIVER_INPUT) input_driver_unset_own_driver(); if (flags & DRIVER_CAMERA) camera_driver_ctl(RARCH_CAMERA_CTL_UNSET_OWN_DRIVER, NULL); if (flags & DRIVER_LOCATION) location_driver_ctl(RARCH_LOCATION_CTL_UNSET_OWN_DRIVER, NULL); #ifdef HAVE_MENU /* By default, we want the menu to persist through driver reinits. */ menu_driver_ctl(RARCH_MENU_CTL_SET_OWN_DRIVER, NULL); #endif if (flags & (DRIVER_VIDEO | DRIVER_AUDIO)) driver_adjust_system_rates(); if (flags & DRIVER_VIDEO) { struct retro_hw_render_callback *hwr = video_driver_get_hw_context(); video_driver_monitor_reset(); video_driver_init(); if (!video_driver_is_video_cache_context_ack() && hwr->context_reset) hwr->context_reset(); video_driver_unset_video_cache_context_ack(); runloop_ctl(RUNLOOP_CTL_SET_FRAME_TIME_LAST, NULL); } if (flags & DRIVER_AUDIO) { audio_driver_init(); audio_driver_new_devices_list(); } /* Only initialize camera driver if we're ever going to use it. */ if ((flags & DRIVER_CAMERA) && camera_driver_ctl(RARCH_CAMERA_CTL_IS_ACTIVE, NULL)) camera_driver_ctl(RARCH_CAMERA_CTL_INIT, NULL); /* Only initialize location driver if we're ever going to use it. */ if ((flags & DRIVER_LOCATION) && location_driver_ctl(RARCH_LOCATION_CTL_IS_ACTIVE, NULL)) init_location(); #ifdef HAVE_MENU if (flags & DRIVER_MENU) { menu_driver_ctl(RARCH_MENU_CTL_INIT, NULL); menu_driver_ctl(RARCH_MENU_CTL_CONTEXT_RESET, NULL); } #endif if (flags & (DRIVER_VIDEO | DRIVER_AUDIO)) { /* Keep non-throttled state as good as possible. */ if (input_driver_is_nonblock_state()) driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); } }