diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index ffbe6f84bc..bde722a3fe 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -2940,6 +2940,10 @@ MSG_HASH( MENU_ENUM_LABEL_SLOWMOTION_RATIO, "slowmotion_ratio" ) +MSG_HASH( + MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED, + "run_ahead_unsupported" + ) MSG_HASH( MENU_ENUM_LABEL_RUN_AHEAD_ENABLED, "run_ahead_enabled" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 302ec1899a..f5db9d99d8 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3056,6 +3056,14 @@ MSG_HASH( /* Settings > Latency */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RUN_AHEAD_UNSUPPORTED, + "[Run-Ahead Unavailable]" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RUN_AHEAD_UNSUPPORTED, + "Current core is incompatible with run-ahead due to lack of deterministic save state support." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RUN_AHEAD_ENABLED, "Run-Ahead to Reduce Latency" @@ -11862,6 +11870,10 @@ MSG_HASH( MSG_REWINDING, "Rewinding." ) +MSG_HASH( + MSG_REWIND_UNSUPPORTED, + "Rewind unavailable because this core lacks serialized save state support." + ) MSG_HASH( MSG_REWIND_INIT, "Initializing rewind buffer with size" @@ -12170,6 +12182,10 @@ MSG_HASH( MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, "Run-Ahead has been disabled because this core does not support save states." ) +MSG_HASH( + MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_RUNAHEAD, + "Run-Ahead unavailable because this core lacks deterministic save state support." + ) MSG_HASH( MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, "Failed to save state. Run-Ahead has been disabled." diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index ff44c33f98..e4e32cbd22 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -497,6 +497,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_fastforward_ratio, MENU_ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_fastforward_frameskip, MENU_ENUM_SUBLABEL_FASTFORWARD_FRAMESKIP) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_vrr_runloop_enable, MENU_ENUM_SUBLABEL_VRR_RUNLOOP_ENABLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_slowmotion_ratio, MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_unsupported, MENU_ENUM_SUBLABEL_RUN_AHEAD_UNSUPPORTED) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_enabled, MENU_ENUM_SUBLABEL_RUN_AHEAD_ENABLED) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_secondary_instance, MENU_ENUM_SUBLABEL_RUN_AHEAD_SECONDARY_INSTANCE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_hide_warnings, MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS) @@ -3392,6 +3393,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_SLOWMOTION_RATIO: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_slowmotion_ratio); break; + case MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_run_ahead_unsupported); + break; case MENU_ENUM_LABEL_RUN_AHEAD_ENABLED: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_run_ahead_enabled); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index de4b740d11..b4758bb82a 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -3112,7 +3112,9 @@ static int menu_displaylist_parse_load_content_settings( #endif #ifdef HAVE_REWIND - if (settings->bools.menu_show_rewind && !settings->bools.kiosk_mode_enable) + if (settings->bools.menu_show_rewind && + !settings->bools.kiosk_mode_enable && + core_info_current_supports_rewind()) { if (menu_entries_append_enum(list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS), @@ -8485,6 +8487,10 @@ unsigned menu_displaylist_build_list( case DISPLAYLIST_LATENCY_SETTINGS_LIST: { bool video_hard_sync = settings->bools.video_hard_sync; +#ifdef HAVE_RUNAHEAD + bool runahead_supported = true; + bool runahead_enabled = settings->bools.run_ahead_enabled; +#endif menu_displaylist_build_info_selective_t build_list[] = { {MENU_ENUM_LABEL_VIDEO_FRAME_DELAY, PARSE_ONLY_UINT, true }, {MENU_ENUM_LABEL_VIDEO_FRAME_DELAY_AUTO, PARSE_ONLY_BOOL, true }, @@ -8492,7 +8498,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR, PARSE_ONLY_UINT, true }, {MENU_ENUM_LABEL_INPUT_BLOCK_TIMEOUT, PARSE_ONLY_UINT, true }, #ifdef HAVE_RUNAHEAD - {MENU_ENUM_LABEL_RUN_AHEAD_ENABLED, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_RUN_AHEAD_ENABLED, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_RUN_AHEAD_FRAMES, PARSE_ONLY_UINT, false }, {MENU_ENUM_LABEL_RUN_AHEAD_SECONDARY_INSTANCE, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS, PARSE_ONLY_BOOL, false }, @@ -8506,6 +8512,7 @@ unsigned menu_displaylist_build_list( PARSE_ONLY_UINT, false); count++; } + if (video_driver_test_all_flags(GFX_CTX_FLAGS_HARD_SYNC)) { MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, @@ -8521,26 +8528,32 @@ unsigned menu_displaylist_build_list( } } +#ifdef HAVE_RUNAHEAD + if (retroarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL) && + !retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) + runahead_supported = core_info_current_supports_runahead(); + + if (runahead_supported) { - bool runahead_enabled = settings->bools.run_ahead_enabled; - if (runahead_enabled) + for (i = 0; i < ARRAY_SIZE(build_list); i++) { - for (i = 0; i < ARRAY_SIZE(build_list); i++) + switch (build_list[i].enum_idx) { - switch (build_list[i].enum_idx) - { - case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES: - case MENU_ENUM_LABEL_RUN_AHEAD_SECONDARY_INSTANCE: - case MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS: + case MENU_ENUM_LABEL_RUN_AHEAD_ENABLED: + build_list[i].checked = true; + break; + case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES: + case MENU_ENUM_LABEL_RUN_AHEAD_SECONDARY_INSTANCE: + case MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS: + if (runahead_enabled) build_list[i].checked = true; - break; - default: - break; - } + break; + default: + break; } } } - +#endif for (i = 0; i < ARRAY_SIZE(build_list); i++) { if (!build_list[i].checked && !include_everything) @@ -8552,6 +8565,15 @@ unsigned menu_displaylist_build_list( count++; } +#ifdef HAVE_RUNAHEAD + if (!runahead_supported && + menu_entries_append_enum(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_UNSUPPORTED), + msg_hash_to_str(MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED), + MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED, + FILE_TYPE_NONE, 0, 0)) + count++; +#endif if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, MENU_ENUM_LABEL_GAMEMODE_ENABLE, PARSE_ONLY_BOOL, false) == 0) count++; @@ -9423,20 +9445,44 @@ unsigned menu_displaylist_build_list( break; case DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST: { - menu_displaylist_build_info_t build_list[] = { #ifdef HAVE_REWIND - {MENU_ENUM_LABEL_REWIND_SETTINGS, PARSE_ACTION }, + bool rewind_supported = true; #endif - {MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, PARSE_ACTION}, - {MENU_ENUM_LABEL_FASTFORWARD_RATIO, PARSE_ONLY_FLOAT}, - {MENU_ENUM_LABEL_FASTFORWARD_FRAMESKIP, PARSE_ONLY_BOOL }, - {MENU_ENUM_LABEL_SLOWMOTION_RATIO, PARSE_ONLY_FLOAT}, - {MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE, PARSE_ONLY_BOOL }, - {MENU_ENUM_LABEL_MENU_THROTTLE_FRAMERATE, PARSE_ONLY_BOOL }, + menu_displaylist_build_info_selective_t build_list[] = { +#ifdef HAVE_REWIND + {MENU_ENUM_LABEL_REWIND_SETTINGS, PARSE_ACTION, false}, +#endif + {MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, PARSE_ACTION, true}, + {MENU_ENUM_LABEL_FASTFORWARD_RATIO, PARSE_ONLY_FLOAT, true}, + {MENU_ENUM_LABEL_FASTFORWARD_FRAMESKIP, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_SLOWMOTION_RATIO, PARSE_ONLY_FLOAT, true}, + {MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_MENU_THROTTLE_FRAMERATE, PARSE_ONLY_BOOL , true}, }; +#ifdef HAVE_REWIND + if (retroarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL) && + !retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)) + rewind_supported = core_info_current_supports_rewind(); + + if (rewind_supported) + for (i = 0; i < ARRAY_SIZE(build_list); i++) + { + switch (build_list[i].enum_idx) + { + case MENU_ENUM_LABEL_REWIND_SETTINGS: + build_list[i].checked = true; + break; + default: + break; + } + } +#endif for (i = 0; i < ARRAY_SIZE(build_list); i++) { + if (!build_list[i].checked && !include_everything) + continue; + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, build_list[i].enum_idx, build_list[i].parse_type, false) == 0) diff --git a/msg_hash.h b/msg_hash.h index 14964ebdbf..ab371f5a31 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -374,6 +374,7 @@ enum msg_hash_enums MSG_DECOMPRESSION_FAILED, MSG_DISK_EJECTED, MSG_DISK_CLOSED, + MSG_REWIND_UNSUPPORTED, MSG_REWIND_INIT, MSG_REWIND_INIT_FAILED, MSG_REWIND_INIT_FAILED_THREADED_AUDIO, @@ -488,6 +489,7 @@ enum msg_hash_enums MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE, MSG_RUNAHEAD_DISABLED, MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_SAVESTATES, + MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_RUNAHEAD, MSG_RUNAHEAD_FAILED_TO_SAVE_STATE, MSG_RUNAHEAD_FAILED_TO_LOAD_STATE, MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE, @@ -2050,6 +2052,7 @@ enum msg_hash_enums MENU_LABEL(THUMBNAILS_DIRECTORY), MENU_LABEL(SLOWMOTION_RATIO), + MENU_LABEL(RUN_AHEAD_UNSUPPORTED), MENU_LABEL(RUN_AHEAD_ENABLED), MENU_LABEL(RUN_AHEAD_SECONDARY_INSTANCE), MENU_LABEL(RUN_AHEAD_HIDE_WARNINGS), diff --git a/retroarch.c b/retroarch.c index a8e05539bb..dcc5e64777 100644 --- a/retroarch.c +++ b/retroarch.c @@ -1623,6 +1623,14 @@ bool command_event(enum event_command cmd, void *data) char msg[256]; msg[0] = '\0'; + if (!core_info_current_supports_runahead()) + { + runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_RUNAHEAD), + 1, 100, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + break; + } + settings->bools.run_ahead_enabled = !(settings->bools.run_ahead_enabled); @@ -2007,9 +2015,11 @@ bool command_event(enum event_command cmd, void *data) case CMD_EVENT_REWIND_DEINIT: #ifdef HAVE_REWIND { - bool core_type_is_dummy = runloop_st->current_core_type == CORE_TYPE_DUMMY; - if (core_type_is_dummy) + bool core_type_is_dummy = runloop_st->current_core_type == CORE_TYPE_DUMMY; + + if (core_type_is_dummy) return false; + state_manager_event_deinit(&runloop_st->rewind_st); } #endif @@ -2019,8 +2029,9 @@ bool command_event(enum event_command cmd, void *data) { bool rewind_enable = settings->bools.rewind_enable; size_t rewind_buf_size = settings->sizes.rewind_buffer_size; - bool core_type_is_dummy = runloop_st->current_core_type == CORE_TYPE_DUMMY; - if (core_type_is_dummy) + bool core_type_is_dummy = runloop_st->current_core_type == CORE_TYPE_DUMMY; + + if (core_type_is_dummy) return false; #ifdef HAVE_CHEEVOS if (rcheevos_hardcore_active()) diff --git a/runloop.c b/runloop.c index 02f29d9384..d9f8c42b86 100644 --- a/runloop.c +++ b/runloop.c @@ -4727,6 +4727,26 @@ static void do_runahead( if (!runloop_st->runahead_save_state_size_known) { + /* Disable runahead if current core reports + * that it has an insufficient savestate + * support level */ + if (!core_info_current_supports_runahead()) + { + runahead_error(runloop_st); + /* If core is incompatible with runahead, + * log a warning but do not spam OSD messages. + * Runahead menu entries are hidden when using + * incompatible cores, so there is no mechanism + * for users to respond to notifications. In + * addition, auto-disabling runahead is a feature, + * not a cause for 'concern'; OSD warnings should + * be reserved for when a core reports that it is + * runahead-compatible but subsequently fails in + * execution */ + RARCH_WARN("[Run-Ahead]: %s\n", msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_RUNAHEAD)); + goto force_input_dirty; + } + if (!runahead_create(runloop_st)) { if (!runahead_hide_warnings) @@ -7650,7 +7670,8 @@ int runloop_iterate(void) bool run_ahead_hide_warnings = settings->bools.run_ahead_hide_warnings; bool run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance; /* Run Ahead Feature replaces the call to core_run in this loop */ - bool want_runahead = run_ahead_enabled && run_ahead_num_frames > 0; + bool want_runahead = run_ahead_enabled && + (run_ahead_num_frames > 0) && runloop_st->runahead_available; #ifdef HAVE_NETWORKING want_runahead = want_runahead && !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL); #endif @@ -8040,7 +8061,8 @@ bool core_set_cheat(retro_ctx_cheat_info_t *info) run_ahead_enabled = settings->bools.run_ahead_enabled; run_ahead_frames = settings->uints.run_ahead_frames; run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance; - want_runahead = run_ahead_enabled && (run_ahead_frames > 0); + want_runahead = run_ahead_enabled && + (run_ahead_frames > 0) && runloop_st->runahead_available; #ifdef HAVE_NETWORKING if (want_runahead) want_runahead = !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL); @@ -8078,7 +8100,8 @@ bool core_reset_cheat(void) run_ahead_enabled = settings->bools.run_ahead_enabled; run_ahead_frames = settings->uints.run_ahead_frames; run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance; - want_runahead = run_ahead_enabled && (run_ahead_frames > 0); + want_runahead = run_ahead_enabled && + (run_ahead_frames > 0) && runloop_st->runahead_available; #ifdef HAVE_NETWORKING if (want_runahead) want_runahead = !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL); diff --git a/state_manager.c b/state_manager.c index 844431d0aa..262a245913 100644 --- a/state_manager.c +++ b/state_manager.c @@ -30,6 +30,7 @@ #include "state_manager.h" #include "msg_hash.h" #include "core.h" +#include "core_info.h" #include "retroarch.h" #include "verbosity.h" #include "content.h" @@ -582,6 +583,12 @@ void state_manager_event_init( if (!rewind_st || rewind_st->state) return; + if (!core_info_current_supports_rewind()) + { + RARCH_ERR("%s\n", msg_hash_to_str(MSG_REWIND_UNSUPPORTED)); + return; + } + if (audio_driver_has_callback()) { RARCH_ERR("%s.\n", msg_hash_to_str(MSG_REWIND_INIT_FAILED)); @@ -641,10 +648,11 @@ bool state_manager_check_rewind( unsigned rewind_granularity, bool is_paused, char *s, size_t len, unsigned *time) { - bool ret = false; - static bool first = true; + bool ret = false; + static bool first = true; + static bool was_pressed = false; #ifdef HAVE_NETWORKING - bool was_reversed = false; + bool was_reversed = false; #endif if (!rewind_st) @@ -666,7 +674,16 @@ bool state_manager_check_rewind( } if (!rewind_st->state) + { + if ((pressed && !was_pressed) && + !core_info_current_supports_rewind()) + runloop_msg_queue_push(msg_hash_to_str(MSG_REWIND_UNSUPPORTED), + 1, 100, false, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + + was_pressed = pressed; return false; + } if (pressed) { @@ -740,5 +757,6 @@ bool state_manager_check_rewind( core_set_rewind_callbacks(); + was_pressed = pressed; return ret; }