uint64_t menu_input(void) { unsigned i; retro_input_t input_state = 0; static const struct retro_keybind *binds[] = { g_settings.input.binds[0] }; if (!driver.menu) return 0; input_push_analog_dpad((struct retro_keybind*)binds[0], (g_settings.input.analog_dpad_mode[0] == ANALOG_DPAD_NONE) ? ANALOG_DPAD_LSTICK : g_settings.input.analog_dpad_mode[0]); for (i = 0; i < MAX_PLAYERS; i++) input_push_analog_dpad(g_settings.input.autoconf_binds[i], g_settings.input.analog_dpad_mode[i]); input_state = input_keys_pressed(0, RARCH_FIRST_CUSTOM_BIND, binds); input_pop_analog_dpad((struct retro_keybind*)binds[0]); for (i = 0; i < MAX_PLAYERS; i++) input_pop_analog_dpad(g_settings.input.autoconf_binds[i]); driver.menu->trigger_state = input_state & ~driver.menu->old_input_state; driver.menu->do_held = (input_state & ( (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) | (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) | (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_L) | (1ULL << RETRO_DEVICE_ID_JOYPAD_R) )); return input_state; }
/** * 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; event_cmd_state_t *cmd_ptr = &cmd; retro_time_t current, target, to_sleep_ms; static retro_usec_t frame_time_last = 0; static retro_time_t frame_limit_minimum_time = 0.0; static retro_time_t frame_limit_last_time = 0.0; static retro_input_t last_input = 0; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); rarch_system_info_t *system = NULL; cmd.state[1] = last_input; cmd.state[0] = input_keys_pressed(); last_input = cmd.state[0]; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system); if (runloop_ctl(RUNLOOP_CTL_IS_FRAME_TIME_LAST, NULL)) { frame_time_last = 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 = retro_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_ctl(RARCH_INPUT_CTL_IS_FLUSHING_INPUT, NULL)) { input_driver_ctl(RARCH_INPUT_CTL_UNSET_FLUSHING_INPUT, NULL); if (cmd.state[0]) { cmd.state[0] = 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], RARCH_PAUSE_TOGGLE); input_driver_ctl(RARCH_INPUT_CTL_SET_FLUSHING_INPUT, NULL); } } if (system->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. */ bool is_slowmotion; retro_time_t current = retro_get_time_usec(); retro_time_t delta = current - frame_time_last; bool is_locked_fps = (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL) || input_driver_ctl(RARCH_INPUT_CTL_IS_NONBLOCK_STATE, NULL)) | !!recording_driver_get_data_ptr(); runloop_ctl(RUNLOOP_CTL_IS_SLOWMOTION, &is_slowmotion); if (!frame_time_last || is_locked_fps) delta = system->frame_time.reference; if (!is_locked_fps && is_slowmotion) delta /= settings->slowmotion_ratio; frame_time_last = current; if (is_locked_fps) frame_time_last = 0; system->frame_time.callback(delta); } cmd.state[2] = cmd.state[0] & ~cmd.state[1]; /* trigger */ if (runloop_cmd_triggered(cmd_ptr, RARCH_OVERLAY_NEXT)) event_command(EVENT_CMD_OVERLAY_NEXT); 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) event_command(EVENT_CMD_FULLSCREEN_TOGGLE); } if (runloop_cmd_triggered(cmd_ptr, RARCH_GRAB_MOUSE_TOGGLE)) event_command(EVENT_CMD_GRAB_MOUSE_TOGGLE); #ifdef HAVE_MENU if (runloop_cmd_menu_press(cmd_ptr) || (global->inited.core.type == CORE_TYPE_DUMMY)) { if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (global->inited.main && (global->inited.core.type != CORE_TYPE_DUMMY)) 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)) { bool focused = runloop_ctl(RUNLOOP_CTL_CHECK_FOCUS, NULL) && !ui_companion_is_on_foreground(); bool is_idle = runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL); if (menu_driver_iterate((enum menu_action)menu_input_frame_retropad(cmd.state[0], cmd.state[2])) == -1) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); if (focused || !is_idle) menu_driver_ctl(RARCH_MENU_CTL_RENDER, NULL); if (!focused || is_idle) { *sleep_ms = 10; return 1; } goto end; } #endif if (!runloop_ctl(RUNLOOP_CTL_CHECK_STATE, &cmd)) { /* RetroArch has been paused. */ retro_ctx.poll_cb(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) lock_autosave(); #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); if (system->camera_callback.caps) driver_camera_poll(); /* 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_ctl(RARCH_INPUT_CTL_IS_NONBLOCK_STATE, NULL)) retro_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ core.retro_run(); #ifdef HAVE_CHEEVOS /* Test the achievements. */ 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) unlock_autosave(); #endif #ifdef HAVE_MENU end: #endif if (!settings->fastforward_ratio) return 0; current = retro_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 = retro_get_time_usec(); return 0; }
/** * 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; }
/** * rarch_main_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 rarch_main_iterate(unsigned *sleep_ms) { int ret; unsigned i; retro_input_t trigger_input; event_cmd_state_t cmd; retro_time_t current, target, to_sleep_ms; static retro_input_t last_input = 0; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); retro_input_t input = input_keys_pressed(driver, settings, global); rarch_system_info_t *system = rarch_system_info_get_ptr(); retro_input_t old_input = last_input; last_input = input; if (driver->flushing_input) { driver->flushing_input = false; if (input) { input = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (main_is_paused) BIT64_SET(input, RARCH_PAUSE_TOGGLE); driver->flushing_input = true; } } trigger_input = input & ~old_input; rarch_main_cmd_get_state(driver, settings, &cmd, input, old_input, trigger_input); if (system->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 = retro_get_time_usec(); retro_time_t delta = current - system->frame_time_last; bool is_locked_fps = (main_is_paused || driver->nonblock_state) | !!driver->recording_data; if (!system->frame_time_last || is_locked_fps) delta = system->frame_time.reference; if (!is_locked_fps && main_is_slowmotion) delta /= settings->slowmotion_ratio; system->frame_time_last = current; if (is_locked_fps) system->frame_time_last = 0; system->frame_time.callback(delta); } if (cmd.overlay_next_pressed) event_command(EVENT_CMD_OVERLAY_NEXT); if (!main_is_paused || menu_driver_alive()) { if (cmd.fullscreen_toggle) event_command(EVENT_CMD_FULLSCREEN_TOGGLE); } if (cmd.grab_mouse_pressed) event_command(EVENT_CMD_GRAB_MOUSE_TOGGLE); #ifdef HAVE_MENU if (cmd.menu_pressed || (global->inited.core.type == CORE_TYPE_DUMMY)) { if (menu_driver_alive()) { if (global->inited.main && (global->inited.core.type != CORE_TYPE_DUMMY)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); } else rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); } #endif #ifdef HAVE_OVERLAY rarch_main_iterate_linefeed_overlay(driver, settings); #endif ret = rarch_main_iterate_time_to_exit(&cmd); if (ret != 1) return -1; #ifdef HAVE_MENU if (menu_driver_alive()) { if (menu_driver_iterate((enum menu_action)menu_input_frame(input, trigger_input)) == -1) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); if (!input && settings->menu.pause_libretro) return 1; goto end; } #endif if (!rarch_main_ctl(RARCH_MAIN_CTL_CHECK_STATE, &cmd)) { /* RetroArch has been paused. */ driver->retro_ctx.poll_cb(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_pre_frame((netplay_t*)driver->netplay_data); #endif if (global->bsv.movie) bsv_movie_set_frame_start(global->bsv.movie); if (system->camera_callback.caps) driver_camera_poll(); /* 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) && !driver->nonblock_state) retro_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ core.retro_run(); #ifdef HAVE_CHEEVOS /* Test the achievements. */ 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 (global->bsv.movie) bsv_movie_set_frame_end(global->bsv.movie); #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_post_frame((netplay_t*)driver->netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif #ifdef HAVE_MENU end: #endif if (!settings->fastforward_ratio) return 0; current = retro_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 = retro_get_time_usec(); return 0; }
/** * rarch_main_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 rarch_main_iterate(void) { unsigned i; retro_input_t trigger_input, old_input; event_cmd_state_t cmd = {0}; int ret = 0; static retro_input_t last_input = 0; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); runloop_t *runloop = rarch_main_get_ptr(); retro_input_t input = input_keys_pressed(driver, settings, global); rarch_system_info_t *system = rarch_system_info_get_ptr(); old_input = last_input; last_input = input; if (driver->flushing_input) driver->flushing_input = (input) ? input_flush(runloop, &input) : false; trigger_input = input & ~old_input; rarch_main_cmd_get_state(&cmd, input, old_input, trigger_input); if (time_to_exit(driver, global, runloop, &cmd)) return rarch_main_iterate_quit(settings, global); if (system->frame_time.callback) rarch_update_frame_time(driver, settings, runloop); do_pre_state_checks(settings, global, runloop, &cmd); #ifdef HAVE_OVERLAY rarch_main_iterate_linefeed_overlay(driver, settings); #endif #ifdef HAVE_MENU if (menu_driver_alive()) { menu_handle_t *menu = menu_driver_get_ptr(); if (menu) if (menu_iterate(input, old_input, trigger_input) == -1) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); if (!input && settings->menu.pause_libretro) ret = 1; goto success; } #endif if (global->exec) { global->exec = false; return rarch_main_iterate_quit(settings, global); } if (do_state_checks(driver, settings, global, runloop, &cmd)) { /* RetroArch has been paused */ driver->retro_ctx.poll_cb(); rarch_sleep(10); return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_pre_frame((netplay_t*)driver->netplay_data); #endif if (global->bsv.movie) bsv_movie_set_frame_start(global->bsv.movie); if (system->camera_callback.caps) driver_camera_poll(); /* 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) && !driver->nonblock_state) rarch_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ pretro_run(); 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 (global->bsv.movie) bsv_movie_set_frame_end(global->bsv.movie); #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_post_frame((netplay_t*)driver->netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif success: if (settings->fastforward_ratio_throttle_enable) rarch_limit_frame_time(settings, runloop); return ret; }
/** * 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; }
/** * rarch_main_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 rarch_main_iterate(unsigned *sleep_ms) { unsigned i; retro_input_t trigger_input; event_cmd_state_t cmd; bool do_quit = false; static retro_input_t last_input = 0; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); retro_input_t input = input_keys_pressed(driver, settings, global); rarch_system_info_t *system = rarch_system_info_get_ptr(); retro_input_t old_input = last_input; last_input = input; if (driver->flushing_input) { driver->flushing_input = false; if (input) { input = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (main_is_paused) BIT64_SET(input, RARCH_PAUSE_TOGGLE); driver->flushing_input = true; } } trigger_input = input & ~old_input; rarch_main_cmd_get_state(driver, settings, &cmd, input, old_input, trigger_input); if (time_to_exit(driver, global, system, &cmd)) do_quit = true; if (system->frame_time.callback) rarch_update_frame_time(driver, settings->slowmotion_ratio, system); do_pre_state_checks(settings, global, &cmd); #ifdef HAVE_OVERLAY rarch_main_iterate_linefeed_overlay(driver, settings); #endif if (global->exec) { global->exec = false; do_quit = true; } if (do_quit) { /* Quits out of RetroArch main loop. * On special case, loads dummy core * instead of exiting RetroArch completely. * Aborts core shutdown if invoked. */ if (global->core_shutdown_initiated && settings->load_dummy_on_core_shutdown) { if (!event_command(EVENT_CMD_PREPARE_DUMMY)) return -1; system->shutdown = false; global->core_shutdown_initiated = false; return 0; } return -1; } #ifdef HAVE_MENU if (menu_driver_alive()) { menu_handle_t *menu = menu_driver_get_ptr(); if (menu) if (menu_iterate(true, menu_input_frame(input, trigger_input)) == -1) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); if (!input && settings->menu.pause_libretro) return 1; return rarch_limit_frame_time(settings->fastforward_ratio, sleep_ms); } #endif if (do_state_checks(driver, settings, global, &cmd)) { /* RetroArch has been paused. */ driver->retro_ctx.poll_cb(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_pre_frame((netplay_t*)driver->netplay_data); #endif if (global->bsv.movie) bsv_movie_set_frame_start(global->bsv.movie); if (system->camera_callback.caps) driver_camera_poll(); /* 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) && !driver->nonblock_state) rarch_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ pretro_run(); 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 (global->bsv.movie) bsv_movie_set_frame_end(global->bsv.movie); #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_post_frame((netplay_t*)driver->netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif return rarch_limit_frame_time(settings->fastforward_ratio, sleep_ms); }
int rarch_main_iterate(void) { unsigned i; retro_input_t trigger_input; int ret = 0; static retro_input_t last_input = 0; retro_input_t old_input = last_input; retro_input_t input = input_keys_pressed(); last_input = input; if (driver.flushing_input) driver.flushing_input = (input) ? input_flush(&input) : false; trigger_input = input & ~old_input; if (time_to_exit(input)) return -1; if (g_extern.system.frame_time.callback) update_frame_time(); #ifdef HAVE_MENU if (check_enter_menu_func(trigger_input) || (g_extern.libretro_dummy)) do_state_check_menu_toggle(); if (g_extern.is_menu) { if (menu_iterate(input, old_input, trigger_input) == -1) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); if (!input && g_settings.menu.pause_libretro) ret = 1; goto success; } #endif if (g_extern.exec) { g_extern.exec = false; return -1; } if (do_state_checks(input, old_input, trigger_input)) { /* RetroArch has been paused */ driver.retro_ctx.poll_cb(); rarch_sleep(10); return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver.netplay_data) netplay_pre_frame((netplay_t*)driver.netplay_data); #endif if (g_extern.bsv.movie) bsv_movie_set_frame_start(g_extern.bsv.movie); if (g_extern.system.camera_callback.caps) driver_camera_poll(); /* Update binds for analog dpad modes. */ for (i = 0; i < MAX_PLAYERS; i++) { if (!g_settings.input.analog_dpad_mode[i]) continue; input_push_analog_dpad(g_settings.input.binds[i], g_settings.input.analog_dpad_mode[i]); input_push_analog_dpad(g_settings.input.autoconf_binds[i], g_settings.input.analog_dpad_mode[i]); } if ((g_settings.video.frame_delay > 0) && !driver.nonblock_state) rarch_sleep(g_settings.video.frame_delay); /* Run libretro for one frame. */ pretro_run(); for (i = 0; i < MAX_PLAYERS; i++) { if (!g_settings.input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(g_settings.input.binds[i]); input_pop_analog_dpad(g_settings.input.autoconf_binds[i]); } if (g_extern.bsv.movie) bsv_movie_set_frame_end(g_extern.bsv.movie); #ifdef HAVE_NETPLAY if (driver.netplay_data) netplay_post_frame((netplay_t*)driver.netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif success: if (g_settings.fastforward_ratio_throttle_enable) limit_frame_time(); return ret; }