From b0146abd11609e142ff952be399342781dd48d4c Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 23:08:55 -0400 Subject: [PATCH 1/2] add fullpath and use_thread parameters to take_screenshot() --- cheevos/cheevos.c | 4 +- command.c | 2 +- tasks/task_save.c | 2 +- tasks/task_screenshot.c | 135 +++++++++++++++++++++++----------------- tasks/tasks_internal.h | 2 +- 5 files changed, 84 insertions(+), 61 deletions(-) diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index d65ed9ec32..0e21e3687a 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -1674,7 +1674,7 @@ static void cheevos_test_cheevo_set(const cheevoset_t *set) shotname[sizeof(shotname) - 1] = '\0'; if (take_screenshot(shotname, true, - video_driver_cached_frame_has_valid_framebuffer())) + video_driver_cached_frame_has_valid_framebuffer(), false, true)) CHEEVOS_LOG("[CHEEVOS]: got a screenshot for cheevo %u\n", cheevo->id); else CHEEVOS_LOG("[CHEEVOS]: failed to get screenshot for cheevo %u\n", cheevo->id); @@ -2080,7 +2080,7 @@ void cheevos_populate_menu(void *data) cheevo_t *cheevo = cheevos_locals.core.cheevos; end = cheevo + cheevos_locals.core.count; - if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable + if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable && cheevos_loaded) { if (!cheevos_hardcore_paused) diff --git a/command.c b/command.c index 55b2cf94e6..7cb6a22d37 100644 --- a/command.c +++ b/command.c @@ -1954,7 +1954,7 @@ bool command_event(enum event_command cmd, void *data) break; case CMD_EVENT_TAKE_SCREENSHOT: if (!take_screenshot(path_get(RARCH_PATH_BASENAME), false, - video_driver_cached_frame_has_valid_framebuffer())) + video_driver_cached_frame_has_valid_framebuffer(), false, true)) return false; break; case CMD_EVENT_UNLOAD_CORE: diff --git a/tasks/task_save.c b/tasks/task_save.c index 556da1fde0..1b5d93be4e 100644 --- a/tasks/task_save.c +++ b/tasks/task_save.c @@ -1010,7 +1010,7 @@ static void save_state_cb(void *task_data, char *path = strdup(state->path); if (state->thumbnail_enable) - take_screenshot(path, true, state->has_valid_framebuffer); + take_screenshot(path, true, state->has_valid_framebuffer, false, true); free(path); } diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 42cc5d8d72..80c3b90cee 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -70,39 +70,17 @@ struct screenshot_task_state uint8_t *out_buffer; const void *frame; char filename[PATH_MAX_LENGTH]; - char shotname[256]; void *userbuf; struct scaler_ctx scaler; }; -/** - * task_screenshot_handler: - * @task : the task being worked on - * - * Saves a screenshot to disk. - **/ -static void task_screenshot_handler(retro_task_t *task) +static bool screenshot_dump_direct(screenshot_task_state_t *state) { + struct scaler_ctx *scaler = (struct scaler_ctx*)&state->scaler; + bool ret = false; #ifdef HAVE_RBMP enum rbmp_source_type bmp_type = RBMP_SOURCE_TYPE_DONT_CARE; -#endif - screenshot_task_state_t *state = (screenshot_task_state_t*)task->state; - struct scaler_ctx *scaler = (struct scaler_ctx*)&state->scaler; - bool ret = false; - - if (task_get_progress(task) == 100) - { - task_set_finished(task, true); - - if (state->userbuf) - free(state->userbuf); - - free(state); - return; - } - -#ifdef HAVE_RBMP - (void)bmp_type; + (void)bmp_type; #endif #if defined(HAVE_RPNG) @@ -146,6 +124,33 @@ static void task_screenshot_handler(retro_task_t *task) bmp_type); #endif + return ret; +} + +/** + * task_screenshot_handler: + * @task : the task being worked on + * + * Saves a screenshot to disk. + **/ +static void task_screenshot_handler(retro_task_t *task) +{ + screenshot_task_state_t *state = (screenshot_task_state_t*)task->state; + bool ret = false; + + if (task_get_progress(task) == 100) + { + task_set_finished(task, true); + + if (state->userbuf) + free(state->userbuf); + + free(state); + return; + } + + ret = screenshot_dump_direct(state); + #ifdef HAVE_IMAGEVIEWER if ( ret && !state->silence && @@ -178,7 +183,9 @@ static bool screenshot_dump( int pitch, bool bgr24, void *userbuf, bool savestate, bool is_idle, - bool is_paused) + bool is_paused, + bool fullpath, + bool use_thread) { char screenshot_path[PATH_MAX_LENGTH]; uint8_t *buf = NULL; @@ -187,14 +194,22 @@ static bool screenshot_dump( screenshot_task_state_t *state = (screenshot_task_state_t*) calloc(1, sizeof(*state)); const char *screenshot_dir = settings->paths.directory_screenshot; + char shotname[256]; + shotname[0] = '\0'; screenshot_path[0] = '\0'; - if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) + /* If fullpath is true, name_base already contains a static path + filename to save the screenshot to. */ + if (fullpath) + strlcpy(state->filename, name_base, sizeof(state->filename)); + else { - fill_pathname_basedir(screenshot_path, name_base, - sizeof(screenshot_path)); - screenshot_dir = screenshot_path; + if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) + { + fill_pathname_basedir(screenshot_path, name_base, + sizeof(screenshot_path)); + screenshot_dir = screenshot_path; + } } state->is_idle = is_idle; @@ -209,20 +224,23 @@ static bool screenshot_dump( state->history_list_enable = settings->bools.history_list_enable; state->pixel_format_type = video_driver_get_pixel_format(); - if (savestate) - snprintf(state->filename, - sizeof(state->filename), "%s.png", name_base); - else + if (!fullpath) { - if (settings->bools.auto_screenshot_filename) - fill_str_dated_filename(state->shotname, path_basename(name_base), - IMG_EXT, sizeof(state->shotname)); + if (savestate) + snprintf(state->filename, + sizeof(state->filename), "%s.png", name_base); else - snprintf(state->shotname, sizeof(state->shotname), - "%s.png", path_basename(name_base)); + { + if (settings->bools.auto_screenshot_filename) + fill_str_dated_filename(shotname, path_basename(name_base), + IMG_EXT, sizeof(shotname)); + else + snprintf(shotname, sizeof(shotname), + "%s.png", path_basename(name_base)); - fill_pathname_join(state->filename, screenshot_dir, - state->shotname, sizeof(state->filename)); + fill_pathname_join(state->filename, screenshot_dir, + shotname, sizeof(state->filename)); + } } #if defined(HAVE_RPNG) @@ -241,17 +259,22 @@ static bool screenshot_dump( task->state = state; task->handler = task_screenshot_handler; - if (!savestate) - task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); + if (use_thread) + return screenshot_dump_direct(state); + else + { + if (!savestate) + task->title = strdup(msg_hash_to_str(MSG_TAKING_SCREENSHOT)); - task_queue_push(task); + task_queue_push(task); + } return true; } #if !defined(VITA) static bool take_screenshot_viewport(const char *name_base, bool savestate, - bool is_idle, bool is_paused) + bool is_idle, bool is_paused, bool fullpath, bool use_thread) { struct video_viewport vp; uint8_t *buffer = NULL; @@ -280,7 +303,7 @@ static bool take_screenshot_viewport(const char *name_base, bool savestate, /* Data read from viewport is in bottom-up order, suitable for BMP. */ if (!screenshot_dump(name_base, buffer, vp.width, vp.height, - vp.width * 3, true, buffer, savestate, is_idle, is_paused)) + vp.width * 3, true, buffer, savestate, is_idle, is_paused, fullpath, use_thread)) goto error; return true; @@ -293,7 +316,7 @@ error: #endif static bool take_screenshot_raw(const char *name_base, void *userbuf, - bool savestate, bool is_idle, bool is_paused) + bool savestate, bool is_idle, bool is_paused, bool fullpath, bool use_thread) { size_t pitch; unsigned width, height; @@ -306,14 +329,14 @@ static bool take_screenshot_raw(const char *name_base, void *userbuf, */ if (!screenshot_dump(name_base, (const uint8_t*)data + (height - 1) * pitch, - width, height, (int)(-pitch), false, userbuf, savestate, is_idle, is_paused)) + width, height, (int)(-pitch), false, userbuf, savestate, is_idle, is_paused, fullpath, use_thread)) return false; return true; } static bool take_screenshot_choice(const char *name_base, bool savestate, - bool is_paused, bool is_idle, bool has_valid_framebuffer) + bool is_paused, bool is_idle, bool has_valid_framebuffer, bool fullpath, bool use_thread) { size_t old_pitch; unsigned old_width, old_height; @@ -335,14 +358,14 @@ static bool take_screenshot_choice(const char *name_base, bool savestate, if (!is_idle) video_driver_cached_frame(); #if defined(VITA) - return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused); + return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused, fullpath, use_thread); #else - return take_screenshot_viewport(name_base, savestate, is_idle, is_paused); + return take_screenshot_viewport(name_base, savestate, is_idle, is_paused, fullpath, use_thread); #endif } if (!has_valid_framebuffer) - return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused); + return take_screenshot_raw(name_base, NULL, savestate, is_idle, is_paused, fullpath, use_thread); if (!video_driver_supports_read_frame_raw()) return false; @@ -359,14 +382,14 @@ static bool take_screenshot_choice(const char *name_base, bool savestate, if (frame_data) { video_driver_set_cached_frame_ptr(frame_data); - if (take_screenshot_raw(name_base, frame_data, savestate, is_idle, is_paused)) + if (take_screenshot_raw(name_base, frame_data, savestate, is_idle, is_paused, fullpath, use_thread)) ret = true; } return ret; } -bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebuffer) +bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebuffer, bool fullpath, bool use_thread) { bool is_paused = false; bool is_idle = false; @@ -377,7 +400,7 @@ bool take_screenshot(const char *name_base, bool silence, bool has_valid_framebu runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); ret = take_screenshot_choice(name_base, silence, is_paused, is_idle, - has_valid_framebuffer); + has_valid_framebuffer, fullpath, use_thread); if (is_paused && !is_idle) video_driver_cached_frame(); diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index fe9bd41122..a2632e4ac8 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -223,7 +223,7 @@ void task_file_load_handler(retro_task_t *task); bool task_audio_mixer_load_handler(retro_task_t *task); -bool take_screenshot(const char *path, bool silence, bool has_valid_framebuffer); +bool take_screenshot(const char *path, bool silence, bool has_valid_framebuffer, bool fullpath, bool use_thread); bool event_load_save_files(void); From b1dde87ce59d8bbbc045b6983e28ae386f362bad Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 18 Aug 2018 23:09:40 -0400 Subject: [PATCH 2/2] add --max-frames-ss and --max-frames-ss-path parameters for taking a screenshot after max_frames is reached --- retroarch.c | 246 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 145 insertions(+), 101 deletions(-) diff --git a/retroarch.c b/retroarch.c index de1298a024..42c8fa24b6 100644 --- a/retroarch.c +++ b/retroarch.c @@ -165,7 +165,9 @@ enum RA_OPT_VERSION, RA_OPT_EOF_EXIT, RA_OPT_LOG_FILE, - RA_OPT_MAX_FRAMES + RA_OPT_MAX_FRAMES, + RA_OPT_MAX_FRAMES_SCREENSHOT, + RA_OPT_MAX_FRAMES_SCREENSHOT_PATH }; enum runloop_state @@ -187,86 +189,88 @@ typedef struct runloop_ctx_msg_info } runloop_ctx_msg_info_t; static jmp_buf error_sjlj_context; -static enum rarch_core_type current_core_type = CORE_TYPE_PLAIN; -static enum rarch_core_type explicit_current_core_type = CORE_TYPE_PLAIN; -static char error_string[255] = {0}; +static enum rarch_core_type current_core_type = CORE_TYPE_PLAIN; +static enum rarch_core_type explicit_current_core_type = CORE_TYPE_PLAIN; +static char error_string[255] = {0}; static char runtime_shader_preset[255] = {0}; #ifdef HAVE_THREAD_STORAGE static sthread_tls_t rarch_tls; -const void *MAGIC_POINTER = (void*)(uintptr_t)0x0DEFACED; +const void *MAGIC_POINTER = (void*)(uintptr_t)0x0DEFACED; #endif static retro_bits_t has_set_libretro_device; -static bool has_set_core = false; -static bool has_set_username = false; +static bool has_set_core = false; +static bool has_set_username = false; #ifdef HAVE_DISCORD -static bool discord_is_inited = false; +static bool discord_is_inited = false; #endif -static bool rarch_is_inited = false; -static bool rarch_error_on_init = false; -static bool rarch_block_config_read = false; -static bool rarch_force_fullscreen = false; -static bool has_set_verbosity = false; -static bool has_set_libretro = false; -static bool has_set_libretro_directory = false; -static bool has_set_save_path = false; -static bool has_set_state_path = false; -static bool has_set_netplay_mode = false; -static bool has_set_netplay_ip_address = false; -static bool has_set_netplay_ip_port = false; -static bool has_set_netplay_stateless_mode = false; -static bool has_set_netplay_check_frames = false; -static bool has_set_ups_pref = false; -static bool has_set_bps_pref = false; -static bool has_set_ips_pref = false; +static bool rarch_is_inited = false; +static bool rarch_error_on_init = false; +static bool rarch_block_config_read = false; +static bool rarch_force_fullscreen = false; +static bool has_set_verbosity = false; +static bool has_set_libretro = false; +static bool has_set_libretro_directory = false; +static bool has_set_save_path = false; +static bool has_set_state_path = false; +static bool has_set_netplay_mode = false; +static bool has_set_netplay_ip_address = false; +static bool has_set_netplay_ip_port = false; +static bool has_set_netplay_stateless_mode = false; +static bool has_set_netplay_check_frames = false; +static bool has_set_ups_pref = false; +static bool has_set_bps_pref = false; +static bool has_set_ips_pref = false; -static bool rarch_is_sram_load_disabled = false; -static bool rarch_is_sram_save_disabled = false; -static bool rarch_use_sram = false; -static bool rarch_ups_pref = false; -static bool rarch_bps_pref = false; -static bool rarch_ips_pref = false; -static bool rarch_patch_blocked = false; -static bool rarch_first_start = true; +static bool rarch_is_sram_load_disabled = false; +static bool rarch_is_sram_save_disabled = false; +static bool rarch_use_sram = false; +static bool rarch_ups_pref = false; +static bool rarch_bps_pref = false; +static bool rarch_ips_pref = false; +static bool rarch_patch_blocked = false; +static bool rarch_first_start = true; -static bool runloop_force_nonblock = false; -static bool runloop_paused = false; -static bool runloop_idle = false; -static bool runloop_exec = false; -static bool runloop_slowmotion = false; -static bool runloop_fastmotion = 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_remaps_core_active = false; -static bool runloop_remaps_game_active = false; -static bool runloop_remaps_content_dir_active = false; -static bool runloop_game_options_active = false; -static bool runloop_missing_bios = false; -static bool runloop_autosave = false; +static bool runloop_force_nonblock = false; +static bool runloop_paused = false; +static bool runloop_idle = false; +static bool runloop_exec = false; +static bool runloop_slowmotion = false; +static bool runloop_fastmotion = 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_remaps_core_active = false; +static bool runloop_remaps_game_active = false; +static bool runloop_remaps_content_dir_active = false; +static bool runloop_game_options_active = false; +static bool runloop_missing_bios = false; +static bool runloop_autosave = false; #ifdef HAVE_DYNAMIC -static bool core_set_on_cmdline = false; +static bool core_set_on_cmdline = false; #endif static rarch_system_info_t runloop_system; static struct retro_frame_time_callback runloop_frame_time; -static retro_keyboard_event_t runloop_key_event = NULL; -static retro_keyboard_event_t runloop_frontend_key_event = NULL; -static core_option_manager_t *runloop_core_options = NULL; +static retro_keyboard_event_t runloop_key_event = NULL; +static retro_keyboard_event_t runloop_frontend_key_event = NULL; +static core_option_manager_t *runloop_core_options = NULL; #ifdef HAVE_THREADS -static slock_t *_runloop_msg_queue_lock = NULL; +static slock_t *_runloop_msg_queue_lock = NULL; #endif -static msg_queue_t *runloop_msg_queue = NULL; +static msg_queue_t *runloop_msg_queue = NULL; -static unsigned runloop_pending_windowed_scale = 0; -static unsigned runloop_max_frames = 0; -static unsigned fastforward_after_frames = 0; +static unsigned runloop_pending_windowed_scale = 0; +static unsigned runloop_max_frames = 0; +static bool runloop_max_frames_screenshot = false; +static char runloop_max_frames_screenshot_path[PATH_MAX_LENGTH] = {0}; +static unsigned fastforward_after_frames = 0; -static retro_usec_t runloop_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_usec_t runloop_frame_time_last = 0; +static retro_time_t frame_limit_minimum_time = 0.0; +static retro_time_t frame_limit_last_time = 0.0; extern bool input_driver_flushing_input; @@ -593,7 +597,11 @@ static void retroarch_print_help(const char *arg0) "Not relevant for all platforms."); puts(" --max-frames=NUMBER\n" " Runs for the specified number of frames, " - "then exits.\n"); + "then exits."); + puts(" --max-frames-ss\n" + " Takes a screenshot at the end of max-frames."); + puts(" --max-frames-ss-path=FILE\n" + " Path to save the screenshot to at the end of max-frames.\n"); } #define FFMPEG_RECORD_ARG "r:" @@ -629,48 +637,50 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) const struct option opts[] = { #ifdef HAVE_DYNAMIC - { "libretro", 1, NULL, 'L' }, + { "libretro", 1, NULL, 'L' }, #endif - { "menu", 0, NULL, RA_OPT_MENU }, - { "help", 0, NULL, 'h' }, - { "save", 1, NULL, 's' }, - { "fullscreen", 0, NULL, 'f' }, - { "record", 1, NULL, 'r' }, - { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, - { "size", 1, NULL, RA_OPT_SIZE }, - { "verbose", 0, NULL, 'v' }, - { "config", 1, NULL, 'c' }, - { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, - { "nodevice", 1, NULL, 'N' }, - { "dualanalog", 1, NULL, 'A' }, - { "device", 1, NULL, 'd' }, - { "savestate", 1, NULL, 'S' }, - { "bsvplay", 1, NULL, 'P' }, - { "bsvrecord", 1, NULL, 'R' }, - { "sram-mode", 1, NULL, 'M' }, + { "menu", 0, NULL, RA_OPT_MENU }, + { "help", 0, NULL, 'h' }, + { "save", 1, NULL, 's' }, + { "fullscreen", 0, NULL, 'f' }, + { "record", 1, NULL, 'r' }, + { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, + { "size", 1, NULL, RA_OPT_SIZE }, + { "verbose", 0, NULL, 'v' }, + { "config", 1, NULL, 'c' }, + { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, + { "nodevice", 1, NULL, 'N' }, + { "dualanalog", 1, NULL, 'A' }, + { "device", 1, NULL, 'd' }, + { "savestate", 1, NULL, 'S' }, + { "bsvplay", 1, NULL, 'P' }, + { "bsvrecord", 1, NULL, 'R' }, + { "sram-mode", 1, NULL, 'M' }, #ifdef HAVE_NETWORKING - { "host", 0, NULL, 'H' }, - { "connect", 1, NULL, 'C' }, - { "stateless", 0, NULL, RA_OPT_STATELESS }, - { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES }, - { "port", 1, NULL, RA_OPT_PORT }, + { "host", 0, NULL, 'H' }, + { "connect", 1, NULL, 'C' }, + { "stateless", 0, NULL, RA_OPT_STATELESS }, + { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES }, + { "port", 1, NULL, RA_OPT_PORT }, #if defined(HAVE_NETWORK_CMD) - { "command", 1, NULL, RA_OPT_COMMAND }, + { "command", 1, NULL, RA_OPT_COMMAND }, #endif #endif - { "nick", 1, NULL, RA_OPT_NICK }, - { "ups", 1, NULL, 'U' }, - { "bps", 1, NULL, RA_OPT_BPS }, - { "ips", 1, NULL, RA_OPT_IPS }, - { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, - { "detach", 0, NULL, 'D' }, - { "features", 0, NULL, RA_OPT_FEATURES }, - { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, - { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, - { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, - { "version", 0, NULL, RA_OPT_VERSION }, + { "nick", 1, NULL, RA_OPT_NICK }, + { "ups", 1, NULL, 'U' }, + { "bps", 1, NULL, RA_OPT_BPS }, + { "ips", 1, NULL, RA_OPT_IPS }, + { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, + { "detach", 0, NULL, 'D' }, + { "features", 0, NULL, RA_OPT_FEATURES }, + { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, + { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, + { "max-frames-ss", 0, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT }, + { "max-frames-ss-path", 1, NULL, RA_OPT_MAX_FRAMES_SCREENSHOT_PATH }, + { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, + { "version", 0, NULL, RA_OPT_VERSION }, #ifdef HAVE_FILE_LOGGER - { "log-file", 1, NULL, RA_OPT_LOG_FILE }, + { "log-file", 1, NULL, RA_OPT_LOG_FILE }, #endif { NULL, 0, NULL, 0 } }; @@ -1088,6 +1098,14 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) runloop_max_frames = (unsigned)strtoul(optarg, NULL, 10); break; + case RA_OPT_MAX_FRAMES_SCREENSHOT: + runloop_max_frames_screenshot = true; + break; + + case RA_OPT_MAX_FRAMES_SCREENSHOT_PATH: + strlcpy(runloop_max_frames_screenshot_path, optarg, sizeof(runloop_max_frames_screenshot_path)); + break; + case RA_OPT_SUBSYSTEM: path_set(RARCH_PATH_SUBSYSTEM, optarg); break; @@ -2631,6 +2649,32 @@ static enum runloop_state runloop_check_state( if (time_to_exit(trig_quit_key)) { + if ((runloop_max_frames != 0) && (frame_count >= runloop_max_frames)) + { + if (runloop_max_frames_screenshot) + { + const char *screenshot_path = NULL; + bool fullpath = false; + + if (string_is_empty(runloop_max_frames_screenshot_path)) + screenshot_path = path_get(RARCH_PATH_BASENAME); + else + { + fullpath = true; + screenshot_path = runloop_max_frames_screenshot_path; + } + + RARCH_LOG("Taking a screenshot before exiting...\n"); + + /* Take a screenshot before we exit. */ + if (!take_screenshot(screenshot_path, false, + video_driver_cached_frame_has_valid_framebuffer(), fullpath, false)) + { + RARCH_ERR("Could not take a screenshot before exiting.\n"); + } + } + } + if (runloop_exec) runloop_exec = false; @@ -2712,7 +2756,7 @@ static enum runloop_state runloop_check_state( } else { - if ( global->menu.prev_action == action && + if ( global->menu.prev_action == action && global->menu.noop_press_time < 200000) /* 250ms */ { global->menu.action_start_time = global->menu.prev_start_time ; @@ -3444,7 +3488,7 @@ int runloop_iterate(unsigned *sleep_ms) end: { retro_time_t to_sleep_ms; - + if (settings->bools.vrr_runloop_enable) { struct retro_system_av_info *av_info = @@ -3469,7 +3513,7 @@ int runloop_iterate(unsigned *sleep_ms) if (!settings->floats.fastforward_ratio && runloop_fastmotion) return 0; - frame_limit_minimum_time = + frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * (runloop_fastmotion ? settings->floats.fastforward_ratio : 1.0f))); }