static int action_ok_file_load_with_detect_core(const char *path, const char *label, unsigned type, size_t idx) { int ret; menu_displaylist_info_t info = {0}; const char *menu_path = NULL; menu_handle_t *menu = menu_driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!menu) return -1; menu_list_get_last_stack(menu->menu_list, &menu_path, NULL, NULL); ret = rarch_defer_core(global->core_info, menu_path, path, label, menu->deferred_path, sizeof(menu->deferred_path)); if (ret == -1) { if (!strcmp(label, "collection")) { info.list = menu->menu_list->menu_stack; info.type = 0; info.directory_ptr = idx; rdb_entry_start_game_selection_ptr = idx; strlcpy(info.path, settings->libretro_directory, sizeof(info.path)); strlcpy(info.label, "deferred_core_list_set", sizeof(info.label)); return menu_displaylist_push_list(&info, DISPLAYLIST_GENERIC); } else { event_command(EVENT_CMD_LOAD_CORE); menu_entries_common_load_content(false); return -1; } } if (ret == 0) { info.list = menu->menu_list->menu_stack; info.type = 0; info.directory_ptr = idx; strlcpy(info.path, settings->libretro_directory, sizeof(info.path)); if (!strcmp(label, "collection")) { rdb_entry_start_game_selection_ptr = idx; strlcpy(info.label, "deferred_core_list_set", sizeof(info.label)); } else strlcpy(info.label, "deferred_core_list", sizeof(info.label)); ret = menu_displaylist_push_list(&info, DISPLAYLIST_GENERIC); } return ret; }
static int action_iterate_menu_viewport(char *s, size_t len, const char *label, unsigned action, uint32_t hash) { int stride_x = 1, stride_y = 1; menu_displaylist_info_t info = {0}; struct retro_game_geometry *geom = NULL; const char *base_msg = NULL; unsigned type = 0; video_viewport_t *custom = video_viewport_get_custom(); menu_display_t *disp = menu_display_get_ptr(); menu_navigation_t *nav = menu_navigation_get_ptr(); menu_list_t *menu_list = menu_list_get_ptr(); settings_t *settings = config_get_ptr(); struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); if (!menu_list) return -1; menu_list_get_last_stack(menu_list, NULL, NULL, &type, NULL); geom = (struct retro_game_geometry*)&av_info->geometry; if (settings->video.scale_integer) { stride_x = geom->base_width; stride_y = geom->base_height; } switch (action) { case MENU_ACTION_UP: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->y -= stride_y; custom->height += stride_y; } else if (custom->height >= (unsigned)stride_y) custom->height -= stride_y; event_command(EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_DOWN: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->y += stride_y; if (custom->height >= (unsigned)stride_y) custom->height -= stride_y; } else custom->height += stride_y; event_command(EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_LEFT: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->x -= stride_x; custom->width += stride_x; } else if (custom->width >= (unsigned)stride_x) custom->width -= stride_x; event_command(EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_RIGHT: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->x += stride_x; if (custom->width >= (unsigned)stride_x) custom->width -= stride_x; } else custom->width += stride_x; event_command(EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_CANCEL: menu_list_pop_stack(menu_list); if (hash == MENU_LABEL_CUSTOM_VIEWPORT_2) { info.list = menu_list->menu_stack; info.type = MENU_SETTINGS_CUSTOM_VIEWPORT; info.directory_ptr = nav->selection_ptr; menu_displaylist_push_list(&info, DISPLAYLIST_INFO); } break; case MENU_ACTION_OK: menu_list_pop_stack(menu_list); if (type == MENU_SETTINGS_CUSTOM_VIEWPORT && !settings->video.scale_integer) { info.list = menu_list->menu_stack; strlcpy(info.label, menu_hash_to_str(MENU_LABEL_CUSTOM_VIEWPORT_2), sizeof(info.label)); info.type = 0; info.directory_ptr = nav->selection_ptr; menu_displaylist_push_list(&info, DISPLAYLIST_INFO); } break; case MENU_ACTION_START: if (!settings->video.scale_integer) { video_viewport_t vp; video_driver_viewport_info(&vp); if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->width += custom->x; custom->height += custom->y; custom->x = 0; custom->y = 0; } else { custom->width = vp.full_width - custom->x; custom->height = vp.full_height - custom->y; } event_command(EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); } break; case MENU_ACTION_MESSAGE: if (disp) disp->msg_force = true; break; default: break; } menu_list_get_last_stack(menu_list, NULL, &label, &type, NULL); menu_driver_render(); if (settings->video.scale_integer) { custom->x = 0; custom->y = 0; custom->width = ((custom->width + geom->base_width - 1) / geom->base_width) * geom->base_width; custom->height = ((custom->height + geom->base_height - 1) / geom->base_height) * geom->base_height; base_msg = "Set scale"; snprintf(s, len, "%s (%4ux%4u, %u x %u scale)", base_msg, custom->width, custom->height, custom->width / geom->base_width, custom->height / geom->base_height); } else { if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) base_msg = menu_hash_to_str(MENU_LABEL_VALUE_CUSTOM_VIEWPORT_1); else if (hash == MENU_LABEL_CUSTOM_VIEWPORT_2) base_msg = menu_hash_to_str(MENU_LABEL_VALUE_CUSTOM_VIEWPORT_2); snprintf(s, len, "%s (%d, %d : %4ux%4u)", base_msg, custom->x, custom->y, custom->width, custom->height); } menu_driver_render_messagebox(s); if (!custom->width) custom->width = stride_x; if (!custom->height) custom->height = stride_y; aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (float)custom->width / custom->height; event_command(EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); return 0; }
/** * main_entry: * * Main function of RetroArch. * * If HAVE_MAIN is not defined, will contain main loop and will not * be exited from until we exit the program. Otherwise, will * just do initialization. * * Returns: varies per platform. **/ int rarch_main(int argc, char *argv[], void *data) { void *args = (void*)data; int ret = 0; settings_t *settings = NULL; rarch_ctl(RARCH_CTL_PREINIT, NULL); frontend_driver_init_first(args); rarch_ctl(RARCH_CTL_INIT, NULL); #ifdef HAVE_THREADS async_jobs = async_job_new(); #endif if (frontend_driver_is_inited()) { ret = main_load_content(argc, argv, args, frontend_driver_environment_get_ptr()); if (!ret) return ret; } event_command(EVENT_CMD_HISTORY_INIT); settings = config_get_ptr(); if (settings->history_list_enable) { char *fullpath = NULL; global_t *global = global_get_ptr(); rarch_system_info_t *system = NULL; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system); runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); if (global->inited.content || system->no_content) history_playlist_push( g_defaults.history, fullpath, settings->libretro, system ? &system->info : NULL); } ui_companion_driver_init_first(); #ifndef HAVE_MAIN do { unsigned sleep_ms = 0; ret = runloop_iterate(&sleep_ms); if (ret == 1 && sleep_ms > 0) retro_sleep(sleep_ms); runloop_ctl(RUNLOOP_CTL_DATA_ITERATE, NULL); }while(ret != -1); main_exit(args); #endif #ifdef HAVE_THREADS async_job_free(async_jobs); async_jobs = NULL; #endif return 0; }
/** * do_state_checks: * * Checks for state changes in this frame. * * Returns: 1 if RetroArch is in pause mode, 0 otherwise. **/ static int do_state_checks(driver_t *driver, settings_t *settings, global_t *global, runloop_t *runloop, event_cmd_state_t *cmd) { if (runloop->is_idle) return 1; if (cmd->screenshot_pressed) event_command(EVENT_CMD_TAKE_SCREENSHOT); if (cmd->mute_pressed) event_command(EVENT_CMD_AUDIO_MUTE_TOGGLE); if (cmd->osk_pressed) driver->keyboard_linefeed_enable = !driver->keyboard_linefeed_enable; if (cmd->volume_up_pressed) event_command(EVENT_CMD_VOLUME_UP); else if (cmd->volume_down_pressed) event_command(EVENT_CMD_VOLUME_DOWN); #ifdef HAVE_NETPLAY if (driver->netplay_data) return do_netplay_state_checks(cmd->netplay_flip_pressed, cmd->fullscreen_toggle); #endif check_pause(driver, settings, runloop, cmd->pause_pressed, cmd->frameadvance_pressed); if (do_pause_state_checks( runloop, cmd->pause_pressed, cmd->frameadvance_pressed, cmd->fullscreen_toggle, cmd->rewind_pressed)) return 1; check_fast_forward_button(driver, cmd->fastforward_pressed, cmd->hold_pressed, cmd->old_hold_pressed); check_stateslots(settings, cmd->state_slot_increase, cmd->state_slot_decrease); if (cmd->save_state_pressed) event_command(EVENT_CMD_SAVE_STATE); else if (cmd->load_state_pressed) event_command(EVENT_CMD_LOAD_STATE); check_rewind(settings, global, runloop, cmd->rewind_pressed); check_slowmotion(settings, global, runloop, cmd->slowmotion_pressed); if (cmd->movie_record) check_movie(global); check_shader_dir(global, cmd->shader_next_pressed, cmd->shader_prev_pressed); if (cmd->disk_eject_pressed) event_command(EVENT_CMD_DISK_EJECT_TOGGLE); else if (cmd->disk_next_pressed) event_command(EVENT_CMD_DISK_NEXT); else if (cmd->disk_prev_pressed) event_command(EVENT_CMD_DISK_PREV); if (cmd->reset_pressed) event_command(EVENT_CMD_RESET); if (global->cheat) { if (cmd->cheat_index_plus_pressed) cheat_manager_index_next(global->cheat); else if (cmd->cheat_index_minus_pressed) cheat_manager_index_prev(global->cheat); else if (cmd->cheat_toggle_pressed) cheat_manager_toggle(global->cheat); } return 0; }
void recording_dump_frame(const void *data, unsigned width, unsigned height, size_t pitch) { struct ffemu_video_data ffemu_data = {0}; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); if (!driver->recording_data) return; ffemu_data.pitch = pitch; ffemu_data.width = width; ffemu_data.height = height; ffemu_data.data = data; if (global->record.gpu_buffer) { struct video_viewport vp = {0}; video_driver_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_WARN("%s \n", msg_hash_to_str(MSG_VIEWPORT_SIZE_CALCULATION_FAILED)); event_command(EVENT_CMD_GPU_RECORD_DEINIT); recording_dump_frame(data, width, height, pitch); return; } /* User has resized. We kinda have a problem now. */ if (vp.width != global->record.gpu_width || vp.height != global->record.gpu_height) { RARCH_WARN("%s\n", msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE)); rarch_main_msg_queue_push_new(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, 1, 180, true); event_command(EVENT_CMD_RECORD_DEINIT); return; } /* Big bottleneck. * Since we might need to do read-backs asynchronously, * it might take 3-4 times before this returns true. */ if (!video_driver_read_viewport(global->record.gpu_buffer)) return; ffemu_data.pitch = global->record.gpu_width * 3; ffemu_data.width = global->record.gpu_width; ffemu_data.height = global->record.gpu_height; ffemu_data.data = global->record.gpu_buffer + (ffemu_data.height - 1) * ffemu_data.pitch; ffemu_data.pitch = -ffemu_data.pitch; } if (!global->record.gpu_buffer) ffemu_data.is_dupe = !data; if (driver->recording && driver->recording->push_video) driver->recording->push_video(driver->recording_data, &ffemu_data); }
/** * 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); }
static bool netplay_get_cmd(netplay_t *netplay) { uint32_t cmd; uint32_t flip_frame; size_t cmd_size; if (!socket_receive_all_blocking(netplay->fd, &cmd, sizeof(cmd))) return false; cmd = ntohl(cmd); cmd_size = cmd & 0xffff; cmd = cmd >> 16; switch (cmd) { case NETPLAY_CMD_FLIP_PLAYERS: if (cmd_size != sizeof(uint32_t)) { RARCH_ERR("CMD_FLIP_PLAYERS recieved an unexpected command size.\n"); return netplay_cmd_nak(netplay); } if (!socket_receive_all_blocking(netplay->fd, &flip_frame, sizeof(flip_frame))) { RARCH_ERR("Failed to receive CMD_FLIP_PLAYERS argument.\n"); return netplay_cmd_nak(netplay); } flip_frame = ntohl(flip_frame); if (flip_frame < netplay->flip_frame) { RARCH_ERR("Host asked us to flip users in the past. Not possible ...\n"); return netplay_cmd_nak(netplay); } netplay->flip ^= true; netplay->flip_frame = flip_frame; RARCH_LOG("Netplay users are flipped.\n"); rarch_main_msg_queue_push("Netplay users are flipped.", 1, 180, false); return netplay_cmd_ack(netplay); case NETPLAY_CMD_SPECTATE: RARCH_ERR("NETPLAY_CMD_SPECTATE unimplemented.\n"); return netplay_cmd_nak(netplay); case NETPLAY_CMD_DISCONNECT: warn_hangup(); return netplay_cmd_ack(netplay); case NETPLAY_CMD_LOAD_SAVESTATE: RARCH_ERR("NETPLAY_CMD_LOAD_SAVESTATE unimplemented.\n"); return netplay_cmd_nak(netplay); case NETPLAY_CMD_PAUSE: event_command(EVENT_CMD_PAUSE); return netplay_cmd_ack(netplay); case NETPLAY_CMD_RESUME: event_command(EVENT_CMD_UNPAUSE); return netplay_cmd_ack(netplay); default: break; } RARCH_ERR("Unknown netplay command received.\n"); return netplay_cmd_nak(netplay); }
/** * rarch_main_deinit: * * Deinitializes the program. **/ void rarch_main_deinit(void) { global_t *global = global_get_ptr(); event_command(EVENT_CMD_NETPLAY_DEINIT); event_command(EVENT_CMD_COMMAND_DEINIT); if (global->sram.use) event_command(EVENT_CMD_AUTOSAVE_DEINIT); event_command(EVENT_CMD_RECORD_DEINIT); event_command(EVENT_CMD_SAVEFILES); event_command(EVENT_CMD_REWIND_DEINIT); event_command(EVENT_CMD_CHEATS_DEINIT); event_command(EVENT_CMD_BSV_MOVIE_DEINIT); event_command(EVENT_CMD_AUTOSAVE_STATE); event_command(EVENT_CMD_CORE_DEINIT); event_command(EVENT_CMD_TEMPORARY_CONTENT_DEINIT); event_command(EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT); event_command(EVENT_CMD_SAVEFILES_DEINIT); global->inited.main = false; }
void cmd_load_state(void) { event_command(EVENT_CMD_LOAD_STATE); }
void cmd_take_screenshot(void) { event_command(EVENT_CMD_TAKE_SCREENSHOT); }
void cmd_save_state(void) { event_command(EVENT_CMD_SAVE_STATE); }
void cmd_savefiles(void) { event_command(EVENT_CMD_SAVEFILES); }
/** * event_command: * @cmd : Event command index. * * Performs program event command with index @cmd. * * Returns: true (1) on success, otherwise false (0). **/ bool event_command(enum event_command cmd) { unsigned i = 0; bool boolean = false; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); rarch_system_info_t *info = NULL; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &info); (void)i; switch (cmd) { case EVENT_CMD_MENU_REFRESH: #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_REFRESH, NULL); #endif break; case EVENT_CMD_SET_PER_GAME_RESOLUTION: #if defined(GEKKO) { unsigned width = 0, height = 0; event_command(EVENT_CMD_VIDEO_SET_ASPECT_RATIO); if (video_driver_get_video_output_size(&width, &height)) { char msg[128] = {0}; video_driver_set_video_mode(width, height, true); snprintf(msg, sizeof(msg),"Resolution: %dx%d",width, height); runloop_msg_queue_push(msg, 1, 100, true); } } #endif break; case EVENT_CMD_LOAD_CONTENT_PERSIST: #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CORE); #endif rarch_ctl(RARCH_CTL_LOAD_CONTENT, NULL); break; #ifdef HAVE_FFMPEG case EVENT_CMD_LOAD_CONTENT_FFMPEG: rarch_ctl(RARCH_CTL_LOAD_CONTENT_FFMPEG, NULL); break; #endif case EVENT_CMD_LOAD_CONTENT_IMAGEVIEWER: rarch_ctl(RARCH_CTL_LOAD_CONTENT_IMAGEVIEWER, NULL); break; case EVENT_CMD_LOAD_CONTENT: { #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CONTENT_PERSIST); #else char *fullpath = NULL; runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)settings->libretro); rarch_environment_cb(RETRO_ENVIRONMENT_EXEC, (void*)fullpath); event_command(EVENT_CMD_QUIT); #endif } break; case EVENT_CMD_LOAD_CORE_DEINIT: #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_DEINIT, NULL); #endif break; case EVENT_CMD_LOAD_CORE_PERSIST: event_command(EVENT_CMD_LOAD_CORE_DEINIT); { #ifdef HAVE_MENU bool *ptr = NULL; struct retro_system_info *system = NULL; menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_GET, &system); if (menu_driver_ctl(RARCH_MENU_CTL_LOAD_NO_CONTENT_GET, &ptr)) event_update_system_info(system, ptr); #endif } break; case EVENT_CMD_LOAD_CORE: event_command(EVENT_CMD_LOAD_CORE_PERSIST); #ifndef HAVE_DYNAMIC event_command(EVENT_CMD_QUIT); #endif break; case EVENT_CMD_LOAD_STATE: /* Immutable - disallow savestate load when * we absolutely cannot change game state. */ if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; #ifdef HAVE_NETPLAY if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) return false; #endif event_main_state(cmd); break; case EVENT_CMD_RESIZE_WINDOWED_SCALE: { unsigned idx = 0; unsigned *window_scale = NULL; runloop_ctl(RUNLOOP_CTL_GET_WINDOWED_SCALE, &window_scale); if (*window_scale == 0) return false; settings->video.scale = *window_scale; if (!settings->video.fullscreen) event_command(EVENT_CMD_REINIT); runloop_ctl(RUNLOOP_CTL_SET_WINDOWED_SCALE, &idx); } break; case EVENT_CMD_MENU_TOGGLE: #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); else rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); #endif break; case EVENT_CMD_CONTROLLERS_INIT: event_init_controllers(); break; case EVENT_CMD_RESET: RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET)); runloop_msg_queue_push_new(MSG_RESET, 1, 120, true); #ifdef HAVE_CHEEVOS cheevos_set_cheats(); #endif core.retro_reset(); /* bSNES since v073r01 resets controllers to JOYPAD * after a reset, so just enforce it here. */ event_command(EVENT_CMD_CONTROLLERS_INIT); break; case EVENT_CMD_SAVE_STATE: if (settings->savestate_auto_index) settings->state_slot++; event_main_state(cmd); break; case EVENT_CMD_SAVE_STATE_DECREMENT: /* Slot -1 is (auto) slot. */ if (settings->state_slot >= 0) settings->state_slot--; break; case EVENT_CMD_SAVE_STATE_INCREMENT: settings->state_slot++; break; case EVENT_CMD_TAKE_SCREENSHOT: if (!take_screenshot()) return false; break; case EVENT_CMD_UNLOAD_CORE: runloop_ctl(RUNLOOP_CTL_PREPARE_DUMMY, NULL); event_command(EVENT_CMD_LOAD_CORE_DEINIT); break; case EVENT_CMD_QUIT: rarch_ctl(RARCH_CTL_QUIT, NULL); break; case EVENT_CMD_REINIT: { const struct retro_hw_render_callback *hw_render = (const struct retro_hw_render_callback*)video_driver_callback(); if (hw_render->cache_context) video_driver_ctl(RARCH_DISPLAY_CTL_SET_VIDEO_CACHE_CONTEXT, NULL); else video_driver_ctl(RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT, NULL); video_driver_ctl(RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT_ACK, NULL); event_command(EVENT_CMD_RESET_CONTEXT); video_driver_ctl(RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT, NULL); /* Poll input to avoid possibly stale data to corrupt things. */ input_driver_ctl(RARCH_INPUT_CTL_POLL, NULL); #ifdef HAVE_MENU menu_display_ctl(MENU_DISPLAY_CTL_SET_FRAMEBUFFER_DIRTY_FLAG, NULL); if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) event_command(EVENT_CMD_VIDEO_SET_BLOCKING_STATE); #endif } break; case EVENT_CMD_CHEATS_DEINIT: cheat_manager_state_free(); break; case EVENT_CMD_CHEATS_INIT: event_command(EVENT_CMD_CHEATS_DEINIT); event_init_cheats(); break; case EVENT_CMD_CHEATS_APPLY: cheat_manager_apply_cheats(); break; case EVENT_CMD_REMAPPING_DEINIT: break; case EVENT_CMD_REMAPPING_INIT: event_command(EVENT_CMD_REMAPPING_DEINIT); event_init_remapping(); break; case EVENT_CMD_REWIND_DEINIT: #ifdef HAVE_NETPLAY if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) return false; #endif state_manager_event_deinit(); break; case EVENT_CMD_REWIND_INIT: #ifdef HAVE_NETPLAY if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) #endif init_rewind(); break; case EVENT_CMD_REWIND_TOGGLE: if (settings->rewind_enable) event_command(EVENT_CMD_REWIND_INIT); else event_command(EVENT_CMD_REWIND_DEINIT); break; case EVENT_CMD_AUTOSAVE_DEINIT: #ifdef HAVE_THREADS autosave_event_deinit(); #endif break; case EVENT_CMD_AUTOSAVE_INIT: event_command(EVENT_CMD_AUTOSAVE_DEINIT); #ifdef HAVE_THREADS autosave_event_init(); #endif break; case EVENT_CMD_AUTOSAVE_STATE: event_save_auto_state(); break; case EVENT_CMD_AUDIO_STOP: if (!audio_driver_ctl(RARCH_AUDIO_CTL_ALIVE, NULL)) return false; if (!audio_driver_ctl(RARCH_AUDIO_CTL_STOP, NULL)) return false; break; case EVENT_CMD_AUDIO_START: if (audio_driver_ctl(RARCH_AUDIO_CTL_ALIVE, NULL)) return false; if (!settings->audio.mute_enable && !audio_driver_ctl(RARCH_AUDIO_CTL_START, NULL)) { RARCH_ERR("Failed to start audio driver. Will continue without audio.\n"); audio_driver_ctl(RARCH_AUDIO_CTL_UNSET_ACTIVE, NULL); } break; case EVENT_CMD_AUDIO_MUTE_TOGGLE: { const char *msg = !settings->audio.mute_enable ? msg_hash_to_str(MSG_AUDIO_MUTED): msg_hash_to_str(MSG_AUDIO_UNMUTED); if (!audio_driver_ctl(RARCH_AUDIO_CTL_MUTE_TOGGLE, NULL)) { RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_UNMUTE_AUDIO)); return false; } runloop_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s\n", msg); } break; case EVENT_CMD_OVERLAY_DEINIT: #ifdef HAVE_OVERLAY input_overlay_free(); #endif break; case EVENT_CMD_OVERLAY_INIT: event_command(EVENT_CMD_OVERLAY_DEINIT); #ifdef HAVE_OVERLAY input_overlay_init(); #endif break; case EVENT_CMD_OVERLAY_NEXT: #ifdef HAVE_OVERLAY input_overlay_next(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DSP_FILTER_DEINIT: audio_driver_dsp_filter_free(); break; case EVENT_CMD_DSP_FILTER_INIT: event_command(EVENT_CMD_DSP_FILTER_DEINIT); if (!*settings->audio.dsp_plugin) break; audio_driver_dsp_filter_init(settings->audio.dsp_plugin); break; case EVENT_CMD_GPU_RECORD_DEINIT: video_driver_ctl(RARCH_DISPLAY_CTL_GPU_RECORD_DEINIT, NULL); break; case EVENT_CMD_RECORD_DEINIT: if (!recording_deinit()) return false; break; case EVENT_CMD_RECORD_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!recording_init()) return false; break; case EVENT_CMD_HISTORY_DEINIT: if (g_defaults.history) { content_playlist_write_file(g_defaults.history); content_playlist_free(g_defaults.history); } g_defaults.history = NULL; break; case EVENT_CMD_HISTORY_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!settings->history_list_enable) return false; RARCH_LOG("%s: [%s].\n", msg_hash_to_str(MSG_LOADING_HISTORY_FILE), settings->content_history_path); g_defaults.history = content_playlist_init( settings->content_history_path, settings->content_history_size); break; case EVENT_CMD_CORE_INFO_DEINIT: runloop_ctl(RUNLOOP_CTL_CURRENT_CORE_LIST_FREE, NULL); break; case EVENT_CMD_CORE_INFO_INIT: event_command(EVENT_CMD_CORE_INFO_DEINIT); if (*settings->libretro_directory) runloop_ctl(RUNLOOP_CTL_CURRENT_CORE_LIST_INIT, NULL); break; case EVENT_CMD_CORE_DEINIT: { struct retro_hw_render_callback *cb = video_driver_callback(); event_deinit_core(true); if (cb) memset(cb, 0, sizeof(*cb)); break; } case EVENT_CMD_CORE_INIT: if (!event_init_core()) return false; break; case EVENT_CMD_VIDEO_APPLY_STATE_CHANGES: video_driver_ctl(RARCH_DISPLAY_CTL_APPLY_STATE_CHANGES, NULL); break; case EVENT_CMD_VIDEO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_VIDEO_SET_BLOCKING_STATE: video_driver_ctl(RARCH_DISPLAY_CTL_SET_NONBLOCK_STATE, &boolean); break; case EVENT_CMD_VIDEO_SET_ASPECT_RATIO: video_driver_ctl(RARCH_DISPLAY_CTL_SET_ASPECT_RATIO, NULL); break; case EVENT_CMD_AUDIO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_AUDIO_SET_BLOCKING_STATE: audio_driver_set_nonblocking_state(boolean); break; case EVENT_CMD_OVERLAY_SET_SCALE_FACTOR: #ifdef HAVE_OVERLAY input_overlay_set_scale_factor(settings->input.overlay_scale); #endif break; case EVENT_CMD_OVERLAY_SET_ALPHA_MOD: #ifdef HAVE_OVERLAY input_overlay_set_alpha_mod(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DRIVERS_DEINIT: { int flags = DRIVERS_CMD_ALL; driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags); } break; case EVENT_CMD_DRIVERS_INIT: { int flags = DRIVERS_CMD_ALL; driver_ctl(RARCH_DRIVER_CTL_INIT, &flags); } break; case EVENT_CMD_AUDIO_REINIT: { int flags = DRIVER_AUDIO; driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags); driver_ctl(RARCH_DRIVER_CTL_INIT, &flags); } break; case EVENT_CMD_RESET_CONTEXT: event_command(EVENT_CMD_DRIVERS_DEINIT); event_command(EVENT_CMD_DRIVERS_INIT); break; case EVENT_CMD_QUIT_RETROARCH: rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL); break; case EVENT_CMD_SHUTDOWN: #if defined(__linux__) && !defined(ANDROID) runloop_msg_queue_push("Shutting down...", 1, 180, true); rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL); system("shutdown -P now"); #endif break; case EVENT_CMD_RESUME: rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); break; case EVENT_CMD_RESTART_RETROARCH: { #if defined(GEKKO) && defined(HW_RVL) char new_path[PATH_MAX_LENGTH]; fill_pathname_join(new_path, g_defaults.dir.core, SALAMANDER_FILE, sizeof(new_path)); runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, new_path); #endif frontend_driver_set_fork(true, false); } break; case EVENT_CMD_MENU_SAVE_CURRENT_CONFIG: event_save_current_config(); break; case EVENT_CMD_MENU_SAVE_CONFIG: if (!event_save_core_config()) return false; break; case EVENT_CMD_SHADERS_APPLY_CHANGES: #ifdef HAVE_MENU menu_shader_manager_apply_changes(); #endif break; case EVENT_CMD_PAUSE_CHECKS: if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL)) { RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); event_command(EVENT_CMD_AUDIO_STOP); if (settings->video.black_frame_insertion) video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL); } else { RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED)); event_command(EVENT_CMD_AUDIO_START); } break; case EVENT_CMD_PAUSE_TOGGLE: boolean = runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL); boolean = !boolean; runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_UNPAUSE: boolean = false; runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_PAUSE: boolean = true; runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_MENU_PAUSE_LIBRETRO: #ifdef HAVE_MENU if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL)) { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_STOP); else event_command(EVENT_CMD_AUDIO_START); } else { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_START); } #endif break; case EVENT_CMD_SHADER_DIR_DEINIT: runloop_ctl(RUNLOOP_CTL_SHADER_DIR_DEINIT, NULL); break; case EVENT_CMD_SHADER_DIR_INIT: event_command(EVENT_CMD_SHADER_DIR_DEINIT); if (!runloop_ctl(RUNLOOP_CTL_SHADER_DIR_INIT, NULL)) return false; break; case EVENT_CMD_SAVEFILES: if (!global->savefiles || !global->sram.use) return false; for (i = 0; i < global->savefiles->size; i++) { unsigned type = global->savefiles->elems[i].attr.i; const char *path = global->savefiles->elems[i].data; RARCH_LOG("%s #%u %s \"%s\".\n", msg_hash_to_str(MSG_SAVING_RAM_TYPE), type, msg_hash_to_str(MSG_TO), path); save_ram_file(path, type); } return true; case EVENT_CMD_SAVEFILES_DEINIT: if (!global) break; if (global->savefiles) string_list_free(global->savefiles); global->savefiles = NULL; break; case EVENT_CMD_SAVEFILES_INIT: global->sram.use = global->sram.use && !global->sram.save_disable #ifdef HAVE_NETPLAY && (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL) || !global->netplay.is_client) #endif ; if (!global->sram.use) RARCH_LOG("%s\n", msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED)); if (global->sram.use) event_command(EVENT_CMD_AUTOSAVE_INIT); break; case EVENT_CMD_BSV_MOVIE_DEINIT: bsv_movie_ctl(BSV_MOVIE_CTL_DEINIT, NULL); break; case EVENT_CMD_BSV_MOVIE_INIT: event_command(EVENT_CMD_BSV_MOVIE_DEINIT); bsv_movie_ctl(BSV_MOVIE_CTL_INIT, NULL); break; case EVENT_CMD_NETPLAY_DEINIT: #ifdef HAVE_NETPLAY deinit_netplay(); #endif break; case EVENT_CMD_NETWORK_DEINIT: #ifdef HAVE_NETWORKING network_deinit(); #endif break; case EVENT_CMD_NETWORK_INIT: #ifdef HAVE_NETWORKING network_init(); #endif break; case EVENT_CMD_NETPLAY_INIT: event_command(EVENT_CMD_NETPLAY_DEINIT); #ifdef HAVE_NETPLAY if (!init_netplay()) return false; #endif break; case EVENT_CMD_NETPLAY_FLIP_PLAYERS: #ifdef HAVE_NETPLAY netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, NULL); #endif break; case EVENT_CMD_FULLSCREEN_TOGGLE: if (!video_driver_ctl(RARCH_DISPLAY_CTL_HAS_WINDOWED, NULL)) return false; /* If we go fullscreen we drop all drivers and * reinitialize to be safe. */ settings->video.fullscreen = !settings->video.fullscreen; event_command(EVENT_CMD_REINIT); break; case EVENT_CMD_COMMAND_DEINIT: input_driver_ctl(RARCH_INPUT_CTL_COMMAND_DEINIT, NULL); break; case EVENT_CMD_COMMAND_INIT: event_command(EVENT_CMD_COMMAND_DEINIT); input_driver_ctl(RARCH_INPUT_CTL_COMMAND_INIT, NULL); break; case EVENT_CMD_REMOTE_DEINIT: input_driver_ctl(RARCH_INPUT_CTL_REMOTE_DEINIT, NULL); break; case EVENT_CMD_REMOTE_INIT: event_command(EVENT_CMD_REMOTE_DEINIT); input_driver_ctl(RARCH_INPUT_CTL_REMOTE_INIT, NULL); break; case EVENT_CMD_TEMPORARY_CONTENT_DEINIT: content_temporary_free(); break; case EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT: if (!global) break; if (global->subsystem_fullpaths) string_list_free(global->subsystem_fullpaths); global->subsystem_fullpaths = NULL; break; case EVENT_CMD_LOG_FILE_DEINIT: retro_main_log_file_deinit(); break; case EVENT_CMD_DISK_EJECT_TOGGLE: if (info && info->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &info->disk_control; if (control) { bool new_state = !control->get_eject_state(); event_disk_control_set_eject(new_state, true); } } else runloop_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_NEXT: if (info && info->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &info->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_next(control); } else runloop_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_PREV: if (info && info->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &info->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_prev(control); } else runloop_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_RUMBLE_STOP: for (i = 0; i < MAX_USERS; i++) { input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0); input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0); } break; case EVENT_CMD_GRAB_MOUSE_TOGGLE: { static bool grab_mouse_state = false; bool grab_mouse_state_tmp; grab_mouse_state = !grab_mouse_state; if (!input_driver_grab_mouse(grab_mouse_state)) return false; RARCH_LOG("%s: %s.\n", msg_hash_to_str(MSG_GRAB_MOUSE_STATE), grab_mouse_state ? "yes" : "no"); grab_mouse_state_tmp = !grab_mouse_state; video_driver_ctl(RARCH_DISPLAY_CTL_SHOW_MOUSE, &grab_mouse_state_tmp); } break; case EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG: rarch_perf_log(); break; case EVENT_CMD_VOLUME_UP: event_set_volume(0.5f); break; case EVENT_CMD_VOLUME_DOWN: event_set_volume(-0.5f); break; case EVENT_CMD_SET_FRAME_LIMIT: runloop_ctl(RUNLOOP_CTL_SET_FRAME_LIMIT, NULL); break; case EVENT_CMD_NONE: default: return false; } return true; }
/** * rarch_main_init: * @argc : Count of (commandline) arguments. * @argv : (Commandline) arguments. * * Initializes the program. * * Returns: 0 on success, otherwise 1 if there was an error. **/ int rarch_main_init(int argc, char *argv[]) { int sjlj_ret; global_t *global = global_get_ptr(); init_state(); if ((sjlj_ret = setjmp(global->error_sjlj_context)) > 0) { RARCH_ERR("Fatal error received in: \"%s\"\n", global->error_string); return sjlj_ret; } global->inited.error = true; global->log_file = stderr; parse_input(argc, argv); if (global->verbosity) { char str[PATH_MAX_LENGTH] = {0}; RARCH_LOG_OUTPUT("=== Build ======================================="); rarch_info_get_capabilities(RARCH_CAPABILITIES_CPU, str, sizeof(str)); fprintf(stderr, "%s", str); fprintf(stderr, "Built: %s\n", __DATE__); RARCH_LOG_OUTPUT("Version: %s\n", PACKAGE_VERSION); #ifdef HAVE_GIT_VERSION RARCH_LOG_OUTPUT("Git: %s\n", rarch_git_version); #endif RARCH_LOG_OUTPUT("=================================================\n"); } rarch_ctl(RARCH_ACTION_STATE_VALIDATE_CPU_FEATURES, NULL); config_load(); { settings_t *settings = config_get_ptr(); if (settings && (settings->multimedia.builtin_mediaplayer_enable || settings->multimedia.builtin_imageviewer_enable)) { switch (rarch_path_is_media_type(global->path.fullpath)) { case RARCH_CONTENT_MOVIE: case RARCH_CONTENT_MUSIC: if (settings->multimedia.builtin_mediaplayer_enable) { #ifdef HAVE_FFMPEG global->has_set.libretro = false; global->inited.core.type = CORE_TYPE_FFMPEG; #endif } break; #ifdef HAVE_IMAGEVIEWER case RARCH_CONTENT_IMAGE: if (settings->multimedia.builtin_imageviewer_enable) { global->has_set.libretro = false; global->inited.core.type = CORE_TYPE_IMAGEVIEWER; } break; #endif default: break; } } } init_libretro_sym(global->inited.core.type); rarch_system_info_init(); init_drivers_pre(); if (!event_command(EVENT_CMD_CORE_INIT)) goto error; event_command(EVENT_CMD_DRIVERS_INIT); event_command(EVENT_CMD_COMMAND_INIT); event_command(EVENT_CMD_REWIND_INIT); event_command(EVENT_CMD_CONTROLLERS_INIT); event_command(EVENT_CMD_RECORD_INIT); event_command(EVENT_CMD_CHEATS_INIT); event_command(EVENT_CMD_REMAPPING_INIT); event_command(EVENT_CMD_SAVEFILES_INIT); #if defined(GEKKO) && defined(HW_RVL) { settings_t *settings = config_get_ptr(); if (settings) { event_command(EVENT_CMD_VIDEO_SET_ASPECT_RATIO); video_driver_set_aspect_ratio(settings->video.aspect_ratio_idx); } unsigned width = 0, height = 0; (void)width; (void)height; width = global->console.screen.resolutions.width; height = global->console.screen.resolutions.height; video_driver_set_video_mode(width, height, true); char msg[PATH_MAX_LENGTH] = {0}; snprintf(msg, sizeof(msg),"Resolution: %dx%d",width, height); rarch_main_msg_queue_push(msg, 1, 100, true); } #endif global->inited.error = false; global->inited.main = true; return 0; error: event_command(EVENT_CMD_CORE_DEINIT); global->inited.main = false; return 1; }
static bool ctr_frame(void* data, const void* frame, unsigned width, unsigned height, uint64_t frame_count, unsigned pitch, const char* msg) { uint32_t diff; static uint64_t currentTick,lastTick; ctr_video_t *ctr = (ctr_video_t*)data; settings_t *settings = config_get_ptr(); static float fps = 0.0; static int total_frames = 0; static int frames = 0; static struct retro_perf_counter ctrframe_f = {0}; uint32_t state_tmp; touchPosition state_tmp_touch; extern bool select_pressed; if (!width || !height) { gspWaitForEvent(GSPEVENT_VBlank0, true); return true; } if(!aptMainLoop()) { event_command(EVENT_CMD_QUIT); return true; } if (select_pressed) { event_command(EVENT_CMD_QUIT); return true; } state_tmp = hidKeysDown(); hidTouchRead(&state_tmp_touch); if((state_tmp & KEY_TOUCH) && (state_tmp_touch.py < 120)) { Handle lcd_handle; u8 not_2DS; extern PrintConsole* currentConsole; gfxBottomFramebuffers[0] = ctr->lcd_buttom_on ? (u8*)ctr->empty_framebuffer: (u8*)currentConsole->frameBuffer; CFGU_GetModelNintendo2DS(¬_2DS); if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0) { u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = ctr->lcd_buttom_on? 0x00120040: 0x00110040; cmdbuf[1] = 2; svcSendSyncRequest(lcd_handle); svcCloseHandle(lcd_handle); } ctr->lcd_buttom_on = !ctr->lcd_buttom_on; } svcWaitSynchronization(gspEvents[GSPEVENT_P3D], 20000000); svcClearEvent(gspEvents[GSPEVENT_P3D]); svcWaitSynchronization(gspEvents[GSPEVENT_PPF], 20000000); svcClearEvent(gspEvents[GSPEVENT_PPF]); frames++; if (ctr->vsync) svcWaitSynchronization(gspEvents[GSPEVENT_VBlank0], U64_MAX); svcClearEvent(gspEvents[GSPEVENT_VBlank0]); currentTick = svcGetSystemTick(); diff = currentTick - lastTick; if(diff > CTR_CPU_TICKS_PER_SECOND) { fps = (float)frames * ((float) CTR_CPU_TICKS_PER_SECOND / (float) diff); lastTick = currentTick; frames = 0; } // extern u32 __linear_heap_size; // extern u32 gpuCmdBufOffset; // extern u32 __heap_size; // printf("0x%08X 0x%08X 0x%08X\r", __heap_size, gpuCmdBufOffset, (__linear_heap_size - linearSpaceFree() +0x3FF) & ~0x3FF); // printf("fps: %8.4f frames: %i (%X)\r", fps, total_frames++, (__linear_heap_size - linearSpaceFree())); printf("fps: %8.4f frames: %i\r", fps, total_frames++); fflush(stdout); rarch_perf_init(&ctrframe_f, "ctrframe_f"); retro_perf_start(&ctrframe_f); if (ctr->should_resize) ctr_update_viewport(ctr); ctrGuSetMemoryFill(true, (u32*)CTR_GPU_FRAMEBUFFER, 0x00000000, (u32*)(CTR_GPU_FRAMEBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201, (u32*)CTR_GPU_DEPTHBUFFER, 0x00000000, (u32*)(CTR_GPU_DEPTHBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201); GPUCMD_SetBufferOffset(0); if (width > ctr->texture_width) width = ctr->texture_width; if (height > ctr->texture_height) height = ctr->texture_height; if(frame) { if(((((u32)(frame)) >= 0x14000000 && ((u32)(frame)) < 0x40000000)) /* frame in linear memory */ && !((u32)frame & 0x7F) /* 128-byte aligned */ && !((pitch) & 0xF)) /* 16-byte aligned */ { /* can copy the buffer directly with the GPU */ ctrGuCopyImage(false, frame, pitch / (ctr->rgb32? 4: 2), height, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, true); } else { int i; uint8_t *dst = (uint8_t*)ctr->texture_linear; const uint8_t *src = frame; for (i = 0; i < height; i++) { memcpy(dst, src, width * (ctr->rgb32? 4: 2)); dst += ctr->texture_width * (ctr->rgb32? 4: 2); src += pitch; } GSPGPU_FlushDataCache(ctr->texture_linear, ctr->texture_width * ctr->texture_height * (ctr->rgb32? 4: 2)); ctrGuCopyImage(false, ctr->texture_linear, ctr->texture_width, ctr->texture_height, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, true); } } ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->texture_swizzled), ctr->texture_width, ctr->texture_height, (ctr->smooth? GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) : GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST)) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), ctr->rgb32 ? GPU_RGBA8: GPU_RGB565); ctr->frame_coords->u = width; ctr->frame_coords->v = height; GSPGPU_FlushDataCache(ctr->frame_coords, sizeof(ctr_vertex_t)); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->frame_coords)); ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->scale_vector, 1); /* ARGB --> RGBA */ if (ctr->rgb32) { GPU_SetTexEnv(0, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, 0), GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, 0), GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_G, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MODULATE, GPU_MODULATE, 0x0000FF); GPU_SetTexEnv(1, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_PREVIOUS), GPU_TEVSOURCES(GPU_PREVIOUS, GPU_PREVIOUS, 0), GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_B, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MULTIPLY_ADD, GPU_MODULATE, 0x00FF00); GPU_SetTexEnv(2, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_PREVIOUS), GPU_TEVSOURCES(GPU_PREVIOUS, GPU_PREVIOUS, 0), GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_ALPHA, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MULTIPLY_ADD, GPU_MODULATE, 0xFF0000); } GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1); /* restore */ if (ctr->rgb32) { GPU_SetTexEnv(0, GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_TEVOPERANDS(0, 0, 0), GPU_MODULATE, GPU_MODULATE, 0xFFFFFFFF); GPU_SetTexEnv(1, GPU_PREVIOUS,GPU_PREVIOUS, 0, 0, 0, 0, 0); GPU_SetTexEnv(2, GPU_PREVIOUS,GPU_PREVIOUS, 0, 0, 0, 0, 0); } if (ctr->menu_texture_enable) { GSPGPU_FlushDataCache(ctr->menu.texture_linear, ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->menu.texture_linear, ctr->menu.texture_width, ctr->menu.texture_height, CTRGU_RGBA4444,false, ctr->menu.texture_swizzled, ctr->menu.texture_width, CTRGU_RGBA4444, true); ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->menu.texture_swizzled), ctr->menu.texture_width, ctr->menu.texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGBA4); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->menu.frame_coords)); ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->menu.scale_vector, 1); GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1); } GPU_FinishDrawing(); GPUCMD_Finalize(); ctrGuFlushAndRun(true); ctrGuDisplayTransfer(true, CTR_GPU_FRAMEBUFFER, 240,400, CTRGU_RGBA8, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 240,400,CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE); gfxSwapBuffersGpu(); retro_perf_stop(&ctrframe_f); return true; }
bool rarch_ctl(enum rarch_ctl_state state, void *data) { driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); switch(state) { case RARCH_ACTION_STATE_REPLACE_CONFIG: { char *path = (char*)data; if (!path) return false; /* If config file to be replaced is the same as the * current config file, exit. */ if (!strcmp(path, global->path.config)) return false; if (settings->config_save_on_exit && *global->path.config) config_save_file(global->path.config); strlcpy(global->path.config, path, sizeof(global->path.config)); global->block_config_read = false; *settings->libretro = '\0'; /* Load core in new config. */ } event_command(EVENT_CMD_PREPARE_DUMMY); return true; case RARCH_ACTION_STATE_MENU_RUNNING: #ifdef HAVE_MENU menu_driver_toggle(true); #endif #ifdef HAVE_OVERLAY if (settings->input.overlay_hide_in_menu) event_command(EVENT_CMD_OVERLAY_DEINIT); #endif break; case RARCH_ACTION_STATE_LOAD_CONTENT: #ifdef HAVE_MENU /* If content loading fails, we go back to menu. */ if (!menu_load_content(CORE_TYPE_PLAIN)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif if (driver->frontend_ctx && driver->frontend_ctx->content_loaded) driver->frontend_ctx->content_loaded(); break; #ifdef HAVE_FFMPEG case RARCH_ACTION_STATE_LOAD_CONTENT_FFMPEG: #ifdef HAVE_MENU /* If content loading fails, we go back to menu. */ if (!menu_load_content(CORE_TYPE_FFMPEG)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif if (driver->frontend_ctx && driver->frontend_ctx->content_loaded) driver->frontend_ctx->content_loaded(); break; #endif case RARCH_ACTION_STATE_LOAD_CONTENT_IMAGEVIEWER: #ifdef HAVE_MENU /* If content loading fails, we go back to menu. */ if (!menu_load_content(CORE_TYPE_IMAGEVIEWER)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif if (driver->frontend_ctx && driver->frontend_ctx->content_loaded) driver->frontend_ctx->content_loaded(); break; case RARCH_ACTION_STATE_MENU_RUNNING_FINISHED: #ifdef HAVE_MENU menu_driver_toggle(false); #endif video_driver_set_texture_enable(false, false); #ifdef HAVE_OVERLAY if (settings && settings->input.overlay_hide_in_menu) event_command(EVENT_CMD_OVERLAY_INIT); #endif break; case RARCH_ACTION_STATE_QUIT: if (global) system->shutdown = true; rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); break; case RARCH_ACTION_STATE_FORCE_QUIT: rarch_ctl(RARCH_ACTION_STATE_QUIT, NULL); break; case RARCH_ACTION_STATE_VALIDATE_CPU_FEATURES: { uint64_t cpu = retro_get_cpu_features(); (void)cpu; #ifdef __SSE__ if (!(cpu & RETRO_SIMD_SSE)) FAIL_CPU("SSE"); #endif #ifdef __SSE2__ if (!(cpu & RETRO_SIMD_SSE2)) FAIL_CPU("SSE2"); #endif #ifdef __AVX__ if (!(cpu & RETRO_SIMD_AVX)) FAIL_CPU("AVX"); #endif } break; case RARCH_ACTION_STATE_VERIFY_API_VERSION: RARCH_LOG("Version of libretro API: %u\n", core.retro_api_version()); RARCH_LOG("Compiled against API: %u\n", RETRO_API_VERSION); if (core.retro_api_version() != RETRO_API_VERSION) RARCH_WARN("%s\n", msg_hash_to_str(MSG_LIBRETRO_ABI_BREAK)); break; case RARCH_ACTION_STATE_FILL_PATHNAMES: rarch_init_savefile_paths(); strlcpy(global->bsv.movie_path, global->name.savefile, sizeof(global->bsv.movie_path)); if (!*global->name.base) return false; if (!*global->name.ups) fill_pathname_noext(global->name.ups, global->name.base, ".ups", sizeof(global->name.ups)); if (!*global->name.bps) fill_pathname_noext(global->name.bps, global->name.base, ".bps", sizeof(global->name.bps)); if (!*global->name.ips) fill_pathname_noext(global->name.ips, global->name.base, ".ips", sizeof(global->name.ips)); break; case RARCH_ACTION_STATE_NONE: default: return false; } return true; }
/** * main_entry: * * Main function of RetroArch. * * If HAVE_MAIN is not defined, will contain main loop and will not * be exited from until we exit the program. Otherwise, will * just do initialization. * * Returns: varies per platform. **/ int rarch_main(int argc, char *argv[], void *data) { void *args = (void*)data; int ret = 0; settings_t *settings = NULL; driver_t *driver = NULL; rarch_main_alloc(); driver = driver_get_ptr(); if (driver) driver->frontend_ctx = (frontend_ctx_driver_t*)frontend_ctx_init_first(); if (!driver || !driver->frontend_ctx) RARCH_WARN("Frontend context could not be initialized.\n"); if (driver->frontend_ctx && driver->frontend_ctx->init) driver->frontend_ctx->init(args); rarch_main_new(); if (driver->frontend_ctx) { if (!(ret = (main_load_content(argc, argv, args, driver->frontend_ctx->environment_get, driver->frontend_ctx->process_args)))) return ret; } event_command(EVENT_CMD_HISTORY_INIT); settings = config_get_ptr(); if (settings->history_list_enable) { global_t *global = global_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); if (global->inited.content || system->no_content) history_playlist_push( g_defaults.history, global->path.fullpath, settings->libretro, system ? &system->info : NULL); } if (driver) driver->ui_companion = (ui_companion_driver_t*)ui_companion_init_first(); if (driver->ui_companion && driver->ui_companion->toggle) { if (settings->ui.companion_start_on_boot) driver->ui_companion->toggle(driver->ui_companion_data); } #ifndef HAVE_MAIN do{ ret = rarch_main_iterate(); if (ret == 1) rarch_sleep(10); rarch_main_data_iterate(); }while(ret != -1); main_exit(args); #endif return 0; }
static void rarch_init_savefile_paths(void) { global_t *global = global_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); event_command(EVENT_CMD_SAVEFILES_DEINIT); global->savefiles = string_list_new(); rarch_assert(global->savefiles); if (*global->subsystem) { /* For subsystems, we know exactly which RAM types are supported. */ unsigned i, j; const struct retro_subsystem_info *info = libretro_find_subsystem_info( system->special, system->num_special, global->subsystem); /* We'll handle this error gracefully later. */ unsigned num_content = min(info ? info->num_roms : 0, global->subsystem_fullpaths ? global->subsystem_fullpaths->size : 0); bool use_sram_dir = path_is_directory(global->dir.savefile); for (i = 0; i < num_content; i++) { for (j = 0; j < info->roms[i].num_memory; j++) { union string_list_elem_attr attr; char path[PATH_MAX_LENGTH] = {0}; char ext[32] = {0}; const struct retro_subsystem_memory_info *mem = (const struct retro_subsystem_memory_info*) &info->roms[i].memory[j]; snprintf(ext, sizeof(ext), ".%s", mem->extension); if (use_sram_dir) { /* Redirect content fullpath to save directory. */ strlcpy(path, global->dir.savefile, sizeof(path)); fill_pathname_dir(path, global->subsystem_fullpaths->elems[i].data, ext, sizeof(path)); } else { fill_pathname(path, global->subsystem_fullpaths->elems[i].data, ext, sizeof(path)); } attr.i = mem->type; string_list_append(global->savefiles, path, attr); } } /* Let other relevant paths be inferred from the main SRAM location. */ if (!global->has_set.save_path) fill_pathname_noext(global->name.savefile, global->name.base, ".srm", sizeof(global->name.savefile)); if (path_is_directory(global->name.savefile)) { fill_pathname_dir(global->name.savefile, global->name.base, ".srm", sizeof(global->name.savefile)); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO), global->name.savefile); } } else { union string_list_elem_attr attr; char savefile_name_rtc[PATH_MAX_LENGTH] = {0}; attr.i = RETRO_MEMORY_SAVE_RAM; string_list_append(global->savefiles, global->name.savefile, attr); /* Infer .rtc save path from save ram path. */ attr.i = RETRO_MEMORY_RTC; fill_pathname(savefile_name_rtc, global->name.savefile, ".rtc", sizeof(savefile_name_rtc)); string_list_append(global->savefiles, savefile_name_rtc, attr); } }
/** * 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; }
/** * recording_init: * * Initializes recording. * * Returns: true (1) if successful, otherwise false (0). **/ bool recording_init(void) { char recording_file[PATH_MAX_LENGTH] = {0}; struct ffemu_params params = {0}; global_t *global = global_get_ptr(); driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); const struct retro_hw_render_callback *hw_render = (const struct retro_hw_render_callback*)video_driver_callback(); if (!global->record.enable) return false; if (global->inited.core.type == CORE_TYPE_DUMMY) { RARCH_WARN(msg_hash_to_str(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED)); return false; } if (!settings->video.gpu_record && hw_render->context_type) { RARCH_WARN("%s.\n", msg_hash_to_str(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING)); return false; } RARCH_LOG("%s: FPS: %.4f, Sample rate: %.4f\n", msg_hash_to_str(MSG_CUSTOM_TIMING_GIVEN), (float)av_info->timing.fps, (float)av_info->timing.sample_rate); strlcpy(recording_file, global->record.path, sizeof(recording_file)); if (global->record.use_output_dir) fill_pathname_join(recording_file, global->record.output_dir, global->record.path, sizeof(recording_file)); params.out_width = av_info->geometry.base_width; params.out_height = av_info->geometry.base_height; params.fb_width = av_info->geometry.max_width; params.fb_height = av_info->geometry.max_height; params.channels = 2; params.filename = recording_file; params.fps = av_info->timing.fps; params.samplerate = av_info->timing.sample_rate; params.pix_fmt = (video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_XRGB8888) ? FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565; params.config = NULL; if (*global->record.config) params.config = global->record.config; if (settings->video.gpu_record && driver->video->read_viewport) { struct video_viewport vp = {0}; video_driver_viewport_info(&vp); if (!vp.width || !vp.height) { RARCH_ERR("Failed to get viewport information from video driver. " "Cannot start recording ...\n"); return false; } params.out_width = vp.width; params.out_height = vp.height; params.fb_width = next_pow2(vp.width); params.fb_height = next_pow2(vp.height); if (settings->video.force_aspect && (video_driver_get_aspect_ratio() > 0.0f)) params.aspect_ratio = video_driver_get_aspect_ratio(); else params.aspect_ratio = (float)vp.width / vp.height; params.pix_fmt = FFEMU_PIX_BGR24; global->record.gpu_width = vp.width; global->record.gpu_height = vp.height; RARCH_LOG("%s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF), vp.width, vp.height); global->record.gpu_buffer = (uint8_t*)malloc(vp.width * vp.height * 3); if (!global->record.gpu_buffer) return false; } else { if (global->record.width || global->record.height) { params.out_width = global->record.width; params.out_height = global->record.height; } if (settings->video.force_aspect && (video_driver_get_aspect_ratio() > 0.0f)) params.aspect_ratio = video_driver_get_aspect_ratio(); else params.aspect_ratio = (float)params.out_width / params.out_height; if (settings->video.post_filter_record && video_driver_frame_filter_alive()) { unsigned max_width = 0; unsigned max_height = 0; if (video_driver_frame_filter_is_32bit()) params.pix_fmt = FFEMU_PIX_ARGB8888; else params.pix_fmt = FFEMU_PIX_RGB565; rarch_softfilter_get_max_output_size( video_driver_frame_filter_get_ptr(), &max_width, &max_height); params.fb_width = next_pow2(max_width); params.fb_height = next_pow2(max_height); } } RARCH_LOG("%s %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n", msg_hash_to_str(MSG_RECORDING_TO), global->record.path, params.out_width, params.out_height, params.fb_width, params.fb_height, (unsigned)params.pix_fmt); if (!record_driver_init_first(&driver->recording, &driver->recording_data, ¶ms)) { RARCH_ERR(msg_hash_to_str(MSG_FAILED_TO_START_RECORDING)); event_command(EVENT_CMD_GPU_RECORD_DEINIT); return false; } return true; }
bool runloop_ctl(enum runloop_ctl_state state, void *data) { static rarch_dir_list_t runloop_shader_dir; static char runloop_fullpath[PATH_MAX_LENGTH]; static rarch_system_info_t runloop_system; static unsigned runloop_pending_windowed_scale; static retro_keyboard_event_t runloop_key_event = NULL; static unsigned runloop_max_frames = false; static bool runloop_frame_time_last = false; static bool runloop_set_frame_limit = false; static bool runloop_paused = false; static bool runloop_idle = false; static bool runloop_exec = false; static bool runloop_slowmotion = false; static bool runloop_shutdown_initiated = false; static bool runloop_core_shutdown_initiated = false; static bool runloop_perfcnt_enable = false; static bool runloop_overrides_active = false; static bool runloop_game_options_active = false; #ifdef HAVE_THREADS static slock_t *runloop_msg_queue_lock = NULL; #endif static core_info_t *core_info_current = NULL; static core_info_list_t *core_info_curr_list = NULL; settings_t *settings = config_get_ptr(); switch (state) { case RUNLOOP_CTL_DATA_ITERATE: rarch_task_check(); return true; case RUNLOOP_CTL_SHADER_DIR_DEINIT: shader_dir_free(&runloop_shader_dir); return true; case RUNLOOP_CTL_SHADER_DIR_INIT: return shader_dir_init(&runloop_shader_dir); case RUNLOOP_CTL_SYSTEM_INFO_INIT: core.retro_get_system_info(&runloop_system.info); if (!runloop_system.info.library_name) runloop_system.info.library_name = msg_hash_to_str(MSG_UNKNOWN); if (!runloop_system.info.library_version) runloop_system.info.library_version = "v0"; #ifndef RARCH_CONSOLE strlcpy(runloop_system.title_buf, msg_hash_to_str(MSG_PROGRAM), sizeof(runloop_system.title_buf)); strlcat(runloop_system.title_buf, " : ", sizeof(runloop_system.title_buf)); #endif strlcat(runloop_system.title_buf, runloop_system.info.library_name, sizeof(runloop_system.title_buf)); strlcat(runloop_system.title_buf, " ", sizeof(runloop_system.title_buf)); strlcat(runloop_system.title_buf, runloop_system.info.library_version, sizeof(runloop_system.title_buf)); strlcpy(runloop_system.valid_extensions, runloop_system.info.valid_extensions ? runloop_system.info.valid_extensions : DEFAULT_EXT, sizeof(runloop_system.valid_extensions)); runloop_system.block_extract = runloop_system.info.block_extract; break; case RUNLOOP_CTL_GET_CORE_OPTION_SIZE: { unsigned *idx = (unsigned*)data; if (!idx) return false; *idx = core_option_size(runloop_system.core_options); } return true; case RUNLOOP_CTL_HAS_CORE_OPTIONS: return runloop_system.core_options; case RUNLOOP_CTL_CURRENT_CORE_LIST_FREE: if (core_info_curr_list) core_info_list_free(core_info_curr_list); core_info_curr_list = NULL; return true; case RUNLOOP_CTL_CURRENT_CORE_LIST_INIT: core_info_curr_list = core_info_list_new(); return true; case RUNLOOP_CTL_CURRENT_CORE_LIST_GET: { core_info_list_t **core = (core_info_list_t**)data; if (!core) return false; *core = core_info_curr_list; } return true; case RUNLOOP_CTL_CURRENT_CORE_FREE: if (core_info_current) free(core_info_current); core_info_current = NULL; return true; case RUNLOOP_CTL_CURRENT_CORE_INIT: core_info_current = (core_info_t*)calloc(1, sizeof(core_info_t)); if (!core_info_current) return false; return true; case RUNLOOP_CTL_CURRENT_CORE_GET: { core_info_t **core = (core_info_t**)data; if (!core) return false; *core = core_info_current; } return true; case RUNLOOP_CTL_SYSTEM_INFO_GET: { rarch_system_info_t **system = (rarch_system_info_t**)data; if (!system) return false; *system = &runloop_system; } return true; case RUNLOOP_CTL_SYSTEM_INFO_FREE: if (runloop_system.core_options) { core_option_flush(runloop_system.core_options); core_option_free(runloop_system.core_options); } runloop_system.core_options = NULL; /* No longer valid. */ if (runloop_system.special) free(runloop_system.special); runloop_system.special = NULL; if (runloop_system.ports) free(runloop_system.ports); runloop_system.ports = NULL; runloop_key_event = NULL; global_get_ptr()->frontend_key_event = NULL; audio_driver_unset_callback(); memset(&runloop_system, 0, sizeof(rarch_system_info_t)); break; case RUNLOOP_CTL_IS_FRAME_COUNT_END: { uint64_t *frame_count = NULL; video_driver_ctl(RARCH_DISPLAY_CTL_GET_FRAME_COUNT, &frame_count); return runloop_max_frames && (*frame_count >= runloop_max_frames); } case RUNLOOP_CTL_SET_FRAME_TIME_LAST: runloop_frame_time_last = true; break; case RUNLOOP_CTL_UNSET_FRAME_TIME_LAST: runloop_frame_time_last = false; break; case RUNLOOP_CTL_SET_OVERRIDES_ACTIVE: runloop_overrides_active = true; break; case RUNLOOP_CTL_UNSET_OVERRIDES_ACTIVE: runloop_overrides_active = false; break; case RUNLOOP_CTL_IS_OVERRIDES_ACTIVE: return runloop_overrides_active; case RUNLOOP_CTL_SET_GAME_OPTIONS_ACTIVE: runloop_game_options_active = true; break; case RUNLOOP_CTL_UNSET_GAME_OPTIONS_ACTIVE: runloop_game_options_active = false; break; case RUNLOOP_CTL_IS_GAME_OPTIONS_ACTIVE: return runloop_game_options_active; case RUNLOOP_CTL_IS_FRAME_TIME_LAST: return runloop_frame_time_last; case RUNLOOP_CTL_SET_FRAME_LIMIT: runloop_set_frame_limit = true; break; case RUNLOOP_CTL_UNSET_FRAME_LIMIT: runloop_set_frame_limit = false; break; case RUNLOOP_CTL_SHOULD_SET_FRAME_LIMIT: return runloop_set_frame_limit; case RUNLOOP_CTL_GET_PERFCNT: { bool **perfcnt = (bool**)data; if (!perfcnt) return false; *perfcnt = &runloop_perfcnt_enable; } return true; case RUNLOOP_CTL_SET_PERFCNT_ENABLE: runloop_perfcnt_enable = true; break; case RUNLOOP_CTL_UNSET_PERFCNT_ENABLE: runloop_perfcnt_enable = false; break; case RUNLOOP_CTL_IS_PERFCNT_ENABLE: return runloop_perfcnt_enable; case RUNLOOP_CTL_GET_WINDOWED_SCALE: { unsigned **scale = (unsigned**)data; if (!scale) return false; *scale = (unsigned*)&runloop_pending_windowed_scale; } break; case RUNLOOP_CTL_SET_WINDOWED_SCALE: { unsigned *idx = (unsigned*)data; if (!idx) return false; runloop_pending_windowed_scale = *idx; } break; case RUNLOOP_CTL_SET_LIBRETRO_PATH: { const char *fullpath = (const char*)data; if (!fullpath) return false; strlcpy(settings->libretro, fullpath, sizeof(settings->libretro)); } break; case RUNLOOP_CTL_CLEAR_CONTENT_PATH: *runloop_fullpath = '\0'; break; case RUNLOOP_CTL_GET_CONTENT_PATH: { char **fullpath = (char**)data; if (!fullpath) return false; *fullpath = (char*)runloop_fullpath; } break; case RUNLOOP_CTL_SET_CONTENT_PATH: { const char *fullpath = (const char*)data; if (!fullpath) return false; strlcpy(runloop_fullpath, fullpath, sizeof(runloop_fullpath)); } break; case RUNLOOP_CTL_CHECK_FOCUS: if (settings->pause_nonactive) return video_driver_ctl(RARCH_DISPLAY_CTL_IS_FOCUSED, NULL); return true; case RUNLOOP_CTL_CHECK_IDLE_STATE: { event_cmd_state_t *cmd = (event_cmd_state_t*)data; bool focused = runloop_ctl(RUNLOOP_CTL_CHECK_FOCUS, NULL); check_pause(settings, focused, runloop_cmd_triggered(cmd, RARCH_PAUSE_TOGGLE), runloop_cmd_triggered(cmd, RARCH_FRAMEADVANCE)); if (!runloop_ctl(RUNLOOP_CTL_CHECK_PAUSE_STATE, cmd) || !focused) return false; break; } case RUNLOOP_CTL_CHECK_STATE: { bool tmp = false; event_cmd_state_t *cmd = (event_cmd_state_t*)data; if (!cmd || runloop_idle) return false; if (runloop_cmd_triggered(cmd, RARCH_SCREENSHOT)) event_command(EVENT_CMD_TAKE_SCREENSHOT); if (runloop_cmd_triggered(cmd, RARCH_MUTE)) event_command(EVENT_CMD_AUDIO_MUTE_TOGGLE); if (runloop_cmd_triggered(cmd, RARCH_OSK)) { if (input_driver_ctl(RARCH_INPUT_CTL_IS_KEYBOARD_LINEFEED_ENABLED, NULL)) input_driver_ctl(RARCH_INPUT_CTL_UNSET_KEYBOARD_LINEFEED_ENABLED, NULL); else input_driver_ctl(RARCH_INPUT_CTL_SET_KEYBOARD_LINEFEED_ENABLED, NULL); } if (runloop_cmd_press(cmd, RARCH_VOLUME_UP)) event_command(EVENT_CMD_VOLUME_UP); else if (runloop_cmd_press(cmd, RARCH_VOLUME_DOWN)) event_command(EVENT_CMD_VOLUME_DOWN); #ifdef HAVE_NETPLAY tmp = runloop_cmd_triggered(cmd, RARCH_NETPLAY_FLIP); netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, &tmp); tmp = runloop_cmd_triggered(cmd, RARCH_FULLSCREEN_TOGGLE_KEY); netplay_driver_ctl(RARCH_NETPLAY_CTL_FULLSCREEN_TOGGLE, &tmp); #endif if (!runloop_ctl(RUNLOOP_CTL_CHECK_IDLE_STATE, data)) return false; check_fast_forward_button( runloop_cmd_triggered(cmd, RARCH_FAST_FORWARD_KEY), runloop_cmd_press (cmd, RARCH_FAST_FORWARD_HOLD_KEY), runloop_cmd_pressed (cmd, RARCH_FAST_FORWARD_HOLD_KEY)); check_stateslots(settings, runloop_cmd_triggered(cmd, RARCH_STATE_SLOT_PLUS), runloop_cmd_triggered(cmd, RARCH_STATE_SLOT_MINUS) ); if (runloop_cmd_triggered(cmd, RARCH_SAVE_STATE_KEY)) event_command(EVENT_CMD_SAVE_STATE); else if (runloop_cmd_triggered(cmd, RARCH_LOAD_STATE_KEY)) event_command(EVENT_CMD_LOAD_STATE); state_manager_check_rewind(runloop_cmd_press(cmd, RARCH_REWIND)); tmp = runloop_cmd_press(cmd, RARCH_SLOWMOTION); runloop_ctl(RUNLOOP_CTL_CHECK_SLOWMOTION, &tmp); if (runloop_cmd_triggered(cmd, RARCH_MOVIE_RECORD_TOGGLE)) runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE, NULL); check_shader_dir(&runloop_shader_dir, runloop_cmd_triggered(cmd, RARCH_SHADER_NEXT), runloop_cmd_triggered(cmd, RARCH_SHADER_PREV)); if (runloop_cmd_triggered(cmd, RARCH_DISK_EJECT_TOGGLE)) event_command(EVENT_CMD_DISK_EJECT_TOGGLE); else if (runloop_cmd_triggered(cmd, RARCH_DISK_NEXT)) event_command(EVENT_CMD_DISK_NEXT); else if (runloop_cmd_triggered(cmd, RARCH_DISK_PREV)) event_command(EVENT_CMD_DISK_PREV); if (runloop_cmd_triggered(cmd, RARCH_RESET)) event_command(EVENT_CMD_RESET); cheat_manager_state_checks( runloop_cmd_triggered(cmd, RARCH_CHEAT_INDEX_PLUS), runloop_cmd_triggered(cmd, RARCH_CHEAT_INDEX_MINUS), runloop_cmd_triggered(cmd, RARCH_CHEAT_TOGGLE)); } break; case RUNLOOP_CTL_CHECK_PAUSE_STATE: { bool check_is_oneshot; event_cmd_state_t *cmd = (event_cmd_state_t*)data; if (!cmd) return false; check_is_oneshot = runloop_cmd_triggered(cmd, RARCH_FRAMEADVANCE) || runloop_cmd_press(cmd, RARCH_REWIND); if (!runloop_paused) return true; if (runloop_cmd_triggered(cmd, RARCH_FULLSCREEN_TOGGLE_KEY)) { event_command(EVENT_CMD_FULLSCREEN_TOGGLE); video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL); } if (!check_is_oneshot) return false; } break; case RUNLOOP_CTL_CHECK_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_slowmotion = *ptr; if (!runloop_slowmotion) return false; if (settings->video.black_frame_insertion) video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL); if (state_manager_frame_is_reversed()) runloop_msg_queue_push_new(MSG_SLOW_MOTION_REWIND, 0, 30, true); else runloop_msg_queue_push_new(MSG_SLOW_MOTION, 0, 30, true); } break; case RUNLOOP_CTL_CHECK_MOVIE: if (bsv_movie_ctl(BSV_MOVIE_CTL_PLAYBACK_ON, NULL)) return runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE_PLAYBACK, NULL); if (!bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE_INIT, NULL); return runloop_ctl(RUNLOOP_CTL_CHECK_MOVIE_RECORD, NULL); case RUNLOOP_CTL_CHECK_MOVIE_RECORD: if (!bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; runloop_msg_queue_push_new( MSG_MOVIE_RECORD_STOPPED, 2, 180, true); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED)); event_command(EVENT_CMD_BSV_MOVIE_DEINIT); break; case RUNLOOP_CTL_CHECK_MOVIE_INIT: if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; { char msg[128]; char path[PATH_MAX_LENGTH]; settings->rewind_granularity = 1; if (settings->state_slot > 0) snprintf(path, sizeof(path), "%s%d", bsv_movie_get_path(), settings->state_slot); else strlcpy(path, bsv_movie_get_path(), sizeof(path)); strlcat(path, ".bsv", sizeof(path)); snprintf(msg, sizeof(msg), "%s \"%s\".", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), path); bsv_movie_init_handle(path, RARCH_MOVIE_RECORD); if (!bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) return false; else if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL)) { runloop_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), path); } else { runloop_msg_queue_push_new( MSG_FAILED_TO_START_MOVIE_RECORD, 1, 180, true); RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD)); } } break; case RUNLOOP_CTL_CHECK_MOVIE_PLAYBACK: if (!bsv_movie_ctl(BSV_MOVIE_CTL_END, NULL)) return false; runloop_msg_queue_push_new( MSG_MOVIE_PLAYBACK_ENDED, 1, 180, false); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED)); event_command(EVENT_CMD_BSV_MOVIE_DEINIT); bsv_movie_ctl(BSV_MOVIE_CTL_UNSET_END, NULL); bsv_movie_ctl(BSV_MOVIE_CTL_UNSET_PLAYBACK, NULL); break; case RUNLOOP_CTL_STATE_FREE: runloop_perfcnt_enable = false; runloop_idle = false; runloop_paused = false; runloop_slowmotion = false; runloop_frame_time_last = false; runloop_set_frame_limit = false; runloop_overrides_active = false; runloop_max_frames = 0; break; case RUNLOOP_CTL_GLOBAL_FREE: { global_t *global; event_command(EVENT_CMD_TEMPORARY_CONTENT_DEINIT); event_command(EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT); event_command(EVENT_CMD_RECORD_DEINIT); event_command(EVENT_CMD_LOG_FILE_DEINIT); rarch_ctl(RARCH_CTL_UNSET_BLOCK_CONFIG_READ, NULL); runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); runloop_overrides_active = false; global = global_get_ptr(); memset(global, 0, sizeof(struct global)); } break; case RUNLOOP_CTL_CLEAR_STATE: driver_ctl(RARCH_DRIVER_CTL_DEINIT, NULL); runloop_ctl(RUNLOOP_CTL_STATE_FREE, NULL); runloop_ctl(RUNLOOP_CTL_GLOBAL_FREE, NULL); break; case RUNLOOP_CTL_SET_MAX_FRAMES: { unsigned *ptr = (unsigned*)data; if (!ptr) return false; runloop_max_frames = *ptr; } break; case RUNLOOP_CTL_IS_IDLE: return runloop_idle; case RUNLOOP_CTL_SET_IDLE: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_idle = *ptr; } break; case RUNLOOP_CTL_IS_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; *ptr = runloop_slowmotion; } break; case RUNLOOP_CTL_SET_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_slowmotion = *ptr; } break; case RUNLOOP_CTL_SET_PAUSED: { bool *ptr = (bool*)data; if (!ptr) return false; runloop_paused = *ptr; } break; case RUNLOOP_CTL_IS_PAUSED: return runloop_paused; case RUNLOOP_CTL_MSG_QUEUE_FREE: #ifdef HAVE_THREADS slock_free(runloop_msg_queue_lock); runloop_msg_queue_lock = NULL; #endif break; case RUNLOOP_CTL_MSG_QUEUE_DEINIT: if (!g_msg_queue) return true; runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_LOCK, NULL); msg_queue_free(g_msg_queue); runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_UNLOCK, NULL); runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_FREE, NULL); g_msg_queue = NULL; break; case RUNLOOP_CTL_MSG_QUEUE_INIT: runloop_ctl(RUNLOOP_CTL_MSG_QUEUE_DEINIT, NULL); g_msg_queue = msg_queue_new(8); retro_assert(g_msg_queue); #ifdef HAVE_THREADS runloop_msg_queue_lock = slock_new(); retro_assert(runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_MSG_QUEUE_LOCK: #ifdef HAVE_THREADS slock_lock(runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_MSG_QUEUE_UNLOCK: #ifdef HAVE_THREADS slock_unlock(runloop_msg_queue_lock); #endif break; case RUNLOOP_CTL_PREPARE_DUMMY: #ifdef HAVE_MENU menu_driver_ctl(RARCH_MENU_CTL_UNSET_LOAD_NO_CONTENT, NULL); #endif runloop_data_clear_state(); runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); rarch_ctl(RARCH_CTL_LOAD_CONTENT, NULL); break; case RUNLOOP_CTL_SET_CORE_SHUTDOWN: runloop_core_shutdown_initiated = true; break; case RUNLOOP_CTL_UNSET_CORE_SHUTDOWN: runloop_core_shutdown_initiated = false; break; case RUNLOOP_CTL_IS_CORE_SHUTDOWN: return runloop_core_shutdown_initiated; case RUNLOOP_CTL_SET_SHUTDOWN: runloop_shutdown_initiated = true; break; case RUNLOOP_CTL_UNSET_SHUTDOWN: runloop_shutdown_initiated = false; break; case RUNLOOP_CTL_IS_SHUTDOWN: return runloop_shutdown_initiated; case RUNLOOP_CTL_SET_EXEC: runloop_exec = true; break; case RUNLOOP_CTL_UNSET_EXEC: runloop_exec = false; break; case RUNLOOP_CTL_IS_EXEC: return runloop_exec; case RUNLOOP_CTL_DATA_DEINIT: rarch_task_deinit(); break; case RUNLOOP_CTL_IS_CORE_OPTION_UPDATED: return runloop_system.core_options ? core_option_updated(runloop_system.core_options) : false; case RUNLOOP_CTL_CORE_OPTION_PREV: { unsigned *idx = (unsigned*)data; if (!idx) return false; core_option_prev(runloop_system.core_options, *idx); if (ui_companion_is_on_foreground()) ui_companion_driver_notify_refresh(); } return true; case RUNLOOP_CTL_CORE_OPTION_NEXT: { unsigned *idx = (unsigned*)data; if (!idx) return false; core_option_next(runloop_system.core_options, *idx); if (ui_companion_is_on_foreground()) ui_companion_driver_notify_refresh(); } return true; case RUNLOOP_CTL_CORE_OPTIONS_GET: { struct retro_variable *var = (struct retro_variable*)data; if (!runloop_system.core_options || !var) return false; RARCH_LOG("Environ GET_VARIABLE %s:\n", var->key); core_option_get(runloop_system.core_options, var); RARCH_LOG("\t%s\n", var->value ? var->value : "N/A"); } return true; case RUNLOOP_CTL_CORE_OPTIONS_INIT: { char *game_options_path = NULL; bool ret = false; const struct retro_variable *vars = (const struct retro_variable*)data; char buf[PATH_MAX_LENGTH] = {0}; global_t *global = global_get_ptr(); const char *options_path = settings->core_options_path; if (!*options_path && *global->path.config) { fill_pathname_resolve_relative(buf, global->path.config, "retroarch-core-options.cfg", sizeof(buf)); options_path = buf; } if (settings->game_specific_options) ret = rarch_game_specific_options(&game_options_path); if(ret) { runloop_ctl(RUNLOOP_CTL_SET_GAME_OPTIONS_ACTIVE, NULL); runloop_system.core_options = core_option_new(game_options_path, vars); free(game_options_path); } else { runloop_ctl(RUNLOOP_CTL_UNSET_GAME_OPTIONS_ACTIVE, NULL); runloop_system.core_options = core_option_new(options_path, vars); } } break; case RUNLOOP_CTL_CORE_OPTIONS_DEINIT: if (!runloop_system.core_options) return false; core_option_flush(runloop_system.core_options); core_option_free(runloop_system.core_options); runloop_system.core_options = NULL; return true; case RUNLOOP_CTL_KEY_EVENT_GET: { retro_keyboard_event_t **key_event = (retro_keyboard_event_t**)data; if (!key_event) return false; *key_event = &runloop_key_event; } break; case RUNLOOP_CTL_NONE: default: return false; } return true; }
/** * rarch_environment_cb: * @cmd : Identifier of command. * @data : Pointer to data. * * Environment callback function implementation. * * Returns: true (1) if environment callback command could * be performed, otherwise false (0). **/ bool rarch_environment_cb(unsigned cmd, void *data) { unsigned p; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); if (ignore_environment_cb) return false; switch (cmd) { case RETRO_ENVIRONMENT_GET_OVERSCAN: *(bool*)data = !settings->video.crop_overscan; RARCH_LOG("Environ GET_OVERSCAN: %u\n", (unsigned)!settings->video.crop_overscan); break; case RETRO_ENVIRONMENT_GET_CAN_DUPE: *(bool*)data = true; RARCH_LOG("Environ GET_CAN_DUPE: true\n"); break; case RETRO_ENVIRONMENT_GET_VARIABLE: { if (!runloop_ctl(RUNLOOP_CTL_CORE_OPTIONS_GET, data)) { struct retro_variable *var = (struct retro_variable*)data; RARCH_LOG("Environ GET_VARIABLE %s:\n", var->key); if (var) var->value = NULL; RARCH_LOG("\t%s\n", var->value ? var->value : "N/A"); } break; } case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE: *(bool*)data = runloop_ctl(RUNLOOP_CTL_IS_CORE_OPTION_UPDATED, NULL); break; case RETRO_ENVIRONMENT_SET_VARIABLES: { RARCH_LOG("Environ SET_VARIABLES.\n"); runloop_ctl(RUNLOOP_CTL_CORE_OPTIONS_DEINIT, NULL); runloop_ctl(RUNLOOP_CTL_CORE_OPTIONS_INIT, data); break; } case RETRO_ENVIRONMENT_SET_MESSAGE: { const struct retro_message *msg = (const struct retro_message*)data; RARCH_LOG("Environ SET_MESSAGE: %s\n", msg->msg); runloop_msg_queue_push(msg->msg, 1, msg->frames, true); break; } case RETRO_ENVIRONMENT_SET_ROTATION: { unsigned rotation = *(const unsigned*)data; RARCH_LOG("Environ SET_ROTATION: %u\n", rotation); if (!settings->video.allow_rotate) break; system->rotation = rotation; if (!video_driver_set_rotation(rotation)) return false; break; } case RETRO_ENVIRONMENT_SHUTDOWN: RARCH_LOG("Environ SHUTDOWN.\n"); runloop_ctl(RUNLOOP_CTL_SET_SHUTDOWN, NULL); runloop_ctl(RUNLOOP_CTL_SET_CORE_SHUTDOWN, NULL); break; case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: system->performance_level = *(const unsigned*)data; RARCH_LOG("Environ PERFORMANCE_LEVEL: %u.\n", system->performance_level); break; case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: if (settings->system_directory[0] == '\0') { char *fullpath = NULL; runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", fullpath); fill_pathname_basedir(global->dir.systemdir, fullpath, sizeof(global->dir.systemdir)); *(const char**)data = global->dir.systemdir; RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", global->dir.systemdir); } else { *(const char**)data = settings->system_directory; RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", settings->system_directory); } break; case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY: *(const char**)data = rarch_get_current_savefile_dir(); break; case RETRO_ENVIRONMENT_GET_USERNAME: *(const char**)data = *settings->username ? settings->username : NULL; RARCH_LOG("Environ GET_USERNAME: \"%s\".\n", settings->username); break; case RETRO_ENVIRONMENT_GET_LANGUAGE: *(unsigned *)data = settings->user_language; RARCH_LOG("Environ GET_LANGUAGE: \"%u\".\n", settings->user_language); break; case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: { enum retro_pixel_format pix_fmt = *(const enum retro_pixel_format*)data; switch (pix_fmt) { case RETRO_PIXEL_FORMAT_0RGB1555: RARCH_LOG("Environ SET_PIXEL_FORMAT: 0RGB1555.\n"); break; case RETRO_PIXEL_FORMAT_RGB565: RARCH_LOG("Environ SET_PIXEL_FORMAT: RGB565.\n"); break; case RETRO_PIXEL_FORMAT_XRGB8888: RARCH_LOG("Environ SET_PIXEL_FORMAT: XRGB8888.\n"); break; default: return false; } video_driver_set_pixel_format(pix_fmt); break; } case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: { unsigned retro_id, retro_port; const struct retro_input_descriptor *desc = NULL; static const char *libretro_btn_desc[] = { "B (bottom)", "Y (left)", "Select", "Start", "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right", "A (right)", "X (up)", "L", "R", "L2", "R2", "L3", "R3", }; memset(system->input_desc_btn, 0, sizeof(system->input_desc_btn)); desc = (const struct retro_input_descriptor*)data; for (; desc->description; desc++) { retro_port = desc->port; retro_id = desc->id; if (desc->port >= MAX_USERS) continue; /* Ignore all others for now. */ if (desc->device != RETRO_DEVICE_JOYPAD && desc->device != RETRO_DEVICE_ANALOG) continue; if (desc->id >= RARCH_FIRST_CUSTOM_BIND) continue; if (desc->device == RETRO_DEVICE_ANALOG) { switch (retro_id) { case RETRO_DEVICE_ID_ANALOG_X: switch (desc->index) { case RETRO_DEVICE_INDEX_ANALOG_LEFT: system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_X_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_X_MINUS] = desc->description; break; case RETRO_DEVICE_INDEX_ANALOG_RIGHT: system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_X_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_X_MINUS] = desc->description; break; } break; case RETRO_DEVICE_ID_ANALOG_Y: switch (desc->index) { case RETRO_DEVICE_INDEX_ANALOG_LEFT: system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_Y_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_Y_MINUS] = desc->description; break; case RETRO_DEVICE_INDEX_ANALOG_RIGHT: system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description; break; } break; } } else system->input_desc_btn[retro_port][retro_id] = desc->description; } RARCH_LOG("Environ SET_INPUT_DESCRIPTORS:\n"); for (p = 0; p < settings->input.max_users; p++) { for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++) { const char *description = system->input_desc_btn[p][retro_id]; if (!description) continue; RARCH_LOG("\tRetroPad, User %u, Button \"%s\" => \"%s\"\n", p + 1, libretro_btn_desc[retro_id], description); } } global->has_set.input_descriptors = true; break; } case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK: { const struct retro_keyboard_callback *info = (const struct retro_keyboard_callback*)data; RARCH_LOG("Environ SET_KEYBOARD_CALLBACK.\n"); system->key_event = info->callback; global->frontend_key_event = system->key_event; break; } case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE: RARCH_LOG("Environ SET_DISK_CONTROL_INTERFACE.\n"); system->disk_control = *(const struct retro_disk_control_callback*)data; break; case RETRO_ENVIRONMENT_SET_HW_RENDER: case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL: { struct retro_hw_render_callback *hw_render = video_driver_callback(); struct retro_hw_render_callback *cb = (struct retro_hw_render_callback*)data; RARCH_LOG("Environ SET_HW_RENDER.\n"); switch (cb->context_type) { case RETRO_HW_CONTEXT_NONE: RARCH_LOG("Requesting no HW context.\n"); break; #if defined(HAVE_OPENGLES2) case RETRO_HW_CONTEXT_OPENGLES2: #if defined(HAVE_OPENGLES3) case RETRO_HW_CONTEXT_OPENGLES3: #endif RARCH_LOG("Requesting OpenGLES%u context.\n", cb->context_type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); break; #if defined(HAVE_OPENGLES3) case RETRO_HW_CONTEXT_OPENGLES_VERSION: RARCH_LOG("Requesting OpenGLES%u.%u context.\n", cb->version_major, cb->version_minor); break; #endif case RETRO_HW_CONTEXT_OPENGL: case RETRO_HW_CONTEXT_OPENGL_CORE: RARCH_ERR("Requesting OpenGL context, but RetroArch is compiled against OpenGLES2. Cannot use HW context.\n"); return false; #elif defined(HAVE_OPENGL) case RETRO_HW_CONTEXT_OPENGLES2: case RETRO_HW_CONTEXT_OPENGLES3: RARCH_ERR("Requesting OpenGLES%u context, but RetroArch is compiled against OpenGL. Cannot use HW context.\n", cb->context_type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); return false; case RETRO_HW_CONTEXT_OPENGLES_VERSION: RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against OpenGL. Cannot use HW context.\n", cb->version_major, cb->version_minor); return false; case RETRO_HW_CONTEXT_OPENGL: RARCH_LOG("Requesting OpenGL context.\n"); break; case RETRO_HW_CONTEXT_OPENGL_CORE: RARCH_LOG("Requesting core OpenGL context (%u.%u).\n", cb->version_major, cb->version_minor); break; #endif default: RARCH_LOG("Requesting unknown context.\n"); return false; } cb->get_current_framebuffer = video_driver_get_current_framebuffer; cb->get_proc_address = video_driver_get_proc_address; if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL) /* Old ABI. Don't copy garbage. */ memcpy(hw_render, cb, offsetof(struct retro_hw_render_callback, stencil)); else memcpy(hw_render, cb, sizeof(*cb)); break; } case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: { bool state = *(const bool*)data; RARCH_LOG("Environ SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no"); system->no_content = state; break; } case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH: { const char **path = (const char**)data; #ifdef HAVE_DYNAMIC *path = settings->libretro; #else *path = NULL; #endif break; } /* FIXME - PS3 audio driver needs to be fixed so that threaded * audio works correctly (audio is already on a thread for PS3 * audio driver so that's probably the problem) */ #if defined(HAVE_THREADS) && !defined(__CELLOS_LV2__) case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK: { const struct retro_audio_callback *info = (const struct retro_audio_callback*)data; RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n"); if (recording_driver_get_data_ptr()) /* A/V sync is a must. */ return false; #ifdef HAVE_NETPLAY if (global->netplay.enable) return false; #endif audio_driver_set_callback(info); break; } #endif case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK: { const struct retro_frame_time_callback *info = (const struct retro_frame_time_callback*)data; RARCH_LOG("Environ SET_FRAME_TIME_CALLBACK.\n"); #ifdef HAVE_NETPLAY /* retro_run() will be called in very strange and * mysterious ways, have to disable it. */ if (global->netplay.enable) return false; #endif system->frame_time = *info; break; } case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE: { struct retro_rumble_interface *iface = (struct retro_rumble_interface*)data; RARCH_LOG("Environ GET_RUMBLE_INTERFACE.\n"); iface->set_rumble_state = input_driver_set_rumble_state; break; } case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES: { uint64_t *mask = (uint64_t*)data; RARCH_LOG("Environ GET_INPUT_DEVICE_CAPABILITIES.\n"); if (input_driver_ctl(RARCH_INPUT_CTL_HAS_CAPABILITIES, NULL)) *mask = input_driver_get_capabilities(); else return false; break; } case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE: { struct retro_sensor_interface *iface = (struct retro_sensor_interface*)data; RARCH_LOG("Environ GET_SENSOR_INTERFACE.\n"); iface->set_sensor_state = input_sensor_set_state; iface->get_sensor_input = input_sensor_get_input; break; } case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE: { struct retro_camera_callback *cb = (struct retro_camera_callback*)data; RARCH_LOG("Environ GET_CAMERA_INTERFACE.\n"); cb->start = driver_camera_start; cb->stop = driver_camera_stop; system->camera_callback = *cb; if (cb->caps != 0) camera_driver_ctl(RARCH_CAMERA_CTL_SET_ACTIVE, NULL); else camera_driver_ctl(RARCH_CAMERA_CTL_UNSET_ACTIVE, NULL); break; } case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE: { struct retro_location_callback *cb = (struct retro_location_callback*)data; RARCH_LOG("Environ GET_LOCATION_INTERFACE.\n"); cb->start = driver_location_start; cb->stop = driver_location_stop; cb->get_position = driver_location_get_position; cb->set_interval = driver_location_set_interval; system->location_callback = *cb; location_driver_ctl(RARCH_LOCATION_CTL_UNSET_ACTIVE, NULL); break; } case RETRO_ENVIRONMENT_GET_LOG_INTERFACE: { struct retro_log_callback *cb = (struct retro_log_callback*)data; RARCH_LOG("Environ GET_LOG_INTERFACE.\n"); cb->log = rarch_log_libretro; break; } case RETRO_ENVIRONMENT_GET_PERF_INTERFACE: { struct retro_perf_callback *cb = (struct retro_perf_callback*)data; RARCH_LOG("Environ GET_PERF_INTERFACE.\n"); cb->get_time_usec = retro_get_time_usec; cb->get_cpu_features = retro_get_cpu_features; cb->get_perf_counter = retro_get_perf_counter; cb->perf_register = retro_perf_register; /* libretro specific path. */ cb->perf_start = retro_perf_start; cb->perf_stop = retro_perf_stop; cb->perf_log = retro_perf_log; /* libretro specific path. */ break; } case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY: { const char **dir = (const char**)data; *dir = *settings->core_assets_directory ? settings->core_assets_directory : NULL; RARCH_LOG("Environ CORE_ASSETS_DIRECTORY: \"%s\".\n", settings->core_assets_directory); break; } case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: { RARCH_LOG("Environ SET_SYSTEM_AV_INFO.\n"); return driver_update_system_av_info( (const struct retro_system_av_info*)data); } case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: { unsigned i, j; const struct retro_subsystem_info *info = (const struct retro_subsystem_info*)data; RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n"); for (i = 0; info[i].ident; i++) { RARCH_LOG("Special game type: %s\n", info[i].desc); RARCH_LOG(" Ident: %s\n", info[i].ident); RARCH_LOG(" ID: %u\n", info[i].id); RARCH_LOG(" Content:\n"); for (j = 0; j < info[i].num_roms; j++) { RARCH_LOG(" %s (%s)\n", info[i].roms[j].desc, info[i].roms[j].required ? "required" : "optional"); } } free(system->special); system->special = (struct retro_subsystem_info*) calloc(i, sizeof(*system->special)); if (!system->special) return false; memcpy(system->special, info, i * sizeof(*system->special)); system->num_special = i; break; } case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO: { unsigned i, j; const struct retro_controller_info *info = (const struct retro_controller_info*)data; RARCH_LOG("Environ SET_CONTROLLER_INFO.\n"); for (i = 0; info[i].types; i++) { RARCH_LOG("Controller port: %u\n", i + 1); for (j = 0; j < info[i].num_types; j++) RARCH_LOG(" %s (ID: %u)\n", info[i].types[j].desc, info[i].types[j].id); } free(system->ports); system->ports = (struct retro_controller_info*) calloc(i, sizeof(*system->ports)); if (!system->ports) return false; memcpy(system->ports, info, i * sizeof(*system->ports)); system->num_ports = i; break; } case RETRO_ENVIRONMENT_SET_GEOMETRY: { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); const struct retro_game_geometry *in_geom = (const struct retro_game_geometry*)data; struct retro_game_geometry *geom = av_info ? (struct retro_game_geometry*)&av_info->geometry : NULL; if (!geom) return false; RARCH_LOG("Environ SET_GEOMETRY.\n"); /* Can potentially be called every frame, * don't do anything unless required. */ if (geom->base_width != in_geom->base_width || geom->base_height != in_geom->base_height || geom->aspect_ratio != in_geom->aspect_ratio) { geom->base_width = in_geom->base_width; geom->base_height = in_geom->base_height; geom->aspect_ratio = in_geom->aspect_ratio; RARCH_LOG("SET_GEOMETRY: %ux%u, aspect: %.3f.\n", geom->base_width, geom->base_height, geom->aspect_ratio); /* Forces recomputation of aspect ratios if * using core-dependent aspect ratios. */ event_command(EVENT_CMD_VIDEO_SET_ASPECT_RATIO); /* TODO: Figure out what to do, if anything, with recording. */ } break; } /* Private extensions for internal use, not part of libretro API. */ case RETRO_ENVIRONMENT_SET_LIBRETRO_PATH: RARCH_LOG("Environ (Private) SET_LIBRETRO_PATH.\n"); if (!path_file_exists((const char*)data)) return false; runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, data); break; case RETRO_ENVIRONMENT_EXEC: case RETRO_ENVIRONMENT_EXEC_ESCAPE: { char *fullpath = NULL; runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath); if (fullpath != data) { runloop_ctl(RUNLOOP_CTL_CLEAR_CONTENT_PATH, NULL); if (data) runloop_ctl(RUNLOOP_CTL_SET_CONTENT_PATH, data); } #if defined(RARCH_CONSOLE) frontend_driver_set_fork(true, true); #elif defined(HAVE_DYNAMIC) rarch_ctl(RARCH_CTL_LOAD_CONTENT, NULL); #endif if (cmd == RETRO_ENVIRONMENT_EXEC_ESCAPE) { RARCH_LOG("Environ (Private) EXEC_ESCAPE.\n"); runloop_ctl(RUNLOOP_CTL_SET_EXEC, NULL); } else RARCH_LOG("Environ (Private) EXEC.\n"); } break; default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); return false; } return true; }
static int disk_options_disk_idx_left(unsigned type, const char *label, bool wraparound) { event_command(EVENT_CMD_DISK_PREV); return 0; }
/** * event_command: * @cmd : Event command index. * * Performs program event command with index @cmd. * * Returns: true (1) on success, otherwise false (0). **/ bool event_command(enum event_command cmd) { unsigned i = 0; bool boolean = false; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); (void)i; switch (cmd) { case EVENT_CMD_LOAD_CONTENT_PERSIST: #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CORE); #endif rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT, NULL); break; #ifdef HAVE_FFMPEG case EVENT_CMD_LOAD_CONTENT_FFMPEG: rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT_FFMPEG, NULL); break; #endif case EVENT_CMD_LOAD_CONTENT_IMAGEVIEWER: rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT_IMAGEVIEWER, NULL); break; case EVENT_CMD_LOAD_CONTENT: #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CONTENT_PERSIST); #else rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)settings->libretro); rarch_environment_cb(RETRO_ENVIRONMENT_EXEC, (void*)global->path.fullpath); event_command(EVENT_CMD_QUIT); #endif break; case EVENT_CMD_LOAD_CORE_DEINIT: #ifdef HAVE_DYNAMIC libretro_free_system_info(&global->menu.info); #endif break; case EVENT_CMD_LOAD_CORE_PERSIST: event_command(EVENT_CMD_LOAD_CORE_DEINIT); { #ifdef HAVE_MENU menu_handle_t *menu = menu_driver_get_ptr(); if (menu) event_update_system_info(&global->menu.info, &menu->load_no_content); #endif } break; case EVENT_CMD_LOAD_CORE: event_command(EVENT_CMD_LOAD_CORE_PERSIST); #ifndef HAVE_DYNAMIC event_command(EVENT_CMD_QUIT); #endif break; case EVENT_CMD_LOAD_STATE: /* Immutable - disallow savestate load when * we absolutely cannot change game state. */ if (global->bsv.movie) return false; #ifdef HAVE_NETPLAY if (driver->netplay_data) return false; #endif event_main_state(cmd); break; case EVENT_CMD_RESIZE_WINDOWED_SCALE: if (global->pending.windowed_scale == 0) return false; settings->video.scale = global->pending.windowed_scale; if (!settings->video.fullscreen) event_command(EVENT_CMD_REINIT); global->pending.windowed_scale = 0; break; case EVENT_CMD_MENU_TOGGLE: #ifdef HAVE_MENU if (menu_driver_alive()) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); else rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif break; case EVENT_CMD_CONTROLLERS_INIT: event_init_controllers(); break; case EVENT_CMD_RESET: RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET)); rarch_main_msg_queue_push_new(MSG_RESET, 1, 120, true); core.retro_reset(); /* bSNES since v073r01 resets controllers to JOYPAD * after a reset, so just enforce it here. */ event_command(EVENT_CMD_CONTROLLERS_INIT); break; case EVENT_CMD_SAVE_STATE: if (settings->savestate_auto_index) settings->state_slot++; event_main_state(cmd); break; case EVENT_CMD_SAVE_STATE_DECREMENT: /* Slot -1 is (auto) slot. */ if (settings->state_slot >= 0) settings->state_slot--; break; case EVENT_CMD_SAVE_STATE_INCREMENT: settings->state_slot++; break; case EVENT_CMD_TAKE_SCREENSHOT: if (!take_screenshot()) return false; break; case EVENT_CMD_PREPARE_DUMMY: { #ifdef HAVE_MENU menu_handle_t *menu = menu_driver_get_ptr(); if (menu) menu->load_no_content = false; #endif rarch_main_data_deinit(); *global->path.fullpath = '\0'; rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT, NULL); } break; case EVENT_CMD_UNLOAD_CORE: event_command(EVENT_CMD_PREPARE_DUMMY); event_command(EVENT_CMD_LOAD_CORE_DEINIT); break; case EVENT_CMD_QUIT: rarch_ctl(RARCH_ACTION_STATE_QUIT, NULL); break; case EVENT_CMD_REINIT: { const struct retro_hw_render_callback *hw_render = (const struct retro_hw_render_callback*)video_driver_callback(); const input_driver_t *input = driver ? (const input_driver_t*)driver->input : NULL; driver->video_cache_context = hw_render->cache_context; driver->video_cache_context_ack = false; event_command(EVENT_CMD_RESET_CONTEXT); driver->video_cache_context = false; /* Poll input to avoid possibly stale data to corrupt things. */ input->poll(driver->input_data); #ifdef HAVE_MENU menu_display_ctl(MENU_DISPLAY_CTL_SET_FRAMEBUFFER_DIRTY_FLAG, NULL); if (menu_driver_alive()) event_command(EVENT_CMD_VIDEO_SET_BLOCKING_STATE); #endif } break; case EVENT_CMD_CHEATS_DEINIT: if (!global) break; if (global->cheat) cheat_manager_free(global->cheat); global->cheat = NULL; break; case EVENT_CMD_CHEATS_INIT: event_command(EVENT_CMD_CHEATS_DEINIT); event_init_cheats(); break; case EVENT_CMD_CHEATS_APPLY: if (!global->cheat) break; cheat_manager_apply_cheats(global->cheat); break; case EVENT_CMD_REMAPPING_DEINIT: break; case EVENT_CMD_REMAPPING_INIT: event_command(EVENT_CMD_REMAPPING_DEINIT); event_init_remapping(); break; case EVENT_CMD_REWIND_DEINIT: if (!global) break; #ifdef HAVE_NETPLAY if (driver->netplay_data) return false; #endif if (global->rewind.state) state_manager_free(global->rewind.state); global->rewind.state = NULL; break; case EVENT_CMD_REWIND_INIT: if (!driver->netplay_data) init_rewind(); break; case EVENT_CMD_REWIND_TOGGLE: if (settings->rewind_enable) event_command(EVENT_CMD_REWIND_INIT); else event_command(EVENT_CMD_REWIND_DEINIT); break; case EVENT_CMD_AUTOSAVE_DEINIT: #ifdef HAVE_THREADS event_deinit_autosave(); #endif break; case EVENT_CMD_AUTOSAVE_INIT: event_command(EVENT_CMD_AUTOSAVE_DEINIT); #ifdef HAVE_THREADS event_init_autosave(); #endif break; case EVENT_CMD_AUTOSAVE_STATE: event_save_auto_state(); break; case EVENT_CMD_AUDIO_STOP: if (!driver->audio_data) return false; if (!audio_driver_alive()) return false; if (!audio_driver_stop()) return false; break; case EVENT_CMD_AUDIO_START: if (!driver->audio_data || audio_driver_alive()) return false; if (!settings->audio.mute_enable && !audio_driver_start()) { RARCH_ERR("Failed to start audio driver. Will continue without audio.\n"); driver->audio_active = false; } break; case EVENT_CMD_AUDIO_MUTE_TOGGLE: { const char *msg = !settings->audio.mute_enable ? msg_hash_to_str(MSG_AUDIO_MUTED): msg_hash_to_str(MSG_AUDIO_UNMUTED); if (!audio_driver_mute_toggle()) { RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_UNMUTE_AUDIO)); return false; } rarch_main_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s\n", msg); } break; case EVENT_CMD_OVERLAY_DEINIT: #ifdef HAVE_OVERLAY input_overlay_free_ptr(); #endif break; case EVENT_CMD_OVERLAY_INIT: event_command(EVENT_CMD_OVERLAY_DEINIT); #ifdef HAVE_OVERLAY if (input_overlay_new_ptr() == -1) RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_LOAD_OVERLAY)); #endif break; case EVENT_CMD_OVERLAY_NEXT: #ifdef HAVE_OVERLAY input_overlay_next(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DSP_FILTER_DEINIT: if (!global) break; audio_driver_dsp_filter_free(); break; case EVENT_CMD_DSP_FILTER_INIT: event_command(EVENT_CMD_DSP_FILTER_DEINIT); if (!*settings->audio.dsp_plugin) break; audio_driver_dsp_filter_init(settings->audio.dsp_plugin); break; case EVENT_CMD_GPU_RECORD_DEINIT: if (!global) break; if (global->record.gpu_buffer) free(global->record.gpu_buffer); global->record.gpu_buffer = NULL; break; case EVENT_CMD_RECORD_DEINIT: if (!recording_deinit()) return false; break; case EVENT_CMD_RECORD_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!recording_init()) return false; break; case EVENT_CMD_HISTORY_DEINIT: if (g_defaults.history) { content_playlist_write_file(g_defaults.history); content_playlist_free(g_defaults.history); } g_defaults.history = NULL; break; case EVENT_CMD_HISTORY_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!settings->history_list_enable) return false; RARCH_LOG("%s: [%s].\n", msg_hash_to_str(MSG_LOADING_HISTORY_FILE), settings->content_history_path); g_defaults.history = content_playlist_init( settings->content_history_path, settings->content_history_size); break; case EVENT_CMD_CORE_INFO_DEINIT: if (!global) break; if (global->core_info.list) core_info_list_free(global->core_info.list); global->core_info.list = NULL; break; case EVENT_CMD_DATA_RUNLOOP_FREE: rarch_main_data_free(); break; case EVENT_CMD_CORE_INFO_INIT: event_command(EVENT_CMD_CORE_INFO_DEINIT); if (*settings->libretro_directory) global->core_info.list = core_info_list_new(); break; case EVENT_CMD_CORE_DEINIT: { struct retro_hw_render_callback *cb = video_driver_callback(); event_deinit_core(true); if (cb) memset(cb, 0, sizeof(*cb)); break; } case EVENT_CMD_CORE_INIT: if (!event_init_core()) return false; break; case EVENT_CMD_VIDEO_APPLY_STATE_CHANGES: video_driver_apply_state_changes(); break; case EVENT_CMD_VIDEO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_VIDEO_SET_BLOCKING_STATE: video_driver_set_nonblock_state(boolean); break; case EVENT_CMD_VIDEO_SET_ASPECT_RATIO: video_driver_set_aspect_ratio(settings->video.aspect_ratio_idx); break; case EVENT_CMD_AUDIO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_AUDIO_SET_BLOCKING_STATE: audio_driver_set_nonblock_state(boolean); break; case EVENT_CMD_OVERLAY_SET_SCALE_FACTOR: #ifdef HAVE_OVERLAY input_overlay_set_scale_factor(settings->input.overlay_scale); #endif break; case EVENT_CMD_OVERLAY_SET_ALPHA_MOD: #ifdef HAVE_OVERLAY input_overlay_set_alpha_mod(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DRIVERS_DEINIT: uninit_drivers(DRIVERS_CMD_ALL); break; case EVENT_CMD_DRIVERS_INIT: init_drivers(DRIVERS_CMD_ALL); break; case EVENT_CMD_AUDIO_REINIT: uninit_drivers(DRIVER_AUDIO); init_drivers(DRIVER_AUDIO); break; case EVENT_CMD_RESET_CONTEXT: event_command(EVENT_CMD_DRIVERS_DEINIT); event_command(EVENT_CMD_DRIVERS_INIT); break; case EVENT_CMD_QUIT_RETROARCH: rarch_ctl(RARCH_ACTION_STATE_FORCE_QUIT, NULL); break; case EVENT_CMD_RESUME: rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); break; case EVENT_CMD_RESTART_RETROARCH: #if defined(GEKKO) && defined(HW_RVL) fill_pathname_join(global->path.fullpath, g_defaults.dir.core, SALAMANDER_FILE, sizeof(global->path.fullpath)); #endif if (driver->frontend_ctx && driver->frontend_ctx->set_fork) driver->frontend_ctx->set_fork(true, false); break; case EVENT_CMD_MENU_SAVE_CONFIG: if (!event_save_core_config()) return false; break; case EVENT_CMD_SHADERS_APPLY_CHANGES: #ifdef HAVE_MENU menu_shader_manager_apply_changes(); #endif break; case EVENT_CMD_PAUSE_CHECKS: rarch_main_ctl(RARCH_MAIN_CTL_IS_PAUSED, &boolean); if (boolean) { RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); event_command(EVENT_CMD_AUDIO_STOP); if (settings->video.black_frame_insertion) video_driver_cached_frame(); } else { RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED)); event_command(EVENT_CMD_AUDIO_START); } break; case EVENT_CMD_PAUSE_TOGGLE: rarch_main_ctl(RARCH_MAIN_CTL_IS_PAUSED, &boolean); boolean = !boolean; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_UNPAUSE: boolean = false; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_PAUSE: boolean = true; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_MENU_PAUSE_LIBRETRO: #ifdef HAVE_MENU if (menu_driver_alive()) { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_STOP); else event_command(EVENT_CMD_AUDIO_START); } else { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_START); } #endif break; case EVENT_CMD_SHADER_DIR_DEINIT: if (!global) break; dir_list_free(global->shader_dir.list); global->shader_dir.list = NULL; global->shader_dir.ptr = 0; break; case EVENT_CMD_SHADER_DIR_INIT: event_command(EVENT_CMD_SHADER_DIR_DEINIT); if (!*settings->video.shader_dir) return false; global->shader_dir.list = dir_list_new_special(NULL, DIR_LIST_SHADERS); if (!global->shader_dir.list || global->shader_dir.list->size == 0) { event_command(EVENT_CMD_SHADER_DIR_DEINIT); return false; } global->shader_dir.ptr = 0; dir_list_sort(global->shader_dir.list, false); for (i = 0; i < global->shader_dir.list->size; i++) RARCH_LOG("%s \"%s\"\n", msg_hash_to_str(MSG_FOUND_SHADER), global->shader_dir.list->elems[i].data); break; case EVENT_CMD_SAVEFILES: event_save_files(); break; case EVENT_CMD_SAVEFILES_DEINIT: if (!global) break; if (global->savefiles) string_list_free(global->savefiles); global->savefiles = NULL; break; case EVENT_CMD_SAVEFILES_INIT: global->sram.use = global->sram.use && !global->sram.save_disable #ifdef HAVE_NETPLAY && (!driver->netplay_data || !global->netplay.is_client) #endif ; if (!global->sram.use) RARCH_LOG("%s\n", msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED)); if (global->sram.use) event_command(EVENT_CMD_AUTOSAVE_INIT); break; case EVENT_CMD_MSG_QUEUE_DEINIT: rarch_main_msg_queue_free(); break; case EVENT_CMD_MSG_QUEUE_INIT: event_command(EVENT_CMD_MSG_QUEUE_DEINIT); rarch_main_msg_queue_init(); rarch_main_data_init_queues(); break; case EVENT_CMD_BSV_MOVIE_DEINIT: if (!global) break; if (global->bsv.movie) bsv_movie_free(global->bsv.movie); global->bsv.movie = NULL; break; case EVENT_CMD_BSV_MOVIE_INIT: event_command(EVENT_CMD_BSV_MOVIE_DEINIT); event_init_movie(); break; case EVENT_CMD_NETPLAY_DEINIT: #ifdef HAVE_NETPLAY deinit_netplay(); #endif break; case EVENT_CMD_NETWORK_DEINIT: #ifdef HAVE_NETWORKING network_deinit(); #endif break; case EVENT_CMD_NETWORK_INIT: #ifdef HAVE_NETWORKING network_init(); #endif break; case EVENT_CMD_NETPLAY_INIT: event_command(EVENT_CMD_NETPLAY_DEINIT); #ifdef HAVE_NETPLAY if (!init_netplay()) return false; #endif break; case EVENT_CMD_NETPLAY_FLIP_PLAYERS: #ifdef HAVE_NETPLAY { netplay_t *netplay = (netplay_t*)driver->netplay_data; if (!netplay) return false; netplay_flip_users(netplay); } #endif break; case EVENT_CMD_FULLSCREEN_TOGGLE: if (!video_driver_has_windowed()) return false; /* If we go fullscreen we drop all drivers and * reinitialize to be safe. */ settings->video.fullscreen = !settings->video.fullscreen; event_command(EVENT_CMD_REINIT); break; case EVENT_CMD_COMMAND_DEINIT: #ifdef HAVE_COMMAND if (driver->command) rarch_cmd_free(driver->command); driver->command = NULL; #endif break; case EVENT_CMD_COMMAND_INIT: event_command(EVENT_CMD_COMMAND_DEINIT); #ifdef HAVE_COMMAND event_init_command(); #endif break; case EVENT_CMD_TEMPORARY_CONTENT_DEINIT: if (!global) break; if (global->temporary_content) event_free_temporary_content(); global->temporary_content = NULL; break; case EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT: if (!global) break; if (global->subsystem_fullpaths) string_list_free(global->subsystem_fullpaths); global->subsystem_fullpaths = NULL; break; case EVENT_CMD_LOG_FILE_DEINIT: if (!global) break; if (global->log_file && global->log_file != stderr) fclose(global->log_file); global->log_file = NULL; break; case EVENT_CMD_DISK_EJECT_TOGGLE: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (control) event_check_disk_eject(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_NEXT: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_next(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_PREV: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_prev(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_RUMBLE_STOP: for (i = 0; i < MAX_USERS; i++) { input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0); input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0); } break; case EVENT_CMD_GRAB_MOUSE_TOGGLE: { static bool grab_mouse_state = false; grab_mouse_state = !grab_mouse_state; if (!driver->input || !input_driver_grab_mouse(grab_mouse_state)) return false; RARCH_LOG("%s: %s.\n", msg_hash_to_str(MSG_GRAB_MOUSE_STATE), grab_mouse_state ? "yes" : "no"); video_driver_show_mouse(!grab_mouse_state); } break; case EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG: rarch_perf_log(); break; case EVENT_CMD_VOLUME_UP: event_set_volume(0.5f); break; case EVENT_CMD_VOLUME_DOWN: event_set_volume(-0.5f); break; case EVENT_CMD_SET_FRAME_LIMIT: rarch_main_ctl(RARCH_MAIN_CTL_SET_FRAME_LIMIT_LAST_TIME, NULL); break; case EVENT_CMD_NONE: default: return false; } return true; }
static bool ctr_frame(void* data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char* msg) { ctr_video_t* ctr = (ctr_video_t*)data; settings_t* settings = config_get_ptr(); static uint64_t currentTick,lastTick; static float fps = 0.0; static int total_frames = 0; static int frames = 0; extern bool select_pressed; RARCH_PERFORMANCE_INIT(ctrframe_f); RARCH_PERFORMANCE_START(ctrframe_f); if (!width || !height) { gspWaitForEvent(GSPEVENT_VBlank0, true); goto end; } if(!aptMainLoop()) { event_command(EVENT_CMD_QUIT); goto end; } if (select_pressed) { event_command(EVENT_CMD_QUIT); goto end; } frames++; currentTick = svcGetSystemTick(); uint32_t diff = currentTick - lastTick; if(diff > CTR_CPU_TICKS_PER_SECOND) { fps = (float)frames * ((float) CTR_CPU_TICKS_PER_SECOND / (float) diff); lastTick = currentTick; frames = 0; } printf("fps: %8.4f frames: %i\r", fps, total_frames++); // fflush(stdout); /* enable this to profile the core without video output */ #if 0 if (!ctr->menu_texture_enable) goto end; #endif svcWaitSynchronization(gspEvents[GSPEVENT_P3D], 20000000); svcClearEvent(gspEvents[GSPEVENT_P3D]); svcWaitSynchronization(gspEvents[GSPEVENT_PPF], 20000000); svcClearEvent(gspEvents[GSPEVENT_PPF]); gfxSwapBuffersGpu(); if (ctr->vsync) gspWaitForEvent(GSPEVENT_VBlank0, true); ctrGuSetMemoryFill(true, (u32*)CTR_GPU_FRAMEBUFFER, 0x00000000, (u32*)(CTR_GPU_FRAMEBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201, (u32*)CTR_GPU_DEPTHBUFFER, 0x00000000, (u32*)(CTR_GPU_DEPTHBUFFER + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * sizeof(uint32_t)), 0x201); GPUCMD_SetBufferOffset(0); if (width > ctr->texture_width) width = ctr->texture_width; if (height > ctr->texture_height) height = ctr->texture_height; if(frame) { if(((((u32)(frame)) >= 0x14000000 && ((u32)(frame)) < 0x1c000000)) /* frame in linear memory */ && !((u32)frame & 0x7F) /* 128-byte aligned */ && !((pitch) & 0xF)) /* 16-byte aligned */ { /* can copy the buffer directly with the GPU */ ctrGuCopyImage(false, frame, pitch / 2, height, CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, CTRGU_RGB565, true); } else { int i; uint16_t* dst = (uint16_t*)ctr->texture_linear; const uint8_t* src = frame; for (i = 0; i < height; i++) { memcpy(dst, src, width * sizeof(uint16_t)); dst += ctr->texture_width; src += pitch; } GSPGPU_FlushDataCache(NULL, ctr->texture_linear, ctr->texture_width * ctr->texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->texture_linear, ctr->texture_width, ctr->menu.texture_height, CTRGU_RGB565, false, ctr->texture_swizzled, ctr->texture_width, CTRGU_RGB565, true); } } ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->texture_swizzled), ctr->texture_width, ctr->texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGB565); ctr->frame_coords->u = width; ctr->frame_coords->v = height; GSPGPU_FlushDataCache(NULL, (u8*)ctr->frame_coords, sizeof(ctr_vertex_t)); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->frame_coords)); ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->scale_vector, 1); GPU_DrawArray(GPU_UNKPRIM, 1); if (ctr->menu_texture_enable) { GSPGPU_FlushDataCache(NULL, ctr->menu.texture_linear, ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t)); ctrGuCopyImage(false, ctr->menu.texture_linear, ctr->menu.texture_width, ctr->menu.texture_height, CTRGU_RGBA4444,false, ctr->menu.texture_swizzled, ctr->menu.texture_width, CTRGU_RGBA4444, true); ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->menu.texture_swizzled), ctr->menu.texture_width, ctr->menu.texture_height, GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE), GPU_RGBA4); ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->menu.frame_coords)); ctrGuSetVertexShaderFloatUniform(1, (float*)&ctr->menu.scale_vector, 1); GPU_DrawArray(GPU_UNKPRIM, 1); } GPU_FinishDrawing(); GPUCMD_Finalize(); ctrGuFlushAndRun(true); ctrGuDisplayTransfer(true, CTR_GPU_FRAMEBUFFER, 240,400, CTRGU_RGBA8, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 240,400,CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE); end: // gspWaitForEvent(GSPEVENT_VBlank0, true); RARCH_PERFORMANCE_STOP(ctrframe_f); return true; }
void init_video(void) { unsigned max_dim, scale, width, height; video_viewport_t *custom_vp = NULL; const input_driver_t *tmp = NULL; const struct retro_game_geometry *geom = NULL; video_info_t video = {0}; static uint16_t dummy_pixels[32] = {0}; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); init_video_filter(video_state.pix_fmt); event_command(EVENT_CMD_SHADER_DIR_INIT); if (av_info) geom = (const struct retro_game_geometry*)&av_info->geometry; max_dim = max(geom->max_width, geom->max_height); scale = next_pow2(max_dim) / RARCH_SCALE_BASE; scale = max(scale, 1); if (video_state.filter.filter) scale = video_state.filter.scale; /* Update core-dependent aspect ratio values. */ video_viewport_set_square_pixel(geom->base_width, geom->base_height); video_viewport_set_core(); video_viewport_set_config(); /* Update CUSTOM viewport. */ custom_vp = video_viewport_get_custom(); if (settings->video.aspect_ratio_idx == ASPECT_RATIO_CUSTOM) { float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value; aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (custom_vp->width && custom_vp->height) ? (float)custom_vp->width / custom_vp->height : default_aspect; } video_driver_set_aspect_ratio_value( aspectratio_lut[settings->video.aspect_ratio_idx].value); if (settings->video.fullscreen) { width = settings->video.fullscreen_x; height = settings->video.fullscreen_y; } else { if (settings->video.force_aspect) { /* Do rounding here to simplify integer scale correctness. */ unsigned base_width = roundf(geom->base_height * video_driver_get_aspect_ratio()); width = roundf(base_width * settings->video.scale); } else width = roundf(geom->base_width * settings->video.scale); height = roundf(geom->base_height * settings->video.scale); } if (width && height) RARCH_LOG("Video @ %ux%u\n", width, height); else RARCH_LOG("Video @ fullscreen\n"); driver->display_type = RARCH_DISPLAY_NONE; driver->video_display = 0; driver->video_window = 0; if (!init_video_pixel_converter(RARCH_SCALE_BASE * scale)) { RARCH_ERR("Failed to initialize pixel converter.\n"); rarch_fail(1, "init_video()"); } video.width = width; video.height = height; video.fullscreen = settings->video.fullscreen; video.vsync = settings->video.vsync && !system->force_nonblock; video.force_aspect = settings->video.force_aspect; #ifdef GEKKO video.viwidth = settings->video.viwidth; video.vfilter = settings->video.vfilter; #endif video.smooth = settings->video.smooth; video.input_scale = scale; video.rgb32 = video_state.filter.filter ? video_state.filter.out_rgb32 : (video_state.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); tmp = (const input_driver_t*)driver->input; /* Need to grab the "real" video driver interface on a reinit. */ find_video_driver(); #ifdef HAVE_THREADS if (settings->video.threaded && !video_state.hw_render_callback.context_type) { /* Can't do hardware rendering with threaded driver currently. */ RARCH_LOG("Starting threaded video driver ...\n"); if (!rarch_threaded_video_init(&driver->video, &driver->video_data, &driver->input, &driver->input_data, driver->video, &video)) { RARCH_ERR("Cannot open threaded video driver ... Exiting ...\n"); rarch_fail(1, "init_video()"); } } else #endif driver->video_data = driver->video->init(&video, &driver->input, &driver->input_data); if (!driver->video_data) { RARCH_ERR("Cannot open video driver ... Exiting ...\n"); rarch_fail(1, "init_video()"); } driver->video_poke = NULL; if (driver->video->poke_interface) driver->video->poke_interface(driver->video_data, &driver->video_poke); if (driver->video->viewport_info && (!custom_vp->width || !custom_vp->height)) { /* Force custom viewport to have sane parameters. */ custom_vp->width = width; custom_vp->height = height; video_driver_viewport_info(custom_vp); } video_driver_set_rotation( (settings->video.rotation + system->rotation) % 4); video_driver_suppress_screensaver(settings->ui.suspend_screensaver_enable); if (!driver->input) init_video_input(tmp); event_command(EVENT_CMD_OVERLAY_DEINIT); event_command(EVENT_CMD_OVERLAY_INIT); video_driver_cached_frame_set(&dummy_pixels, 4, 4, 8); #if defined(PSP) video_driver_set_texture_frame(&dummy_pixels, false, 1, 1, 1.0f); #endif }
static int generic_action_ok_command(enum event_command cmd) { if (!event_command(cmd)) return -1; return 0; }