void init_audio(void) { audio_convert_init_simd(); // Resource leaks will follow if audio is initialized twice. if (driver.audio_data) return; // Accomodate rewind since at some point we might have two full buffers. size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2; size_t outsamples_max = max_bufsamples * AUDIO_MAX_RATIO * g_settings.slowmotion_ratio; // Used for recording even if audio isn't enabled. rarch_assert(g_extern.audio_data.conv_outsamples = (int16_t*)malloc(outsamples_max * sizeof(int16_t))); g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size; // Needs to be able to hold full content of a full max_bufsamples in addition to its own. rarch_assert(g_extern.audio_data.rewind_buf = (int16_t*)malloc(max_bufsamples * sizeof(int16_t))); g_extern.audio_data.rewind_size = max_bufsamples; if (!g_settings.audio.enable) { g_extern.audio_active = false; return; } find_audio_driver(); #ifdef HAVE_THREADS if (g_extern.system.audio_callback.callback) { RARCH_LOG("Starting threaded audio driver ...\n"); if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data, *g_settings.audio.device ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency, driver.audio)) { RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n"); rarch_fail(1, "init_audio()"); } } else #endif { driver.audio_data = driver.audio->init(*g_settings.audio.device ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency); } if (!driver.audio_data) { RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n"); g_extern.audio_active = false; } g_extern.audio_data.use_float = false; if (g_extern.audio_active && driver.audio->use_float && driver.audio->use_float(driver.audio_data)) g_extern.audio_data.use_float = true; if (!g_settings.audio.sync && g_extern.audio_active) { rarch_main_command(RARCH_CMD_AUDIO_SET_NONBLOCKING_STATE); g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size; } // Should never happen. if (g_extern.audio_data.in_rate <= 0.0f) { RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n", g_extern.audio_data.in_rate, g_settings.audio.out_rate); g_extern.audio_data.in_rate = g_settings.audio.out_rate; } g_extern.audio_data.orig_src_ratio = g_extern.audio_data.src_ratio = (double)g_settings.audio.out_rate / g_extern.audio_data.in_rate; if (!rarch_resampler_realloc(&g_extern.audio_data.resampler_data, &g_extern.audio_data.resampler, g_settings.audio.resampler, g_extern.audio_data.orig_src_ratio)) { RARCH_ERR("Failed to initialize resampler \"%s\".\n", g_settings.audio.resampler); g_extern.audio_active = false; } rarch_assert(g_extern.audio_data.data = (float*)malloc(max_bufsamples * sizeof(float))); g_extern.audio_data.data_ptr = 0; rarch_assert(g_settings.audio.out_rate < g_extern.audio_data.in_rate * AUDIO_MAX_RATIO); rarch_assert(g_extern.audio_data.outsamples = (float*)malloc(outsamples_max * sizeof(float))); g_extern.audio_data.rate_control = false; if (!g_extern.system.audio_callback.callback && g_extern.audio_active && g_settings.audio.rate_control) { if (driver.audio->buffer_size && driver.audio->write_avail) { g_extern.audio_data.driver_buffer_size = driver.audio->buffer_size(driver.audio_data); g_extern.audio_data.rate_control = true; } else RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n"); } rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); g_extern.measure_data.buffer_free_samples_count = 0; if (g_extern.audio_active && !g_extern.audio_data.mute && g_extern.system.audio_callback.callback) // Threaded driver is initially stopped. driver.audio->start(driver.audio_data); }
void recording_dump_frame(const void *data, unsigned width, unsigned height, size_t pitch) { struct ffemu_video_data ffemu_data = {0}; if (!driver.recording_data) return; ffemu_data.pitch = pitch; ffemu_data.width = width; ffemu_data.height = height; ffemu_data.data = data; if (g_extern.record_gpu_buffer) { struct video_viewport vp = {0}; if (driver.video && driver.video->viewport_info) driver.video->viewport_info(driver.video_data, &vp); if (!vp.width || !vp.height) { RARCH_WARN("Viewport size calculation failed! Will continue using raw data. This will probably not work right ...\n"); rarch_main_command(RARCH_CMD_GPU_RECORD_DEINIT); recording_dump_frame(data, width, height, pitch); return; } /* User has resized. We kinda have a problem now. */ if (vp.width != g_extern.record_gpu_width || vp.height != g_extern.record_gpu_height) { static const char msg[] = "Recording terminated due to resize."; RARCH_WARN("%s\n", msg); msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, msg, 1, 180); rarch_main_command(RARCH_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 (driver.video && driver.video->read_viewport) if (!driver.video->read_viewport(driver.video_data, g_extern.record_gpu_buffer)) return; ffemu_data.pitch = g_extern.record_gpu_width * 3; ffemu_data.width = g_extern.record_gpu_width; ffemu_data.height = g_extern.record_gpu_height; ffemu_data.data = g_extern.record_gpu_buffer + (ffemu_data.height - 1) * ffemu_data.pitch; ffemu_data.pitch = -ffemu_data.pitch; } if (!g_extern.record_gpu_buffer) ffemu_data.is_dupe = !data; if (driver.recording && driver.recording->push_video) driver.recording->push_video(driver.recording_data, &ffemu_data); }
LRESULT win32_menu_loop(HWND owner, WPARAM wparam) { WPARAM mode = wparam & 0xffff; unsigned cmd = RARCH_CMD_NONE; bool do_wm_close = false; switch (mode) { case ID_M_LOAD_CORE: case ID_M_LOAD_CONTENT: { char win32_file[PATH_MAX_LENGTH] = {0}; const char *extensions = NULL; const char *title = NULL; const char *initial_dir = NULL; if (mode == ID_M_LOAD_CORE) { extensions = "All Files\0*.*\0 Libretro core(.dll)\0*.dll\0"; title = "Load Core"; initial_dir = g_settings.libretro_directory; } else if (mode == ID_M_LOAD_CONTENT) { extensions = "All Files\0*.*\0\0"; title = "Load Content"; initial_dir = g_settings.menu_content_directory; } if (win32_browser(owner, win32_file, extensions, title, initial_dir)) { switch (mode) { case ID_M_LOAD_CORE: strlcpy(g_settings.libretro, win32_file, sizeof(g_settings.libretro)); cmd = RARCH_CMD_LOAD_CORE; break; case ID_M_LOAD_CONTENT: strlcpy(g_extern.fullpath, win32_file, sizeof(g_extern.fullpath)); cmd = RARCH_CMD_LOAD_CONTENT; do_wm_close = true; break; } } } break; case ID_M_RESET: cmd = RARCH_CMD_RESET; break; case ID_M_MUTE_TOGGLE: cmd = RARCH_CMD_AUDIO_MUTE_TOGGLE; break; case ID_M_MENU_TOGGLE: cmd = RARCH_CMD_MENU_TOGGLE; break; case ID_M_PAUSE_TOGGLE: cmd = RARCH_CMD_PAUSE_TOGGLE; break; case ID_M_LOAD_STATE: cmd = RARCH_CMD_LOAD_STATE; break; case ID_M_SAVE_STATE: cmd = RARCH_CMD_SAVE_STATE; break; case ID_M_DISK_CYCLE: cmd = RARCH_CMD_DISK_EJECT_TOGGLE; break; case ID_M_DISK_NEXT: cmd = RARCH_CMD_DISK_NEXT; break; case ID_M_DISK_PREV: cmd = RARCH_CMD_DISK_PREV; break; case ID_M_FULL_SCREEN: cmd = RARCH_CMD_FULLSCREEN_TOGGLE; break; case ID_M_MOUSE_GRAB: cmd = RARCH_CMD_GRAB_MOUSE_TOGGLE; break; case ID_M_TAKE_SCREENSHOT: cmd = RARCH_CMD_TAKE_SCREENSHOT; break; case ID_M_QUIT: do_wm_close = true; break; default: if (mode >= ID_M_WINDOW_SCALE_1X && mode <= ID_M_WINDOW_SCALE_10X) { unsigned idx = (mode - (ID_M_WINDOW_SCALE_1X-1)); g_extern.pending.windowed_scale = idx; cmd = RARCH_CMD_RESIZE_WINDOWED_SCALE; } else if (mode == ID_M_STATE_INDEX_AUTO) { signed idx = -1; g_settings.state_slot = idx; } else if (mode >= (ID_M_STATE_INDEX_AUTO+1) && mode <= (ID_M_STATE_INDEX_AUTO+10)) { signed idx = (mode - (ID_M_STATE_INDEX_AUTO+1)); g_settings.state_slot = idx; } break; } if (cmd != RARCH_CMD_NONE) rarch_main_command(cmd); if (do_wm_close) PostMessage(owner, WM_CLOSE, 0, 0); return 0L; }
void engine_handle_cmd(void *data) { struct android_app *android_app = (struct android_app*)g_android; int8_t cmd; if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd)) cmd = -1; switch (cmd) { case APP_CMD_INPUT_CHANGED: slock_lock(android_app->mutex); if (android_app->inputQueue) AInputQueue_detachLooper(android_app->inputQueue); android_app->inputQueue = android_app->pendingInputQueue; if (android_app->inputQueue) { RARCH_LOG("Attaching input queue to looper"); AInputQueue_attachLooper(android_app->inputQueue, android_app->looper, LOOPER_ID_INPUT, NULL, NULL); } scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); break; case APP_CMD_INIT_WINDOW: slock_lock(android_app->mutex); android_app->window = android_app->pendingWindow; scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); if (g_extern.is_paused) rarch_main_command(RARCH_CMD_REINIT); break; case APP_CMD_RESUME: slock_lock(android_app->mutex); android_app->activityState = cmd; scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); break; case APP_CMD_START: slock_lock(android_app->mutex); android_app->activityState = cmd; scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); break; case APP_CMD_PAUSE: slock_lock(android_app->mutex); android_app->activityState = cmd; scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); if (!g_extern.system.shutdown) { RARCH_LOG("Pausing RetroArch.\n"); g_extern.is_paused = true; } break; case APP_CMD_STOP: slock_lock(android_app->mutex); android_app->activityState = cmd; scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); break; case APP_CMD_CONFIG_CHANGED: break; case APP_CMD_TERM_WINDOW: slock_lock(android_app->mutex); /* The window is being hidden or closed, clean it up. */ /* terminate display/EGL context here */ #if 0 RARCH_WARN("Window is terminated outside PAUSED state.\n"); #endif android_app->window = NULL; scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); break; case APP_CMD_GAINED_FOCUS: g_extern.is_paused = false; if ((android_app->sensor_state_mask & (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE)) && android_app->accelerometerSensor == NULL && driver.input_data) android_input_set_sensor_state(driver.input_data, 0, RETRO_SENSOR_ACCELEROMETER_ENABLE, android_app->accelerometer_event_rate); break; case APP_CMD_LOST_FOCUS: /* Avoid draining battery while app is not being used. */ if ((android_app->sensor_state_mask & (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE)) && android_app->accelerometerSensor != NULL && driver.input_data) android_input_set_sensor_state(driver.input_data, 0, RETRO_SENSOR_ACCELEROMETER_DISABLE, android_app->accelerometer_event_rate); break; case APP_CMD_DESTROY: g_extern.system.shutdown = true; break; } }
/** * recording_init: * * Initializes recording. * * Returns: true (1) if successful, otherwise false (0). **/ bool recording_init(void) { struct ffemu_params params = {0}; const struct retro_system_av_info *info = &g_extern.system.av_info; if (!g_extern.recording_enable) return false; if (g_extern.libretro_dummy) { RARCH_WARN(RETRO_LOG_INIT_RECORDING_SKIPPED); return false; } if (!g_settings.video.gpu_record && g_extern.system.hw_render_callback.context_type) { RARCH_WARN("Libretro core is hardware rendered. Must use post-shaded recording as well.\n"); return false; } RARCH_LOG("Custom timing given: FPS: %.4f, Sample rate: %.4f\n", (float)g_extern.system.av_info.timing.fps, (float)g_extern.system.av_info.timing.sample_rate); params.out_width = info->geometry.base_width; params.out_height = info->geometry.base_height; params.fb_width = info->geometry.max_width; params.fb_height = info->geometry.max_height; params.channels = 2; params.filename = g_extern.record_path; params.fps = g_extern.system.av_info.timing.fps; params.samplerate = g_extern.system.av_info.timing.sample_rate; params.pix_fmt = (g_extern.system.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888) ? FFEMU_PIX_ARGB8888 : FFEMU_PIX_RGB565; params.config = NULL; if (*g_extern.record_config) params.config = g_extern.record_config; if (g_settings.video.gpu_record && driver.video->read_viewport) { struct video_viewport vp = {0}; if (driver.video && driver.video->viewport_info) driver.video->viewport_info(driver.video_data, &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 (g_settings.video.force_aspect && (g_extern.system.aspect_ratio > 0.0f)) params.aspect_ratio = g_extern.system.aspect_ratio; else params.aspect_ratio = (float)vp.width / vp.height; params.pix_fmt = FFEMU_PIX_BGR24; g_extern.record_gpu_width = vp.width; g_extern.record_gpu_height = vp.height; RARCH_LOG("Detected viewport of %u x %u\n", vp.width, vp.height); g_extern.record_gpu_buffer = (uint8_t*)malloc(vp.width * vp.height * 3); if (!g_extern.record_gpu_buffer) { RARCH_ERR("Failed to allocate GPU record buffer.\n"); return false; } } else { if (g_extern.record_width || g_extern.record_height) { params.out_width = g_extern.record_width; params.out_height = g_extern.record_height; } if (g_settings.video.force_aspect && (g_extern.system.aspect_ratio > 0.0f)) params.aspect_ratio = g_extern.system.aspect_ratio; else params.aspect_ratio = (float)params.out_width / params.out_height; if (g_settings.video.post_filter_record && g_extern.filter.filter) { unsigned max_width = 0; unsigned max_height = 0; if (g_extern.filter.out_rgb32) params.pix_fmt = FFEMU_PIX_ARGB8888; else params.pix_fmt = FFEMU_PIX_RGB565; rarch_softfilter_get_max_output_size(g_extern.filter.filter, &max_width, &max_height); params.fb_width = next_pow2(max_width); params.fb_height = next_pow2(max_height); } } RARCH_LOG("Recording to %s @ %ux%u. (FB size: %ux%u pix_fmt: %u)\n", g_extern.record_path, params.out_width, params.out_height, params.fb_width, params.fb_height, (unsigned)params.pix_fmt); if (!ffemu_init_first(&driver.recording, &driver.recording_data, ¶ms)) { RARCH_ERR(RETRO_LOG_INIT_RECORDING_FAILED); rarch_main_command(RARCH_CMD_GPU_RECORD_DEINIT); return false; } return true; }
static int do_state_checks( retro_input_t input, retro_input_t old_input, retro_input_t trigger_input) { if (BIT64_GET(trigger_input, RARCH_SCREENSHOT)) rarch_main_command(RARCH_CMD_TAKE_SCREENSHOT); if (BIT64_GET(trigger_input, RARCH_MUTE)) rarch_main_command(RARCH_CMD_AUDIO_MUTE_TOGGLE); if (BIT64_GET(input, RARCH_VOLUME_UP)) set_volume(0.5f); else if (BIT64_GET(input, RARCH_VOLUME_DOWN)) set_volume(-0.5f); if (BIT64_GET(trigger_input, RARCH_GRAB_MOUSE_TOGGLE)) rarch_main_command(RARCH_CMD_GRAB_MOUSE_TOGGLE); if (BIT64_GET(trigger_input, RARCH_OVERLAY_NEXT)) rarch_main_command(RARCH_CMD_OVERLAY_NEXT); if (!g_extern.is_paused) { if (BIT64_GET(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY)) rarch_main_command(RARCH_CMD_FULLSCREEN_TOGGLE); } #ifdef HAVE_NETPLAY if (driver.netplay_data) { if (BIT64_GET(trigger_input, RARCH_NETPLAY_FLIP)) rarch_main_command(RARCH_CMD_NETPLAY_FLIP_PLAYERS); if (BIT64_GET(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY)) rarch_main_command(RARCH_CMD_FULLSCREEN_TOGGLE); return 0; } #endif if (check_pause_func(trigger_input)) rarch_main_command(RARCH_CMD_PAUSE_TOGGLE); if (g_extern.is_paused) { if (BIT64_GET(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY)) { rarch_main_command(RARCH_CMD_FULLSCREEN_TOGGLE); rarch_render_cached_frame(); } if (!check_oneshot_func(trigger_input)) return 1; } check_fast_forward_button_func(input, old_input, trigger_input); check_stateslots_func(trigger_input); if (BIT64_GET(trigger_input, RARCH_SAVE_STATE_KEY)) rarch_main_command(RARCH_CMD_SAVE_STATE); else if (BIT64_GET(trigger_input, RARCH_LOAD_STATE_KEY)) rarch_main_command(RARCH_CMD_LOAD_STATE); check_rewind_func(input); check_slowmotion_func(input); if (BIT64_GET(trigger_input, RARCH_MOVIE_RECORD_TOGGLE)) check_movie(); check_shader_dir_func(trigger_input); if (BIT64_GET(trigger_input, RARCH_CHEAT_INDEX_PLUS)) cheat_manager_index_next(g_extern.cheat); else if (BIT64_GET(trigger_input, RARCH_CHEAT_INDEX_MINUS)) cheat_manager_index_prev(g_extern.cheat); else if (BIT64_GET(trigger_input, RARCH_CHEAT_TOGGLE)) cheat_manager_toggle(g_extern.cheat); if (BIT64_GET(trigger_input, RARCH_DISK_EJECT_TOGGLE)) rarch_main_command(RARCH_CMD_DISK_EJECT_TOGGLE); else if (BIT64_GET(trigger_input, RARCH_DISK_NEXT)) rarch_main_command(RARCH_CMD_DISK_NEXT); else if (BIT64_GET(trigger_input, RARCH_DISK_PREV)) rarch_main_command(RARCH_CMD_DISK_PREV); if (BIT64_GET(trigger_input, RARCH_RESET)) rarch_main_command(RARCH_CMD_RESET); return 0; }
static int menu_action_ok(const char *menu_path, const char *menu_label, unsigned menu_type) { const char *label = NULL; const char *path = NULL; unsigned type = 0; rarch_setting_t *setting_data = (rarch_setting_t *)driver.menu->list_settings; rarch_setting_t *setting = (rarch_setting_t*) setting_data_find_setting(setting_data, menu_label); (void)hack_shader_pass; if (file_list_get_size(driver.menu->selection_buf) == 0) return 0; file_list_get_at_offset(driver.menu->selection_buf, driver.menu->selection_ptr, &path, &label, &type); #if 0 RARCH_LOG("menu label: %s\n", menu_label); RARCH_LOG("type : %d\n", type == MENU_FILE_USE_DIRECTORY); RARCH_LOG("type id : %d\n", type); #endif while (true) { switch (type) { case MENU_FILE_PLAYLIST_ENTRY: rarch_playlist_load_content(g_defaults.history, driver.menu->selection_ptr); menu_flush_stack_type(driver.menu->menu_stack, MENU_SETTINGS); return -1; #ifdef HAVE_COMPRESSION case MENU_FILE_IN_CARCHIVE: #endif case MENU_FILE_PLAIN: if (!strcmp(menu_label, "detect_core_list")) { int ret = rarch_defer_core(g_extern.core_info, menu_path, path, driver.menu->deferred_path, sizeof(driver.menu->deferred_path)); if (ret == -1) { rarch_main_command(RARCH_CMD_LOAD_CORE); menu_common_load_content(); return -1; } else if (ret == 0) menu_entries_push(driver.menu->menu_stack, g_settings.libretro_directory, "deferred_core_list", 0, driver.menu->selection_ptr); } else if ((setting && setting->type == ST_PATH)) { menu_action_setting_set_current_string_path(setting, menu_path, path); menu_entries_pop_stack(driver.menu->menu_stack, setting->name); } else if (!strcmp(menu_label, "disk_image_append")) { char image[PATH_MAX]; fill_pathname_join(image, menu_path, path, sizeof(image)); rarch_disk_control_append_image(image); rarch_main_command(RARCH_CMD_RESUME); menu_flush_stack_type(driver.menu->menu_stack,MENU_SETTINGS); return -1; } else { if (type == MENU_FILE_IN_CARCHIVE) { fill_pathname_join_delim(g_extern.fullpath, menu_path, path, '#',sizeof(g_extern.fullpath)); } else { fill_pathname_join(g_extern.fullpath, menu_path, path, sizeof(g_extern.fullpath)); } menu_common_load_content(); rarch_main_command(RARCH_CMD_LOAD_CONTENT_PERSIST); menu_flush_stack_type(driver.menu->menu_stack,MENU_SETTINGS); driver.menu->msg_force = true; return -1; } return 0; case MENU_FILE_CONFIG: { char config[PATH_MAX]; fill_pathname_join(config, menu_path, path, sizeof(config)); menu_flush_stack_type(driver.menu->menu_stack,MENU_SETTINGS); driver.menu->msg_force = true; if (rarch_replace_config(config)) { menu_clear_navigation(driver.menu); return -1; } } return 0; case MENU_FILE_FONT: case MENU_FILE_OVERLAY: case MENU_FILE_AUDIOFILTER: case MENU_FILE_VIDEOFILTER: menu_action_setting_set_current_string_path(setting, menu_path, path); menu_entries_pop_stack(driver.menu->menu_stack, setting->name); return 0; case MENU_FILE_SHADER_PRESET: #ifdef HAVE_SHADER_MANAGER { char shader_path[PATH_MAX]; fill_pathname_join(shader_path, menu_path, path, sizeof(shader_path)); menu_shader_manager_set_preset(driver.menu->shader, gfx_shader_parse_type(shader_path, RARCH_SHADER_NONE), shader_path); menu_flush_stack_label(driver.menu->menu_stack, "Shader Options"); } #endif return 0; case MENU_FILE_SHADER: #ifdef HAVE_SHADER_MANAGER fill_pathname_join(driver.menu->shader->pass[hack_shader_pass].source.path, menu_path, path, sizeof(driver.menu->shader->pass[hack_shader_pass].source.path)); /* This will reset any changed parameters. */ gfx_shader_resolve_parameters(NULL, driver.menu->shader); menu_flush_stack_label(driver.menu->menu_stack, "Shader Options"); #endif return 0; case MENU_FILE_CORE: if (!strcmp(menu_label, "deferred_core_list")) { strlcpy(g_settings.libretro, path, sizeof(g_settings.libretro)); strlcpy(g_extern.fullpath, driver.menu->deferred_path, sizeof(g_extern.fullpath)); menu_common_load_content(); return -1; } else if (!strcmp(menu_label, "core_list")) { fill_pathname_join(g_settings.libretro, menu_path, path, sizeof(g_settings.libretro)); rarch_main_command(RARCH_CMD_LOAD_CORE); menu_flush_stack_type(driver.menu->menu_stack,MENU_SETTINGS); #if defined(HAVE_DYNAMIC) /* No content needed for this core, load core immediately. */ if (driver.menu->load_no_content) { *g_extern.fullpath = '\0'; menu_common_load_content(); return -1; } /* Core selection on non-console just updates directory listing. * Will take effect on new content load. */ #elif defined(RARCH_CONSOLE) rarch_main_command(RARCH_CMD_RESTART_RETROARCH); return -1; #endif } return 0; case MENU_FILE_USE_DIRECTORY: if (setting && setting->type == ST_DIR) { menu_action_setting_set_current_string(setting, menu_path); menu_entries_pop_stack(driver.menu->menu_stack, setting->name); } return 0; case MENU_FILE_DIRECTORY: case MENU_FILE_CARCHIVE: { char cat_path[PATH_MAX]; if (type == MENU_FILE_CARCHIVE && !strcmp(menu_label, "detect_core_list")) { file_list_push(driver.menu->menu_stack, path, "load_open_zip", 0, driver.menu->selection_ptr); return 0; } fill_pathname_join(cat_path, menu_path, path, sizeof(cat_path)); menu_entries_push(driver.menu->menu_stack, cat_path, menu_label, type, driver.menu->selection_ptr); } return 0; } break; } if (menu_parse_check(label, type) == 0) { char cat_path[PATH_MAX]; fill_pathname_join(cat_path, menu_path, path, sizeof(cat_path)); menu_entries_push(driver.menu->menu_stack, cat_path, menu_label, type, driver.menu->selection_ptr); } return 0; }
static int menu_viewport_iterate(unsigned action) { int stride_x = 1, stride_y = 1; char msg[64]; struct retro_game_geometry *geom = NULL; const char *base_msg = NULL; const char *label = NULL; unsigned menu_type = 0; rarch_viewport_t *custom = (rarch_viewport_t*) &g_extern.console.screen.viewports.custom_vp; file_list_get_last(driver.menu->menu_stack, NULL, &label, &menu_type); geom = (struct retro_game_geometry*)&g_extern.system.av_info.geometry; if (g_settings.video.scale_integer) { stride_x = geom->base_width; stride_y = geom->base_height; } switch (action) { case MENU_ACTION_UP: if (menu_type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->y -= stride_y; custom->height += stride_y; } else if (custom->height >= (unsigned)stride_y) custom->height -= stride_y; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_DOWN: if (menu_type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->y += stride_y; if (custom->height >= (unsigned)stride_y) custom->height -= stride_y; } else custom->height += stride_y; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_LEFT: if (menu_type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->x -= stride_x; custom->width += stride_x; } else if (custom->width >= (unsigned)stride_x) custom->width -= stride_x; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_RIGHT: if (menu_type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->x += stride_x; if (custom->width >= (unsigned)stride_x) custom->width -= stride_x; } else custom->width += stride_x; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_CANCEL: menu_entries_pop(driver.menu->menu_stack); if (!strcmp(label, "custom_viewport_2")) { file_list_push(driver.menu->menu_stack, "", "", MENU_SETTINGS_CUSTOM_VIEWPORT, driver.menu->selection_ptr); } break; case MENU_ACTION_OK: menu_entries_pop(driver.menu->menu_stack); if (menu_type == MENU_SETTINGS_CUSTOM_VIEWPORT && !g_settings.video.scale_integer) { file_list_push(driver.menu->menu_stack, "", "custom_viewport_2", 0, driver.menu->selection_ptr); } break; case MENU_ACTION_START: if (!g_settings.video.scale_integer) { rarch_viewport_t vp; if (driver.video_data && driver.video && driver.video->viewport_info) driver.video->viewport_info(driver.video_data, &vp); if (menu_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; } rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); } break; case MENU_ACTION_MESSAGE: driver.menu->msg_force = true; break; default: break; } file_list_get_last(driver.menu->menu_stack, NULL, &label, &menu_type); if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render) driver.menu_ctx->render(); if (g_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(msg, sizeof(msg), "%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 (menu_type == MENU_SETTINGS_CUSTOM_VIEWPORT) base_msg = "Set Upper-Left Corner"; else if (!strcmp(label, "custom_viewport_2")) base_msg = "Set Bottom-Right Corner"; snprintf(msg, sizeof(msg), "%s (%d, %d : %4ux%4u)", base_msg, custom->x, custom->y, custom->width, custom->height); } if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render_messagebox) driver.menu_ctx->render_messagebox(msg); 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; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); return 0; }
static void menu_common_load_content(void) { rarch_main_command(RARCH_CMD_LOAD_CONTENT); menu_flush_stack_type(driver.menu->menu_stack,MENU_SETTINGS); driver.menu->msg_force = true; }
void cmd_take_screenshot(void) { rarch_main_command(RARCH_CMD_TAKE_SCREENSHOT); }
static int menu_setting_ok_toggle(unsigned type, const char *dir, const char *label, unsigned action) { if (type == MENU_SETTINGS_CUSTOM_BIND_ALL) { driver.menu->binds.target = &g_settings.input.binds [driver.menu->current_pad][0]; driver.menu->binds.begin = MENU_SETTINGS_BIND_BEGIN; driver.menu->binds.last = MENU_SETTINGS_BIND_LAST; file_list_push(driver.menu->menu_stack, "", "", driver.menu->bind_mode_keyboard ? MENU_SETTINGS_CUSTOM_BIND_KEYBOARD : MENU_SETTINGS_CUSTOM_BIND, driver.menu->selection_ptr); if (driver.menu->bind_mode_keyboard) { driver.menu->binds.timeout_end = rarch_get_time_usec() + MENU_KEYBOARD_BIND_TIMEOUT_SECONDS * 1000000; input_keyboard_wait_keys(driver.menu, menu_custom_bind_keyboard_cb); } else { menu_poll_bind_get_rested_axes(&driver.menu->binds); menu_poll_bind_state(&driver.menu->binds); } return 0; } #ifdef HAVE_SHADER_MANAGER else if (!strcmp(label, "video_shader_preset_save_as")) { if (action == MENU_ACTION_OK) menu_key_start_line(driver.menu, "Preset Filename", label, st_string_callback); } else if (!strcmp(label, "shader_apply_changes")) { rarch_main_command(RARCH_CMD_SHADERS_APPLY_CHANGES); return 0; } #endif else if (type == MENU_SETTINGS_CUSTOM_BIND_DEFAULT_ALL) { unsigned i; struct retro_keybind *target = (struct retro_keybind*) &g_settings.input.binds[driver.menu->current_pad][0]; const struct retro_keybind *def_binds = driver.menu->current_pad ? retro_keybinds_rest : retro_keybinds_1; driver.menu->binds.begin = MENU_SETTINGS_BIND_BEGIN; driver.menu->binds.last = MENU_SETTINGS_BIND_LAST; for (i = MENU_SETTINGS_BIND_BEGIN; i <= MENU_SETTINGS_BIND_LAST; i++, target++) { if (driver.menu->bind_mode_keyboard) target->key = def_binds[i - MENU_SETTINGS_BIND_BEGIN].key; else { target->joykey = NO_BTN; target->joyaxis = AXIS_NONE; } } return 0; } else if (type >= MENU_SETTINGS_BIND_BEGIN && type <= MENU_SETTINGS_BIND_ALL_LAST) { struct retro_keybind *bind = (struct retro_keybind*) &g_settings.input.binds[driver.menu->current_pad] [type - MENU_SETTINGS_BIND_BEGIN]; driver.menu->binds.begin = type; driver.menu->binds.last = type; driver.menu->binds.target = bind; driver.menu->binds.player = driver.menu->current_pad; file_list_push(driver.menu->menu_stack, "", "", driver.menu->bind_mode_keyboard ? MENU_SETTINGS_CUSTOM_BIND_KEYBOARD : MENU_SETTINGS_CUSTOM_BIND, driver.menu->selection_ptr); if (driver.menu->bind_mode_keyboard) { driver.menu->binds.timeout_end = rarch_get_time_usec() + MENU_KEYBOARD_BIND_TIMEOUT_SECONDS * 1000000; input_keyboard_wait_keys(driver.menu, menu_custom_bind_keyboard_cb); } else { menu_poll_bind_get_rested_axes(&driver.menu->binds); menu_poll_bind_state(&driver.menu->binds); } return 0; } else if ( !strcmp(label, "load_content") || !strcmp(label, "detect_core_list") ) { menu_entries_push(driver.menu->menu_stack, g_settings.menu_content_directory, label, MENU_FILE_DIRECTORY, driver.menu->selection_ptr); return 0; } else if (!strcmp(label, "history_list") || menu_common_type_is(label, type) == MENU_FILE_DIRECTORY ) { menu_entries_push(driver.menu->menu_stack, "", label, type, driver.menu->selection_ptr); return 0; } else if ( menu_common_type_is(label, type) == MENU_SETTINGS || !strcmp(label, "core_list") || !strcmp(label, "configurations") || !strcmp(label, "disk_image_append") ) { menu_entries_push(driver.menu->menu_stack, dir ? dir : label, label, type, driver.menu->selection_ptr); return 0; } else if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { file_list_push(driver.menu->menu_stack, "", "", MENU_SETTINGS_CUSTOM_VIEWPORT, driver.menu->selection_ptr); /* Start with something sane. */ rarch_viewport_t *custom = (rarch_viewport_t*) &g_extern.console.screen.viewports.custom_vp; if (driver.video_data && driver.video && driver.video->viewport_info) driver.video->viewport_info(driver.video_data, custom); aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (float)custom->width / custom->height; g_settings.video.aspect_ratio_idx = ASPECT_RATIO_CUSTOM; rarch_main_command(RARCH_CMD_VIDEO_SET_ASPECT_RATIO); return 0; } return -1; }
void cmd_load_state(void) { rarch_main_command(RARCH_CMD_LOAD_STATE); }
void cmd_save_state(void) { rarch_main_command(RARCH_CMD_SAVE_STATE); }
void cmd_savefiles(void) { rarch_main_command(RARCH_CMD_SAVEFILES); }
void init_video_input(void) { unsigned max_dim, scale, width, height; const input_driver_t *tmp = NULL; const struct retro_game_geometry *geom = NULL; rarch_init_filter(g_extern.system.pix_fmt); init_shader_dir(); geom = (const struct retro_game_geometry*)&g_extern.system.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 (g_extern.filter.filter) scale = g_extern.filter.scale; // Update core-dependent aspect ratio values. gfx_set_square_pixel_viewport(geom->base_width, geom->base_height); gfx_set_core_viewport(); gfx_set_config_viewport(); // Update CUSTOM viewport. rarch_viewport_t *custom_vp = &g_extern.console.screen.viewports.custom_vp; if (g_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; } g_extern.system.aspect_ratio = aspectratio_lut[g_settings.video.aspect_ratio_idx].value; if (g_settings.video.fullscreen) { width = g_settings.video.fullscreen_x; height = g_settings.video.fullscreen_y; } else { if (g_settings.video.force_aspect) { // Do rounding here to simplify integer scale correctness. unsigned base_width = roundf(geom->base_height * g_extern.system.aspect_ratio); width = roundf(base_width * g_settings.video.scale); height = roundf(geom->base_height * g_settings.video.scale); } else { width = roundf(geom->base_width * g_settings.video.scale); height = roundf(geom->base_height * g_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_input()"); } video_info_t video = {0}; video.width = width; video.height = height; video.fullscreen = g_settings.video.fullscreen; video.vsync = g_settings.video.vsync && !g_extern.system.force_nonblock; video.force_aspect = g_settings.video.force_aspect; #ifdef GEKKO video.viwidth = g_settings.video.viwidth; #endif video.smooth = g_settings.video.smooth; video.input_scale = scale; video.rgb32 = g_extern.filter.filter ? g_extern.filter.out_rgb32 : (g_extern.system.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888); tmp = (const input_driver_t*)driver.input; find_video_driver(); // Need to grab the "real" video driver interface on a reinit. #ifdef HAVE_THREADS if (g_settings.video.threaded && !g_extern.system.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_input()"); } } 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_input()"); } driver.video_poke = NULL; if (driver.video->poke_interface) driver.video->poke_interface(driver.video_data, &driver.video_poke); // Force custom viewport to have sane parameters. if (driver.video->viewport_info && (!custom_vp->width || !custom_vp->height)) { custom_vp->width = width; custom_vp->height = height; driver.video->viewport_info(driver.video_data, custom_vp); } if (driver.video->set_rotation) driver.video->set_rotation(driver.video_data, (g_settings.video.rotation + g_extern.system.rotation) % 4); #ifdef HAVE_X11 if (driver.display_type == RARCH_DISPLAY_X11) { RARCH_LOG("Suspending screensaver (X11).\n"); x11_suspend_screensaver(driver.video_window); } #endif // Video driver didn't provide an input driver so we use configured one. if (!driver.input) { RARCH_LOG("Graphics driver did not initialize an input driver. Attempting to pick a suitable driver.\n"); if (tmp) driver.input = tmp; else find_input_driver(); if (driver.input) { driver.input_data = driver.input->init(); if (!driver.input_data) { RARCH_ERR("Cannot initialize input driver. Exiting ...\n"); rarch_fail(1, "init_video_input()"); } } else { // This should never really happen as tmp (driver.input) is always found before this in find_driver_input(), // or we have aborted in a similar fashion anyways. rarch_fail(1, "init_video_input()"); } } rarch_main_command(RARCH_CMD_OVERLAY_DEINIT); rarch_main_command(RARCH_CMD_OVERLAY_INIT); g_extern.measure_data.frame_time_samples_count = 0; }
static int menu_load_or_open_zip_iterate(unsigned action) { char msg[PATH_MAX]; snprintf(msg, sizeof(msg), "Opening compressed file\n" " \n" " - OK to open as Folder\n" " - Cancel/Back to Load \n"); if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render_messagebox) { if (*msg && msg[0] != '\0') driver.menu_ctx->render_messagebox(msg); } if (action == MENU_ACTION_OK) { char cat_path[PATH_MAX]; const char *menu_path = NULL; const char *menu_label = NULL; const char* path = NULL; const char* label = NULL; unsigned int menu_type = 0, type = 0; menu_entries_pop(driver.menu->menu_stack); file_list_get_last(driver.menu->menu_stack, &menu_path, &menu_label, &menu_type); if (file_list_get_size(driver.menu->selection_buf) == 0) return 0; file_list_get_at_offset(driver.menu->selection_buf, driver.menu->selection_ptr, &path, &label, &type); fill_pathname_join(cat_path, menu_path, path, sizeof(cat_path)); menu_entries_push(driver.menu->menu_stack, cat_path, menu_label, type, driver.menu->selection_ptr); } else if (action == MENU_ACTION_CANCEL) { const char *menu_path = NULL; const char *menu_label = NULL; const char* path = NULL; const char* label = NULL; unsigned int menu_type = 0, type = 0; menu_entries_pop(driver.menu->menu_stack); file_list_get_last(driver.menu->menu_stack, &menu_path, &menu_label, &menu_type); if (file_list_get_size(driver.menu->selection_buf) == 0) return 0; file_list_get_at_offset(driver.menu->selection_buf, driver.menu->selection_ptr, &path, &label, &type); int ret = rarch_defer_core(g_extern.core_info, menu_path, path, driver.menu->deferred_path, sizeof(driver.menu->deferred_path)); if (ret == -1) { rarch_main_command(RARCH_CMD_LOAD_CORE); menu_common_load_content(); return -1; } else if (ret == 0) menu_entries_push(driver.menu->menu_stack, g_settings.libretro_directory, "deferred_core_list", 0, driver.menu->selection_ptr); } return 0; }
bool load_menu_content(void) { if (*g_extern.fullpath || (driver.menu && driver.menu->load_no_content)) { if (*g_extern.fullpath) { char tmp[PATH_MAX]; char str[PATH_MAX]; fill_pathname_base(tmp, g_extern.fullpath, sizeof(tmp)); snprintf(str, sizeof(str), "INFO - Loading %s ...", tmp); msg_queue_push(g_extern.msg_queue, str, 1, 1); } content_playlist_push(g_extern.history, g_extern.fullpath, g_settings.libretro, g_extern.menu.info.library_name); } /* redraw menu frame */ if (driver.menu) { driver.menu->old_input_state = driver.menu->trigger_state = 0; driver.menu->do_held = false; driver.menu->msg_force = true; } if (driver.menu_ctx && driver.menu_ctx->backend && driver.menu_ctx->backend->iterate) driver.menu_ctx->backend->iterate(MENU_ACTION_NOOP); draw_frame(true); draw_frame(false); if (!(main_load_content(0, NULL, NULL, menu_environment_get, driver.frontend_ctx->process_args))) { char name[PATH_MAX], msg[PATH_MAX]; fill_pathname_base(name, g_extern.fullpath, sizeof(name)); snprintf(msg, sizeof(msg), "Failed to load %s.\n", name); msg_queue_push(g_extern.msg_queue, msg, 1, 90); if (driver.menu) driver.menu->msg_force = true; return false; } if (driver.menu) update_libretro_info(&g_extern.menu.info); rarch_main_command(RARCH_CMD_HISTORY_DEINIT); rarch_main_command(RARCH_CMD_HISTORY_INIT); menu_shader_manager_init(driver.menu); rarch_main_command(RARCH_CMD_VIDEO_SET_ASPECT_RATIO); rarch_main_command(RARCH_CMD_RESUME); return true; }
static void process_pending_intent(void *data) { RARCH_LOG("process_pending_intent.\n"); JNIEnv *env; struct android_app* android_app = (struct android_app*)data; jstring jstr = NULL; bool startgame = false; if (!android_app) return; env = jni_thread_getenv(); if (!env) return; // ROM jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentFullPath); JNI_EXCEPTION(env); RARCH_LOG("Checking arguments passed from intent ...\n"); if (android_app->getPendingIntentFullPath && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(g_extern.fullpath, argv, sizeof(g_extern.fullpath)); (*env)->ReleaseStringUTFChars(env, jstr, argv); startgame = true; RARCH_LOG("ROM Filename: [%s].\n", g_extern.fullpath); } // Config file jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentConfigPath); JNI_EXCEPTION(env); if (android_app->getPendingIntentConfigPath && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(g_defaults.config_path, argv, sizeof(g_defaults.config_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Config file: [%s].\n", g_extern.config_path); } // Current IME jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentIME); JNI_EXCEPTION(env); if (android_app->getPendingIntentIME && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(android_app->current_ime, argv, sizeof(android_app->current_ime)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); } //LIBRETRO jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentLibretroPath); JNI_EXCEPTION(env); if (android_app->getPendingIntentLibretroPath && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(g_defaults.core_path, argv, sizeof(g_defaults.core_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); } RARCH_LOG("Libretro path: [%s].\n", g_defaults.core_path); if (startgame) { g_extern.lifecycle_state &= ~(1ULL << MODE_MENU_PREINIT); g_extern.lifecycle_state &= ~(1ULL << MODE_GAME); rarch_main_command(RARCH_CMD_LOAD_CONTENT); } CALL_VOID_METHOD(env, android_app->activity->clazz, android_app->clearPendingIntent); }