int main () { struct cores *cores = cores_make (2); core_run (cores, 0, productor, NULL); core_run (cores, 1, consumidor, NULL); cores_wait (cores); return 0; }
int main(int argc, char **argv) { rstatus_i status = CC_OK;; FILE *fp = NULL; if (argc > 2) { show_usage(); exit(EX_USAGE); } if (argc == 1) { log_stderr("launching server with default values."); } else { /* argc == 2 */ if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { show_usage(); exit(EX_OK); } if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) { show_version(); exit(EX_OK); } if (strcmp(argv[1], "-c") == 0 || strcmp(argv[1], "--config") == 0) { option_describe_all((struct option *)&setting, nopt); exit(EX_OK); } if (strcmp(argv[1], "-s") == 0 || strcmp(argv[1], "--stats") == 0) { metric_describe_all((struct metric *)&stats, nmetric); exit(EX_OK); } fp = fopen(argv[1], "r"); if (fp == NULL) { log_stderr("cannot open config: incorrect path or doesn't exist"); exit(EX_DATAERR); } } if (option_load_default((struct option *)&setting, nopt) != CC_OK) { log_stderr("failed to load default option values"); exit(EX_CONFIG); } if (fp != NULL) { log_stderr("load config from %s", argv[1]); status = option_load_file(fp, (struct option *)&setting, nopt); fclose(fp); } if (status != CC_OK) { log_stderr("failed to load config"); exit(EX_DATAERR); } setup(); option_print_all((struct option *)&setting, nopt); core_run(&worker_processor); exit(EX_OK); }
bool menu_display_libretro(void) { video_driver_set_texture_enable(true, false); if (menu_display_libretro_running()) { if (!input_driver_is_libretro_input_blocked()) input_driver_set_libretro_input_blocked(); core_run(); input_driver_unset_libretro_input_blocked(); return true; } return video_driver_cached_frame_render(); }
bool netplay_wait_and_init_serialization(netplay_t *netplay) { int frame; if (netplay->state_size) return true; /* Wait a maximum of 60 frames */ for (frame = 0; frame < 60; frame++) { if (netplay_try_init_serialization(netplay)) return true; #if defined(HAVE_THREADS) autosave_lock(); #endif core_run(); #if defined(HAVE_THREADS) autosave_unlock(); #endif } return false; }
/** * netplay_net_post_frame: * @netplay : pointer to netplay object * * Post-frame for Netplay (normal version). * We check if we have new input and replay from recorded input. **/ static void netplay_net_post_frame(netplay_t *netplay) { netplay->self_ptr = NEXT_PTR(netplay->self_ptr); netplay->self_frame_count++; /* Only relevant if we're connected */ if (!netplay->has_connection) { netplay->read_frame_count = netplay->other_frame_count = netplay->self_frame_count; netplay->read_ptr = netplay->other_ptr = netplay->self_ptr; return; } #ifndef DEBUG_NONDETERMINISTIC_CORES if (!netplay->force_rewind) { /* Skip ahead if we predicted correctly. * Skip until our simulation failed. */ while (netplay->other_frame_count < netplay->read_frame_count && netplay->other_frame_count < netplay->self_frame_count) { struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr]; if (memcmp(ptr->simulated_input_state, ptr->real_input_state, sizeof(ptr->real_input_state)) != 0 && !ptr->used_real) break; netplay_handle_frame_hash(netplay, ptr); netplay->other_ptr = NEXT_PTR(netplay->other_ptr); netplay->other_frame_count++; } } #endif /* Now replay the real input if we've gotten ahead of it */ if (netplay->force_rewind || (netplay->other_frame_count < netplay->read_frame_count && netplay->other_frame_count < netplay->self_frame_count)) { retro_ctx_serialize_info_t serial_info; /* Replay frames. */ netplay->is_replay = true; netplay->replay_ptr = netplay->other_ptr; netplay->replay_frame_count = netplay->other_frame_count; if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) /* Make sure we're initialized before we start loading things */ netplay_wait_and_init_serialization(netplay); serial_info.data = NULL; serial_info.data_const = netplay->buffer[netplay->replay_ptr].state; serial_info.size = netplay->state_size; if (!core_unserialize(&serial_info)) { RARCH_ERR("Netplay savestate loading failed: Prepare for desync!\n"); } while (netplay->replay_frame_count < netplay->self_frame_count) { struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr]; serial_info.data = ptr->state; serial_info.size = netplay->state_size; serial_info.data_const = NULL; /* Remember the current state */ memset(serial_info.data, 0, serial_info.size); core_serialize(&serial_info); if (netplay->replay_frame_count < netplay->read_frame_count) netplay_handle_frame_hash(netplay, ptr); /* Simulate this frame's input */ if (netplay->replay_frame_count >= netplay->read_frame_count) netplay_simulate_input(netplay, netplay->replay_ptr); autosave_lock(); core_run(); autosave_unlock(); netplay->replay_ptr = NEXT_PTR(netplay->replay_ptr); netplay->replay_frame_count++; #ifdef DEBUG_NONDETERMINISTIC_CORES if (ptr->have_remote && netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->replay_ptr], netplay->replay_frame_count)) { RARCH_LOG("PRE %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr)); if (netplay->is_server) RARCH_LOG("INP %X %X\n", ptr->real_input_state[0], ptr->self_state[0]); else RARCH_LOG("INP %X %X\n", ptr->self_state[0], ptr->real_input_state[0]); ptr = &netplay->buffer[netplay->replay_ptr]; serial_info.data = ptr->state; memset(serial_info.data, 0, serial_info.size); core_serialize(&serial_info); RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr)); } #endif } if (netplay->read_frame_count < netplay->self_frame_count) { netplay->other_ptr = netplay->read_ptr; netplay->other_frame_count = netplay->read_frame_count; } else { netplay->other_ptr = netplay->self_ptr; netplay->other_frame_count = netplay->self_frame_count; } netplay->is_replay = false; netplay->force_rewind = false; } /* If we're supposed to stall, rewind (we shouldn't get this far if we're * stalled, so this is a last resort) */ if (netplay->stall) { retro_ctx_serialize_info_t serial_info; netplay->self_ptr = PREV_PTR(netplay->self_ptr); netplay->self_frame_count--; serial_info.data = NULL; serial_info.data_const = netplay->buffer[netplay->self_ptr].state; serial_info.size = netplay->state_size; core_unserialize(&serial_info); } }
/** * 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; }
/** * netplay_sync_post_frame * @netplay : pointer to netplay object * * Post-frame for Netplay synchronization. * We check if we have new input and replay from recorded input. */ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) { uint32_t lo_frame_count, hi_frame_count; /* Unless we're stalling, we've just finished running a frame */ if (!stalled) { netplay->run_ptr = NEXT_PTR(netplay->run_ptr); netplay->run_frame_count++; } /* We've finished an input frame even if we're stalling */ if ((!stalled || netplay->stall == NETPLAY_STALL_INPUT_LATENCY) && netplay->self_frame_count < netplay->run_frame_count + netplay->input_latency_frames) { netplay->self_ptr = NEXT_PTR(netplay->self_ptr); netplay->self_frame_count++; } /* Only relevant if we're connected and not in a desynching operation */ if ((netplay->is_server && !netplay->connected_players) || (netplay->self_mode < NETPLAY_CONNECTION_CONNECTED) || (netplay->desync)) { netplay->other_frame_count = netplay->self_frame_count; netplay->other_ptr = netplay->self_ptr; /* FIXME: Duplication */ if (netplay->catch_up) { netplay->catch_up = false; input_driver_unset_nonblock_state(); driver_set_nonblock_state(); } return; } /* Reset if it was requested */ if (netplay->force_reset) { core_reset(); netplay->force_reset = false; } #ifndef DEBUG_NONDETERMINISTIC_CORES if (!netplay->force_rewind) { /* Skip ahead if we predicted correctly. * Skip until our simulation failed. */ while (netplay->other_frame_count < netplay->unread_frame_count && netplay->other_frame_count < netplay->run_frame_count) { struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr]; size_t i; for (i = 0; i < MAX_USERS; i++) { if (memcmp(ptr->simulated_input_state[i], ptr->real_input_state[i], sizeof(ptr->real_input_state[i])) != 0 && !ptr->used_real[i]) break; } if (i != MAX_USERS) break; netplay_handle_frame_hash(netplay, ptr); netplay->other_ptr = NEXT_PTR(netplay->other_ptr); netplay->other_frame_count++; } } #endif /* Now replay the real input if we've gotten ahead of it */ if (netplay->force_rewind || (netplay->other_frame_count < netplay->unread_frame_count && netplay->other_frame_count < netplay->run_frame_count)) { retro_ctx_serialize_info_t serial_info; /* Replay frames. */ netplay->is_replay = true; netplay->replay_ptr = netplay->other_ptr; netplay->replay_frame_count = netplay->other_frame_count; if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) /* Make sure we're initialized before we start loading things */ netplay_wait_and_init_serialization(netplay); serial_info.data = NULL; serial_info.data_const = netplay->buffer[netplay->replay_ptr].state; serial_info.size = netplay->state_size; if (!core_unserialize(&serial_info)) { RARCH_ERR("Netplay savestate loading failed: Prepare for desync!\n"); } while (netplay->replay_frame_count < netplay->run_frame_count) { retro_time_t start, tm; struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr]; serial_info.data = ptr->state; serial_info.size = netplay->state_size; serial_info.data_const = NULL; start = cpu_features_get_time_usec(); /* Remember the current state */ memset(serial_info.data, 0, serial_info.size); core_serialize(&serial_info); if (netplay->replay_frame_count < netplay->unread_frame_count) netplay_handle_frame_hash(netplay, ptr); /* Re-simulate this frame's input */ netplay_simulate_input(netplay, netplay->replay_ptr, true); autosave_lock(); core_run(); autosave_unlock(); netplay->replay_ptr = NEXT_PTR(netplay->replay_ptr); netplay->replay_frame_count++; #ifdef DEBUG_NONDETERMINISTIC_CORES if (ptr->have_remote && netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->replay_ptr], netplay->replay_frame_count)) { RARCH_LOG("PRE %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr)); if (netplay->is_server) RARCH_LOG("INP %X %X\n", ptr->real_input_state[0], ptr->self_state[0]); else RARCH_LOG("INP %X %X\n", ptr->self_state[0], ptr->real_input_state[0]); ptr = &netplay->buffer[netplay->replay_ptr]; serial_info.data = ptr->state; memset(serial_info.data, 0, serial_info.size); core_serialize(&serial_info); RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr)); } #endif /* Get our time window */ tm = cpu_features_get_time_usec() - start; netplay->frame_run_time_sum -= netplay->frame_run_time[netplay->frame_run_time_ptr]; netplay->frame_run_time[netplay->frame_run_time_ptr] = tm; netplay->frame_run_time_sum += tm; netplay->frame_run_time_ptr++; if (netplay->frame_run_time_ptr >= NETPLAY_FRAME_RUN_TIME_WINDOW) netplay->frame_run_time_ptr = 0; } /* Average our time */ netplay->frame_run_time_avg = netplay->frame_run_time_sum / NETPLAY_FRAME_RUN_TIME_WINDOW; if (netplay->unread_frame_count < netplay->run_frame_count) { netplay->other_ptr = netplay->unread_ptr; netplay->other_frame_count = netplay->unread_frame_count; } else { netplay->other_ptr = netplay->run_ptr; netplay->other_frame_count = netplay->run_frame_count; } netplay->is_replay = false; netplay->force_rewind = false; } if (netplay->is_server) { uint32_t player; lo_frame_count = hi_frame_count = netplay->unread_frame_count; /* Look for players that are ahead of us */ for (player = 0; player < MAX_USERS; player++) { if (!(netplay->connected_players & (1<<player))) continue; if (netplay->read_frame_count[player] > hi_frame_count) hi_frame_count = netplay->read_frame_count[player]; } } else { lo_frame_count = hi_frame_count = netplay->server_frame_count; } /* If we're behind, try to catch up */ if (netplay->catch_up) { /* Are we caught up? */ if (netplay->self_frame_count + 1 >= lo_frame_count) { netplay->catch_up = false; input_driver_unset_nonblock_state(); driver_set_nonblock_state(); } } else if (!stalled) { if (netplay->self_frame_count + 3 < lo_frame_count) { retro_time_t cur_time = cpu_features_get_time_usec(); uint32_t cur_behind = lo_frame_count - netplay->self_frame_count; /* We're behind, but we'll only try to catch up if we're actually * falling behind, i.e. if we're more behind after some time */ if (netplay->catch_up_time == 0) { /* Record our current time to check for catch-up later */ netplay->catch_up_time = cur_time; netplay->catch_up_behind = cur_behind; } else if (cur_time - netplay->catch_up_time > CATCH_UP_CHECK_TIME_USEC) { /* Time to check how far behind we are */ if (netplay->catch_up_behind <= cur_behind) { /* We're definitely falling behind! */ netplay->catch_up = true; netplay->catch_up_time = 0; input_driver_set_nonblock_state(); driver_set_nonblock_state(); } else { /* Check again in another period */ netplay->catch_up_time = cur_time; netplay->catch_up_behind = cur_behind; } } } else if (netplay->self_frame_count + 3 < hi_frame_count) { size_t i; netplay->catch_up_time = 0; /* We're falling behind some clients but not others, so request that * clients ahead of us stall */ for (i = 0; i < netplay->connections_size; i++) { struct netplay_connection *connection = &netplay->connections[i]; int player; if (!connection->active || connection->mode != NETPLAY_CONNECTION_PLAYING) continue; player = connection->player; /* Are they ahead? */ if (netplay->self_frame_count + 3 < netplay->read_frame_count[player]) { /* Tell them to stall */ if (connection->stall_frame + NETPLAY_MAX_REQ_STALL_FREQUENCY < netplay->self_frame_count) { connection->stall_frame = netplay->self_frame_count; netplay_cmd_stall(netplay, connection, netplay->read_frame_count[player] - netplay->self_frame_count + 1); } } } } else netplay->catch_up_time = 0; } else netplay->catch_up_time = 0; }
/** * post_frame: * @netplay : pointer to netplay object * * Post-frame for Netplay (normal version). * We check if we have new input and replay from recorded input. **/ static void netplay_net_post_frame(netplay_t *netplay) { netplay->frame_count++; /* Nothing to do... */ if (netplay->other_frame_count == netplay->read_frame_count) return; /* Skip ahead if we predicted correctly. * Skip until our simulation failed. */ while (netplay->other_frame_count < netplay->read_frame_count) { const struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr]; if (memcmp(ptr->simulated_input_state, ptr->real_input_state, sizeof(ptr->real_input_state)) != 0 && !ptr->used_real) break; netplay->other_ptr = NEXT_PTR(netplay->other_ptr); netplay->other_frame_count++; } if (netplay->other_frame_count < netplay->read_frame_count) { retro_ctx_serialize_info_t serial_info; bool first = true; /* Replay frames. */ netplay->is_replay = true; netplay->tmp_ptr = netplay->other_ptr; netplay->tmp_frame_count = netplay->other_frame_count; serial_info.data_const = netplay->buffer[netplay->other_ptr].state; serial_info.size = netplay->state_size; core_unserialize(&serial_info); while (first || (netplay->tmp_ptr != netplay->self_ptr)) { serial_info.data = netplay->buffer[netplay->tmp_ptr].state; serial_info.size = netplay->state_size; serial_info.data_const = NULL; core_serialize(&serial_info); #if defined(HAVE_THREADS) autosave_lock(); #endif core_run(); #if defined(HAVE_THREADS) autosave_unlock(); #endif netplay->tmp_ptr = NEXT_PTR(netplay->tmp_ptr); netplay->tmp_frame_count++; first = false; } netplay->other_ptr = netplay->read_ptr; netplay->other_frame_count = netplay->read_frame_count; netplay->is_replay = false; } }
/** * 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; }