mirror of
https://github.com/libretro/RetroArch
synced 2025-02-02 05:54:16 +00:00
Add Preemptive Frames to Latency Settings (#14832)
This commit is contained in:
parent
975300a320
commit
7213aada8d
@ -261,6 +261,12 @@ enum event_command
|
|||||||
CMD_EVENT_BSV_RECORDING_TOGGLE,
|
CMD_EVENT_BSV_RECORDING_TOGGLE,
|
||||||
/* Toggle Run-Ahead. */
|
/* Toggle Run-Ahead. */
|
||||||
CMD_EVENT_RUNAHEAD_TOGGLE,
|
CMD_EVENT_RUNAHEAD_TOGGLE,
|
||||||
|
/* Toggle Preemtive Frames. */
|
||||||
|
CMD_EVENT_PREEMPT_TOGGLE,
|
||||||
|
/* Deinitialize or Reinitialize Preemptive Frames. */
|
||||||
|
CMD_EVENT_PREEMPT_UPDATE,
|
||||||
|
/* Force Preemptive Frames to refill its state buffer. */
|
||||||
|
CMD_EVENT_PREEMPT_RESET_BUFFER,
|
||||||
/* Toggle VRR runloop. */
|
/* Toggle VRR runloop. */
|
||||||
CMD_EVENT_VRR_RUNLOOP_TOGGLE,
|
CMD_EVENT_VRR_RUNLOOP_TOGGLE,
|
||||||
/* AI service. */
|
/* AI service. */
|
||||||
@ -505,6 +511,7 @@ static const struct cmd_map map[] = {
|
|||||||
|
|
||||||
{ "VRR_RUNLOOP_TOGGLE", RARCH_VRR_RUNLOOP_TOGGLE },
|
{ "VRR_RUNLOOP_TOGGLE", RARCH_VRR_RUNLOOP_TOGGLE },
|
||||||
{ "RUNAHEAD_TOGGLE", RARCH_RUNAHEAD_TOGGLE },
|
{ "RUNAHEAD_TOGGLE", RARCH_RUNAHEAD_TOGGLE },
|
||||||
|
{ "PREEMPT_TOGGLE", RARCH_PREEMPT_TOGGLE },
|
||||||
{ "FPS_TOGGLE", RARCH_FPS_TOGGLE },
|
{ "FPS_TOGGLE", RARCH_FPS_TOGGLE },
|
||||||
{ "STATISTICS_TOGGLE", RARCH_STATISTICS_TOGGLE },
|
{ "STATISTICS_TOGGLE", RARCH_STATISTICS_TOGGLE },
|
||||||
{ "AI_SERVICE", RARCH_AI_SERVICE },
|
{ "AI_SERVICE", RARCH_AI_SERVICE },
|
||||||
|
@ -1299,6 +1299,8 @@
|
|||||||
|
|
||||||
/* Hide warning messages when using the Run Ahead feature. */
|
/* Hide warning messages when using the Run Ahead feature. */
|
||||||
#define DEFAULT_RUN_AHEAD_HIDE_WARNINGS false
|
#define DEFAULT_RUN_AHEAD_HIDE_WARNINGS false
|
||||||
|
/* Hide warning messages when using Preemptive Frames. */
|
||||||
|
#define DEFAULT_PREEMPT_HIDE_WARNINGS false
|
||||||
|
|
||||||
/* Enable stdin/network command interface. */
|
/* Enable stdin/network command interface. */
|
||||||
#define DEFAULT_NETWORK_CMD_ENABLE false
|
#define DEFAULT_NETWORK_CMD_ENABLE false
|
||||||
|
@ -543,6 +543,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
|||||||
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
|
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
NULL, NULL,
|
||||||
|
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
||||||
|
MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE, RETROK_UNKNOWN,
|
||||||
|
RARCH_PREEMPT_TOGGLE, NO_BTN, NO_BTN, 0,
|
||||||
|
true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
||||||
@ -1143,6 +1150,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
|||||||
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
|
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
NULL, NULL,
|
||||||
|
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
||||||
|
MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE, RETROK_UNKNOWN,
|
||||||
|
RARCH_PREEMPT_TOGGLE, NO_BTN, NO_BTN, 0,
|
||||||
|
true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
||||||
@ -1753,6 +1767,13 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
|||||||
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
|
RARCH_RUNAHEAD_TOGGLE, NO_BTN, NO_BTN, 0,
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
NULL, NULL,
|
||||||
|
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
||||||
|
MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE, RETROK_UNKNOWN,
|
||||||
|
RARCH_PREEMPT_TOGGLE, NO_BTN, NO_BTN, 0,
|
||||||
|
true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
AXIS_NONE, AXIS_NONE, AXIS_NONE,
|
||||||
|
@ -357,6 +357,7 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = {
|
|||||||
|
|
||||||
DECLARE_META_BIND(2, toggle_vrr_runloop, RARCH_VRR_RUNLOOP_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE),
|
DECLARE_META_BIND(2, toggle_vrr_runloop, RARCH_VRR_RUNLOOP_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE),
|
||||||
DECLARE_META_BIND(2, runahead_toggle, RARCH_RUNAHEAD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE),
|
DECLARE_META_BIND(2, runahead_toggle, RARCH_RUNAHEAD_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE),
|
||||||
|
DECLARE_META_BIND(2, preempt_toggle, RARCH_PREEMPT_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE),
|
||||||
DECLARE_META_BIND(2, fps_toggle, RARCH_FPS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE),
|
DECLARE_META_BIND(2, fps_toggle, RARCH_FPS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE),
|
||||||
DECLARE_META_BIND(2, toggle_statistics, RARCH_STATISTICS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATISTICS_TOGGLE),
|
DECLARE_META_BIND(2, toggle_statistics, RARCH_STATISTICS_TOGGLE, MENU_ENUM_LABEL_VALUE_INPUT_META_STATISTICS_TOGGLE),
|
||||||
DECLARE_META_BIND(2, ai_service, RARCH_AI_SERVICE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE),
|
DECLARE_META_BIND(2, ai_service, RARCH_AI_SERVICE, MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE),
|
||||||
@ -1686,6 +1687,8 @@ static struct config_bool_setting *populate_settings_bool(
|
|||||||
SETTING_BOOL("run_ahead_enabled", &settings->bools.run_ahead_enabled, true, false, false);
|
SETTING_BOOL("run_ahead_enabled", &settings->bools.run_ahead_enabled, true, false, false);
|
||||||
SETTING_BOOL("run_ahead_secondary_instance", &settings->bools.run_ahead_secondary_instance, true, DEFAULT_RUN_AHEAD_SECONDARY_INSTANCE, false);
|
SETTING_BOOL("run_ahead_secondary_instance", &settings->bools.run_ahead_secondary_instance, true, DEFAULT_RUN_AHEAD_SECONDARY_INSTANCE, false);
|
||||||
SETTING_BOOL("run_ahead_hide_warnings", &settings->bools.run_ahead_hide_warnings, true, DEFAULT_RUN_AHEAD_HIDE_WARNINGS, false);
|
SETTING_BOOL("run_ahead_hide_warnings", &settings->bools.run_ahead_hide_warnings, true, DEFAULT_RUN_AHEAD_HIDE_WARNINGS, false);
|
||||||
|
SETTING_BOOL("preemptive_frames_enable", &settings->bools.preemptive_frames_enable, true, false, false);
|
||||||
|
SETTING_BOOL("preemptive_frames_hide_warnings", &settings->bools.preemptive_frames_hide_warnings, true, DEFAULT_PREEMPT_HIDE_WARNINGS, false);
|
||||||
SETTING_BOOL("audio_sync", &settings->bools.audio_sync, true, DEFAULT_AUDIO_SYNC, false);
|
SETTING_BOOL("audio_sync", &settings->bools.audio_sync, true, DEFAULT_AUDIO_SYNC, false);
|
||||||
SETTING_BOOL("video_shader_enable", &settings->bools.video_shader_enable, true, DEFAULT_SHADER_ENABLE, false);
|
SETTING_BOOL("video_shader_enable", &settings->bools.video_shader_enable, true, DEFAULT_SHADER_ENABLE, false);
|
||||||
SETTING_BOOL("video_shader_watch_files", &settings->bools.video_shader_watch_files, true, DEFAULT_VIDEO_SHADER_WATCH_FILES, false);
|
SETTING_BOOL("video_shader_watch_files", &settings->bools.video_shader_watch_files, true, DEFAULT_VIDEO_SHADER_WATCH_FILES, false);
|
||||||
|
@ -885,6 +885,8 @@ typedef struct settings
|
|||||||
bool run_ahead_enabled;
|
bool run_ahead_enabled;
|
||||||
bool run_ahead_secondary_instance;
|
bool run_ahead_secondary_instance;
|
||||||
bool run_ahead_hide_warnings;
|
bool run_ahead_hide_warnings;
|
||||||
|
bool preemptive_frames_enable;
|
||||||
|
bool preemptive_frames_hide_warnings;
|
||||||
bool pause_nonactive;
|
bool pause_nonactive;
|
||||||
bool pause_on_disconnect;
|
bool pause_on_disconnect;
|
||||||
bool block_sram_overwrite;
|
bool block_sram_overwrite;
|
||||||
|
@ -120,6 +120,7 @@ enum
|
|||||||
|
|
||||||
RARCH_VRR_RUNLOOP_TOGGLE,
|
RARCH_VRR_RUNLOOP_TOGGLE,
|
||||||
RARCH_RUNAHEAD_TOGGLE,
|
RARCH_RUNAHEAD_TOGGLE,
|
||||||
|
RARCH_PREEMPT_TOGGLE,
|
||||||
RARCH_FPS_TOGGLE,
|
RARCH_FPS_TOGGLE,
|
||||||
RARCH_STATISTICS_TOGGLE,
|
RARCH_STATISTICS_TOGGLE,
|
||||||
RARCH_AI_SERVICE,
|
RARCH_AI_SERVICE,
|
||||||
|
@ -235,6 +235,10 @@ int msg_hash_get_help_id_enum(enum msg_hash_enums msg, char *s, size_t len)
|
|||||||
snprintf(s, len,
|
snprintf(s, len,
|
||||||
"Toggles Run-Ahead mode on/off.");
|
"Toggles Run-Ahead mode on/off.");
|
||||||
break;
|
break;
|
||||||
|
case RARCH_PREEMPT_TOGGLE:
|
||||||
|
snprintf(s, len,
|
||||||
|
"Toggles Preemptive Frames on/off.");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (string_is_empty(s))
|
if (string_is_empty(s))
|
||||||
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len);
|
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len);
|
||||||
|
@ -3266,6 +3266,22 @@ MSG_HASH(
|
|||||||
MENU_ENUM_LABEL_RUN_AHEAD_FRAMES,
|
MENU_ENUM_LABEL_RUN_AHEAD_FRAMES,
|
||||||
"run_ahead_frames"
|
"run_ahead_frames"
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_ENABLE,
|
||||||
|
"preemptive_frames_enable"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_UNSUPPORTED,
|
||||||
|
"preemptive_frames_unsupported"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_HIDE_WARNINGS,
|
||||||
|
"preemptive_frames_hide_warnings"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_FRAMES,
|
||||||
|
"preemptive_frames"
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MENU_ENUM_LABEL_SORT_SAVEFILES_ENABLE,
|
MENU_ENUM_LABEL_SORT_SAVEFILES_ENABLE,
|
||||||
"sort_savefiles_enable"
|
"sort_savefiles_enable"
|
||||||
|
@ -3391,6 +3391,14 @@ MSG_HASH(
|
|||||||
MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE,
|
MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE,
|
||||||
"Switches Run-Ahead on/off."
|
"Switches Run-Ahead on/off."
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE,
|
||||||
|
"Preemptive Frames (Toggle)"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_INPUT_META_PREEMPT_TOGGLE,
|
||||||
|
"Switches Preemptive Frames on/off."
|
||||||
|
)
|
||||||
|
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE,
|
MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE,
|
||||||
@ -3720,6 +3728,38 @@ MSG_HASH(
|
|||||||
MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS,
|
MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS,
|
||||||
"Hide the warning message that appears when using Run-Ahead and the core does not support save states."
|
"Hide the warning message that appears when using Run-Ahead and the core does not support save states."
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_PREEMPT_UNSUPPORTED,
|
||||||
|
"[Preemptive Frames Unavailable]"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_PREEMPT_UNSUPPORTED,
|
||||||
|
"Current core is incompatible with preemptive frames due to lack of deterministic save state support."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_PREEMPT_ENABLE,
|
||||||
|
"Run Preemptive Frames"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_PREEMPT_ENABLE,
|
||||||
|
"Rerun core logic with the latest input when the controller state changes. Faster than Run-Ahead, but does not prevent audio issues cores may have with loading states."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_PREEMPT_FRAMES,
|
||||||
|
"Number of Preemptive Frames"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_PREEMPT_FRAMES,
|
||||||
|
"The number of frames to rerun. Causes gameplay issues such as jitter if the number of lag frames internal to the game is exceeded."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_PREEMPT_HIDE_WARNINGS,
|
||||||
|
"Hide Preemptive Frames Warnings"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_PREEMPT_HIDE_WARNINGS,
|
||||||
|
"Hide the warning message that appears when a core is incompatible with preemptive frames."
|
||||||
|
)
|
||||||
|
|
||||||
/* Settings > Core */
|
/* Settings > Core */
|
||||||
|
|
||||||
@ -13902,6 +13942,34 @@ MSG_HASH(
|
|||||||
MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE,
|
MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE,
|
||||||
"Failed to create second instance. Run-Ahead will now use only one instance."
|
"Failed to create second instance. Run-Ahead will now use only one instance."
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_PREEMPT_ENABLED,
|
||||||
|
"Preemptive Frames enabled. Latency frames removed: %u."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_PREEMPT_DISABLED,
|
||||||
|
"Preemptive Frames disabled."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_SAVESTATES,
|
||||||
|
"Preemptive Frames has been disabled because this core does not support save states."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_PREEMPT,
|
||||||
|
"Preemptive Frames unavailable because this core lacks deterministic save state support."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_PREEMPT_FAILED_TO_ALLOCATE,
|
||||||
|
"Failed to allocate memory for Preemptive Frames."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_PREEMPT_FAILED_TO_SAVE_STATE,
|
||||||
|
"Failed to save state. Preemptive Frames has been disabled."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_PREEMPT_FAILED_TO_LOAD_STATE,
|
||||||
|
"Failed to load state. Preemptive Frames has been disabled."
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MSG_SCANNING_OF_FILE_FINISHED,
|
MSG_SCANNING_OF_FILE_FINISHED,
|
||||||
"Scanning of file finished"
|
"Scanning of file finished"
|
||||||
|
@ -433,6 +433,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_ui_companion_toggle, ME
|
|||||||
|
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_vrr_runloop_toggle, MENU_ENUM_SUBLABEL_INPUT_META_VRR_RUNLOOP_TOGGLE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_vrr_runloop_toggle, MENU_ENUM_SUBLABEL_INPUT_META_VRR_RUNLOOP_TOGGLE)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_runahead_toggle, MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_runahead_toggle, MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_preempt_toggle, MENU_ENUM_SUBLABEL_INPUT_META_PREEMPT_TOGGLE)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_fps_toggle, MENU_ENUM_SUBLABEL_INPUT_META_FPS_TOGGLE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_fps_toggle, MENU_ENUM_SUBLABEL_INPUT_META_FPS_TOGGLE)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_statistics_toggle, MENU_ENUM_SUBLABEL_INPUT_META_STATISTICS_TOGGLE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_statistics_toggle, MENU_ENUM_SUBLABEL_INPUT_META_STATISTICS_TOGGLE)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_ai_service, MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_meta_ai_service, MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE)
|
||||||
@ -667,6 +668,10 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_enabled, MENU_
|
|||||||
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_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)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_hide_warnings, MENU_ENUM_SUBLABEL_RUN_AHEAD_HIDE_WARNINGS)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_frames, MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_run_ahead_frames, MENU_ENUM_SUBLABEL_RUN_AHEAD_FRAMES)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_preempt_unsupported, MENU_ENUM_SUBLABEL_PREEMPT_UNSUPPORTED)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_preempt_enable, MENU_ENUM_SUBLABEL_PREEMPT_ENABLE)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_preempt_hide_warnings, MENU_ENUM_SUBLABEL_PREEMPT_HIDE_WARNINGS)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_preempt_frames, MENU_ENUM_SUBLABEL_PREEMPT_FRAMES)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_block_timeout, MENU_ENUM_SUBLABEL_INPUT_BLOCK_TIMEOUT)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_block_timeout, MENU_ENUM_SUBLABEL_INPUT_BLOCK_TIMEOUT)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_rewind, MENU_ENUM_SUBLABEL_REWIND_ENABLE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_rewind, MENU_ENUM_SUBLABEL_REWIND_ENABLE)
|
||||||
#ifdef HAVE_CHEATS
|
#ifdef HAVE_CHEATS
|
||||||
@ -2254,6 +2259,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
|
|||||||
case RARCH_RUNAHEAD_TOGGLE:
|
case RARCH_RUNAHEAD_TOGGLE:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_runahead_toggle);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_runahead_toggle);
|
||||||
return 0;
|
return 0;
|
||||||
|
case RARCH_PREEMPT_TOGGLE:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_preempt_toggle);
|
||||||
|
return 0;
|
||||||
case RARCH_FPS_TOGGLE:
|
case RARCH_FPS_TOGGLE:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_fps_toggle);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_meta_fps_toggle);
|
||||||
return 0;
|
return 0;
|
||||||
@ -3831,6 +3839,18 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
|
|||||||
case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES:
|
case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_run_ahead_frames);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_run_ahead_frames);
|
||||||
break;
|
break;
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_UNSUPPORTED:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_preempt_unsupported);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_ENABLE:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_preempt_enable);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_FRAMES:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_preempt_frames);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_HIDE_WARNINGS:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_preempt_hide_warnings);
|
||||||
|
break;
|
||||||
case MENU_ENUM_LABEL_INPUT_BLOCK_TIMEOUT:
|
case MENU_ENUM_LABEL_INPUT_BLOCK_TIMEOUT:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_block_timeout);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_block_timeout);
|
||||||
break;
|
break;
|
||||||
|
@ -9265,6 +9265,7 @@ unsigned menu_displaylist_build_list(
|
|||||||
#ifdef HAVE_RUNAHEAD
|
#ifdef HAVE_RUNAHEAD
|
||||||
bool runahead_supported = true;
|
bool runahead_supported = true;
|
||||||
bool runahead_enabled = settings->bools.run_ahead_enabled;
|
bool runahead_enabled = settings->bools.run_ahead_enabled;
|
||||||
|
bool preempt_enabled = settings->bools.preemptive_frames_enable;
|
||||||
#endif
|
#endif
|
||||||
menu_displaylist_build_info_selective_t build_list[] = {
|
menu_displaylist_build_info_selective_t build_list[] = {
|
||||||
{MENU_ENUM_LABEL_VIDEO_FRAME_DELAY, PARSE_ONLY_UINT, true },
|
{MENU_ENUM_LABEL_VIDEO_FRAME_DELAY, PARSE_ONLY_UINT, true },
|
||||||
@ -9277,6 +9278,9 @@ unsigned menu_displaylist_build_list(
|
|||||||
{MENU_ENUM_LABEL_RUN_AHEAD_FRAMES, PARSE_ONLY_UINT, 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_SECONDARY_INSTANCE, PARSE_ONLY_BOOL, false },
|
||||||
{MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS, PARSE_ONLY_BOOL, false },
|
{MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS, PARSE_ONLY_BOOL, false },
|
||||||
|
{MENU_ENUM_LABEL_PREEMPT_ENABLE, PARSE_ONLY_BOOL, false },
|
||||||
|
{MENU_ENUM_LABEL_PREEMPT_FRAMES, PARSE_ONLY_UINT, false },
|
||||||
|
{MENU_ENUM_LABEL_PREEMPT_HIDE_WARNINGS, PARSE_ONLY_BOOL, false },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -9330,6 +9334,7 @@ unsigned menu_displaylist_build_list(
|
|||||||
switch (build_list[i].enum_idx)
|
switch (build_list[i].enum_idx)
|
||||||
{
|
{
|
||||||
case MENU_ENUM_LABEL_RUN_AHEAD_ENABLED:
|
case MENU_ENUM_LABEL_RUN_AHEAD_ENABLED:
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_ENABLE:
|
||||||
build_list[i].checked = true;
|
build_list[i].checked = true;
|
||||||
break;
|
break;
|
||||||
case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES:
|
case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES:
|
||||||
@ -9338,6 +9343,11 @@ unsigned menu_displaylist_build_list(
|
|||||||
if (runahead_enabled)
|
if (runahead_enabled)
|
||||||
build_list[i].checked = true;
|
build_list[i].checked = true;
|
||||||
break;
|
break;
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_FRAMES:
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_HIDE_WARNINGS:
|
||||||
|
if (preempt_enabled)
|
||||||
|
build_list[i].checked = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -9356,13 +9366,21 @@ unsigned menu_displaylist_build_list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RUNAHEAD
|
#ifdef HAVE_RUNAHEAD
|
||||||
if (!runahead_supported &&
|
if (!runahead_supported)
|
||||||
menu_entries_append(list,
|
{
|
||||||
|
if (menu_entries_append(list,
|
||||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_UNSUPPORTED),
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_UNSUPPORTED),
|
||||||
msg_hash_to_str(MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED),
|
msg_hash_to_str(MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED),
|
||||||
MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED,
|
MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED,
|
||||||
FILE_TYPE_NONE, 0, 0, NULL))
|
FILE_TYPE_NONE, 0, 0, NULL))
|
||||||
count++;
|
count++;
|
||||||
|
if (menu_entries_append(list,
|
||||||
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PREEMPT_UNSUPPORTED),
|
||||||
|
msg_hash_to_str(MENU_ENUM_LABEL_PREEMPT_UNSUPPORTED),
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_UNSUPPORTED,
|
||||||
|
FILE_TYPE_NONE, 0, 0, NULL))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
|
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
|
||||||
MENU_ENUM_LABEL_GAMEMODE_ENABLE, PARSE_ONLY_BOOL, false) == 0)
|
MENU_ENUM_LABEL_GAMEMODE_ENABLE, PARSE_ONLY_BOOL, false) == 0)
|
||||||
|
@ -6982,6 +6982,13 @@ void retroarch_menu_running_finished(bool quit)
|
|||||||
command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
|
command_event(CMD_EVENT_GAME_FOCUS_TOGGLE, &game_focus_cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
/* Preemptive Frames isn't run behind the menu,
|
||||||
|
* so its savestate buffer is out of date. */
|
||||||
|
if (!settings->bools.menu_pause_libretro)
|
||||||
|
command_event(CMD_EVENT_PREEMPT_RESET_BUFFER, NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure that menu screensaver is disabled when
|
/* Ensure that menu screensaver is disabled when
|
||||||
|
@ -8654,31 +8654,6 @@ static void general_write_handler(rarch_setting_t *setting)
|
|||||||
default_aspect;
|
default_aspect;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#if defined(HAVE_RUNAHEAD) && (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
|
|
||||||
case MENU_ENUM_LABEL_RUN_AHEAD_ENABLED:
|
|
||||||
case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES:
|
|
||||||
case MENU_ENUM_LABEL_RUN_AHEAD_SECONDARY_INSTANCE:
|
|
||||||
{
|
|
||||||
settings_t *settings = config_get_ptr();
|
|
||||||
bool run_ahead_enabled = settings->bools.run_ahead_enabled;
|
|
||||||
unsigned run_ahead_frames = settings->uints.run_ahead_frames;
|
|
||||||
bool run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance;
|
|
||||||
|
|
||||||
/* If any changes here will cause second
|
|
||||||
* instance runahead to be enabled, must
|
|
||||||
* re-apply cheats to ensure that they
|
|
||||||
* propagate to the newly-created secondary
|
|
||||||
* core */
|
|
||||||
if (run_ahead_enabled &&
|
|
||||||
(run_ahead_frames > 0) &&
|
|
||||||
run_ahead_secondary_instance &&
|
|
||||||
!retroarch_ctl(RARCH_CTL_IS_SECOND_CORE_LOADED, NULL) &&
|
|
||||||
retroarch_ctl(RARCH_CTL_IS_SECOND_CORE_AVAILABLE, NULL) &&
|
|
||||||
command_event(CMD_EVENT_LOAD_SECOND_CORE, NULL))
|
|
||||||
command_event(CMD_EVENT_CHEATS_APPLY, NULL);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
/* Special cases */
|
/* Special cases */
|
||||||
|
|
||||||
@ -8713,6 +8688,104 @@ static void frontend_log_level_change_handler(rarch_setting_t *setting)
|
|||||||
verbosity_set_log_level(*setting->value.target.unsigned_integer);
|
verbosity_set_log_level(*setting->value.target.unsigned_integer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_RUNAHEAD
|
||||||
|
static void runahead_change_handler(rarch_setting_t *setting)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
bool run_ahead_enabled = settings->bools.run_ahead_enabled;
|
||||||
|
bool preempt_enabled = settings->bools.preemptive_frames_enable;
|
||||||
|
bool refresh = false;
|
||||||
|
#if (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
|
||||||
|
unsigned run_ahead_frames = settings->uints.run_ahead_frames;
|
||||||
|
bool run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!setting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (setting->enum_idx)
|
||||||
|
{
|
||||||
|
case MENU_ENUM_LABEL_RUN_AHEAD_ENABLED:
|
||||||
|
if (run_ahead_enabled && preempt_enabled)
|
||||||
|
{
|
||||||
|
/* Disable preemptive frames and inform user */
|
||||||
|
settings->bools.preemptive_frames_enable = false;
|
||||||
|
runloop_preempt_deinit();
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg_hash_to_str(MSG_PREEMPT_DISABLED), 1, 100, false,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
}
|
||||||
|
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
|
||||||
|
/* fall-through */
|
||||||
|
case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES:
|
||||||
|
#if (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
|
||||||
|
case MENU_ENUM_LABEL_RUN_AHEAD_SECONDARY_INSTANCE:
|
||||||
|
/* If any changes here will cause second
|
||||||
|
* instance runahead to be enabled, must
|
||||||
|
* re-apply cheats to ensure that they
|
||||||
|
* propagate to the newly-created secondary
|
||||||
|
* core */
|
||||||
|
if ( run_ahead_enabled
|
||||||
|
&& (run_ahead_frames > 0)
|
||||||
|
&& run_ahead_secondary_instance
|
||||||
|
&& !retroarch_ctl(RARCH_CTL_IS_SECOND_CORE_LOADED, NULL)
|
||||||
|
&& retroarch_ctl(RARCH_CTL_IS_SECOND_CORE_AVAILABLE, NULL)
|
||||||
|
&& command_event(CMD_EVENT_LOAD_SECOND_CORE, NULL))
|
||||||
|
command_event(CMD_EVENT_CHEATS_APPLY, NULL);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void preempt_change_handler(rarch_setting_t *setting)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
bool preempt_enabled = settings->bools.preemptive_frames_enable;
|
||||||
|
bool run_ahead_enabled = settings->bools.run_ahead_enabled;
|
||||||
|
preempt_t *preempt = runloop_state_get_ptr()->preempt_data;
|
||||||
|
bool refresh = false;
|
||||||
|
bool netplay_enabled;
|
||||||
|
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
netplay_enabled = netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL);
|
||||||
|
#else
|
||||||
|
netplay_enabled = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!setting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (setting->enum_idx)
|
||||||
|
{
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_ENABLE:
|
||||||
|
if (preempt_enabled && run_ahead_enabled)
|
||||||
|
{
|
||||||
|
/* Disable runahead and inform user */
|
||||||
|
settings->bools.run_ahead_enabled = false;
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg_hash_to_str(MSG_RUNAHEAD_DISABLED), 1, 100, false,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((preempt_enabled != !!preempt) && !netplay_enabled)
|
||||||
|
command_event(CMD_EVENT_PREEMPT_UPDATE, NULL);
|
||||||
|
|
||||||
|
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_PREEMPT_FRAMES:
|
||||||
|
if ( preempt
|
||||||
|
&& preempt->frames != settings->uints.run_ahead_frames
|
||||||
|
&& !netplay_enabled)
|
||||||
|
command_event(CMD_EVENT_PREEMPT_UPDATE, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_OVERLAY
|
#ifdef HAVE_OVERLAY
|
||||||
static void overlay_enable_toggle_change_handler(rarch_setting_t *setting)
|
static void overlay_enable_toggle_change_handler(rarch_setting_t *setting)
|
||||||
{
|
{
|
||||||
@ -14793,6 +14866,7 @@ static bool setting_append_list(
|
|||||||
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
|
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
|
||||||
menu_settings_list_current_add_range(list, list_info, 1, 10, 0.1, true, true);
|
menu_settings_list_current_add_range(list, list_info, 1, 10, 0.1, true, true);
|
||||||
|
|
||||||
|
#ifdef HAVE_RUNAHEAD
|
||||||
CONFIG_BOOL(
|
CONFIG_BOOL(
|
||||||
list, list_info,
|
list, list_info,
|
||||||
&settings->bools.run_ahead_enabled,
|
&settings->bools.run_ahead_enabled,
|
||||||
@ -14808,9 +14882,7 @@ static bool setting_append_list(
|
|||||||
general_read_handler,
|
general_read_handler,
|
||||||
SD_FLAG_NONE
|
SD_FLAG_NONE
|
||||||
);
|
);
|
||||||
(*list)[list_info->index - 1].action_ok = setting_bool_action_left_with_refresh;
|
(*list)[list_info->index - 1].change_handler = runahead_change_handler;
|
||||||
(*list)[list_info->index - 1].action_left = setting_bool_action_left_with_refresh;
|
|
||||||
(*list)[list_info->index - 1].action_right = setting_bool_action_right_with_refresh;
|
|
||||||
|
|
||||||
CONFIG_UINT(
|
CONFIG_UINT(
|
||||||
list, list_info,
|
list, list_info,
|
||||||
@ -14826,7 +14898,8 @@ static bool setting_append_list(
|
|||||||
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX;
|
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX;
|
||||||
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
|
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
|
||||||
(*list)[list_info->index - 1].offset_by = 1;
|
(*list)[list_info->index - 1].offset_by = 1;
|
||||||
menu_settings_list_current_add_range(list, list_info, 1, 12, 1, true, true);
|
(*list)[list_info->index - 1].change_handler = runahead_change_handler;
|
||||||
|
menu_settings_list_current_add_range(list, list_info, 1, MAX_RUNAHEAD_FRAMES, 1, true, true);
|
||||||
|
|
||||||
#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
|
#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
|
||||||
CONFIG_BOOL(
|
CONFIG_BOOL(
|
||||||
@ -14844,6 +14917,7 @@ static bool setting_append_list(
|
|||||||
general_read_handler,
|
general_read_handler,
|
||||||
SD_FLAG_NONE
|
SD_FLAG_NONE
|
||||||
);
|
);
|
||||||
|
(*list)[list_info->index - 1].change_handler = runahead_change_handler;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CONFIG_BOOL(
|
CONFIG_BOOL(
|
||||||
@ -14862,6 +14936,56 @@ static bool setting_append_list(
|
|||||||
SD_FLAG_ADVANCED
|
SD_FLAG_ADVANCED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CONFIG_BOOL(
|
||||||
|
list, list_info,
|
||||||
|
&settings->bools.preemptive_frames_enable,
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_ENABLE,
|
||||||
|
MENU_ENUM_LABEL_VALUE_PREEMPT_ENABLE,
|
||||||
|
false,
|
||||||
|
MENU_ENUM_LABEL_VALUE_OFF,
|
||||||
|
MENU_ENUM_LABEL_VALUE_ON,
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler,
|
||||||
|
SD_FLAG_NONE);
|
||||||
|
(*list)[list_info->index - 1].change_handler = preempt_change_handler;
|
||||||
|
|
||||||
|
CONFIG_UINT(
|
||||||
|
list, list_info,
|
||||||
|
&settings->uints.run_ahead_frames,
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_FRAMES,
|
||||||
|
MENU_ENUM_LABEL_VALUE_PREEMPT_FRAMES,
|
||||||
|
1,
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler);
|
||||||
|
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX;
|
||||||
|
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
|
||||||
|
(*list)[list_info->index - 1].offset_by = 1;
|
||||||
|
(*list)[list_info->index - 1].change_handler = preempt_change_handler;
|
||||||
|
menu_settings_list_current_add_range(list, list_info, 1, MAX_RUNAHEAD_FRAMES, 1, true, true);
|
||||||
|
|
||||||
|
CONFIG_BOOL(
|
||||||
|
list, list_info,
|
||||||
|
&settings->bools.preemptive_frames_hide_warnings,
|
||||||
|
MENU_ENUM_LABEL_PREEMPT_HIDE_WARNINGS,
|
||||||
|
MENU_ENUM_LABEL_VALUE_PREEMPT_HIDE_WARNINGS,
|
||||||
|
DEFAULT_PREEMPT_HIDE_WARNINGS,
|
||||||
|
MENU_ENUM_LABEL_VALUE_OFF,
|
||||||
|
MENU_ENUM_LABEL_VALUE_ON,
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler,
|
||||||
|
SD_FLAG_ADVANCED
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
CONFIG_UINT(
|
CONFIG_UINT(
|
||||||
list, list_info,
|
list, list_info,
|
||||||
|
13
msg_hash.h
13
msg_hash.h
@ -520,6 +520,13 @@ enum msg_hash_enums
|
|||||||
MSG_RUNAHEAD_FAILED_TO_SAVE_STATE,
|
MSG_RUNAHEAD_FAILED_TO_SAVE_STATE,
|
||||||
MSG_RUNAHEAD_FAILED_TO_LOAD_STATE,
|
MSG_RUNAHEAD_FAILED_TO_LOAD_STATE,
|
||||||
MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE,
|
MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE,
|
||||||
|
MSG_PREEMPT_ENABLED,
|
||||||
|
MSG_PREEMPT_DISABLED,
|
||||||
|
MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_SAVESTATES,
|
||||||
|
MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_PREEMPT,
|
||||||
|
MSG_PREEMPT_FAILED_TO_ALLOCATE,
|
||||||
|
MSG_PREEMPT_FAILED_TO_SAVE_STATE,
|
||||||
|
MSG_PREEMPT_FAILED_TO_LOAD_STATE,
|
||||||
MSG_MISSING_ASSETS,
|
MSG_MISSING_ASSETS,
|
||||||
MSG_RGUI_MISSING_FONTS,
|
MSG_RGUI_MISSING_FONTS,
|
||||||
MSG_RGUI_INVALID_LANGUAGE,
|
MSG_RGUI_INVALID_LANGUAGE,
|
||||||
@ -1033,6 +1040,7 @@ enum msg_hash_enums
|
|||||||
|
|
||||||
MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE,
|
MENU_ENUM_LABEL_VALUE_INPUT_META_VRR_RUNLOOP_TOGGLE,
|
||||||
MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE,
|
MENU_ENUM_LABEL_VALUE_INPUT_META_RUNAHEAD_TOGGLE,
|
||||||
|
MENU_ENUM_LABEL_VALUE_INPUT_META_PREEMPT_TOGGLE,
|
||||||
MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE,
|
MENU_ENUM_LABEL_VALUE_INPUT_META_FPS_TOGGLE,
|
||||||
MENU_ENUM_LABEL_VALUE_INPUT_META_STATISTICS_TOGGLE,
|
MENU_ENUM_LABEL_VALUE_INPUT_META_STATISTICS_TOGGLE,
|
||||||
MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE,
|
MENU_ENUM_LABEL_VALUE_INPUT_META_AI_SERVICE,
|
||||||
@ -1109,6 +1117,7 @@ enum msg_hash_enums
|
|||||||
|
|
||||||
MENU_ENUM_SUBLABEL_INPUT_META_VRR_RUNLOOP_TOGGLE,
|
MENU_ENUM_SUBLABEL_INPUT_META_VRR_RUNLOOP_TOGGLE,
|
||||||
MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE,
|
MENU_ENUM_SUBLABEL_INPUT_META_RUNAHEAD_TOGGLE,
|
||||||
|
MENU_ENUM_SUBLABEL_INPUT_META_PREEMPT_TOGGLE,
|
||||||
MENU_ENUM_SUBLABEL_INPUT_META_FPS_TOGGLE,
|
MENU_ENUM_SUBLABEL_INPUT_META_FPS_TOGGLE,
|
||||||
MENU_ENUM_SUBLABEL_INPUT_META_STATISTICS_TOGGLE,
|
MENU_ENUM_SUBLABEL_INPUT_META_STATISTICS_TOGGLE,
|
||||||
MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE,
|
MENU_ENUM_SUBLABEL_INPUT_META_AI_SERVICE,
|
||||||
@ -2444,6 +2453,10 @@ enum msg_hash_enums
|
|||||||
MENU_LABEL(RUN_AHEAD_SECONDARY_INSTANCE),
|
MENU_LABEL(RUN_AHEAD_SECONDARY_INSTANCE),
|
||||||
MENU_LABEL(RUN_AHEAD_HIDE_WARNINGS),
|
MENU_LABEL(RUN_AHEAD_HIDE_WARNINGS),
|
||||||
MENU_LABEL(RUN_AHEAD_FRAMES),
|
MENU_LABEL(RUN_AHEAD_FRAMES),
|
||||||
|
MENU_LABEL(PREEMPT_UNSUPPORTED),
|
||||||
|
MENU_LABEL(PREEMPT_ENABLE),
|
||||||
|
MENU_LABEL(PREEMPT_FRAMES),
|
||||||
|
MENU_LABEL(PREEMPT_HIDE_WARNINGS),
|
||||||
MENU_LABEL(INPUT_BLOCK_TIMEOUT),
|
MENU_LABEL(INPUT_BLOCK_TIMEOUT),
|
||||||
MENU_LABEL(TURBO),
|
MENU_LABEL(TURBO),
|
||||||
|
|
||||||
|
@ -8435,6 +8435,11 @@ void deinit_netplay(void)
|
|||||||
net_st->data = NULL;
|
net_st->data = NULL;
|
||||||
net_st->flags &= ~(NET_DRIVER_ST_FLAG_NETPLAY_ENABLED
|
net_st->flags &= ~(NET_DRIVER_ST_FLAG_NETPLAY_ENABLED
|
||||||
| NET_DRIVER_ST_FLAG_NETPLAY_IS_CLIENT);
|
| NET_DRIVER_ST_FLAG_NETPLAY_IS_CLIENT);
|
||||||
|
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
/* Reinitialize preemptive frames if enabled */
|
||||||
|
runloop_preempt_init();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
free(net_st->client_info);
|
free(net_st->client_info);
|
||||||
|
107
retroarch.c
107
retroarch.c
@ -2228,10 +2228,8 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_RUNAHEAD_TOGGLE:
|
case CMD_EVENT_RUNAHEAD_TOGGLE:
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
{
|
{
|
||||||
char msg[256];
|
|
||||||
msg[0] = '\0';
|
|
||||||
|
|
||||||
if (!core_info_current_supports_runahead())
|
if (!core_info_current_supports_runahead())
|
||||||
{
|
{
|
||||||
runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_RUNAHEAD),
|
runloop_msg_queue_push(msg_hash_to_str(MSG_RUNAHEAD_CORE_DOES_NOT_SUPPORT_RUNAHEAD),
|
||||||
@ -2249,25 +2247,86 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
1, 100, false,
|
1, 100, false,
|
||||||
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
}
|
}
|
||||||
else if (!settings->bools.run_ahead_secondary_instance)
|
|
||||||
{
|
|
||||||
snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED),
|
|
||||||
settings->uints.run_ahead_frames);
|
|
||||||
|
|
||||||
runloop_msg_queue_push(
|
|
||||||
msg, 1, 100, false,
|
|
||||||
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE),
|
char msg[256];
|
||||||
settings->uints.run_ahead_frames);
|
|
||||||
|
|
||||||
|
if (!settings->bools.run_ahead_secondary_instance)
|
||||||
|
{
|
||||||
|
snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED),
|
||||||
|
settings->uints.run_ahead_frames);
|
||||||
|
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg, 1, 100, false,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_RUNAHEAD_ENABLED_WITH_SECOND_INSTANCE),
|
||||||
|
settings->uints.run_ahead_frames);
|
||||||
|
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg, 1, 100, false,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable preemptive frames */
|
||||||
|
settings->bools.preemptive_frames_enable = false;
|
||||||
|
runloop_preempt_deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case CMD_EVENT_PREEMPT_TOGGLE:
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
{
|
||||||
|
bool old_warn = settings->bools.preemptive_frames_hide_warnings;
|
||||||
|
bool old_inited = runloop_st->preempt_data;
|
||||||
|
|
||||||
|
/* Toggle with warnings shown */
|
||||||
|
settings->bools.preemptive_frames_hide_warnings = false;
|
||||||
|
|
||||||
|
settings->bools.preemptive_frames_enable =
|
||||||
|
!(settings->bools.preemptive_frames_enable);
|
||||||
|
command_event(CMD_EVENT_PREEMPT_UPDATE, NULL);
|
||||||
|
|
||||||
|
settings->bools.preemptive_frames_hide_warnings = old_warn;
|
||||||
|
|
||||||
|
if (old_inited && !runloop_st->preempt_data)
|
||||||
|
{
|
||||||
|
runloop_msg_queue_push(msg_hash_to_str(MSG_PREEMPT_DISABLED),
|
||||||
|
1, 100, false,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
}
|
||||||
|
else if (runloop_st->preempt_data)
|
||||||
|
{
|
||||||
|
char msg[256];
|
||||||
|
|
||||||
|
snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_PREEMPT_ENABLED),
|
||||||
|
settings->uints.run_ahead_frames);
|
||||||
runloop_msg_queue_push(
|
runloop_msg_queue_push(
|
||||||
msg, 1, 100, false,
|
msg, 1, 100, false,
|
||||||
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
|
||||||
|
/* Disable runahead */
|
||||||
|
settings->bools.run_ahead_enabled = false;
|
||||||
}
|
}
|
||||||
|
else /* Failed to init */
|
||||||
|
settings->bools.preemptive_frames_enable = false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case CMD_EVENT_PREEMPT_UPDATE:
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
runloop_preempt_deinit();
|
||||||
|
runloop_preempt_init();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case CMD_EVENT_PREEMPT_RESET_BUFFER:
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
if (runloop_st->preempt_data)
|
||||||
|
runloop_st->preempt_data->frame_count = 0;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_RECORDING_TOGGLE:
|
case CMD_EVENT_RECORDING_TOGGLE:
|
||||||
if (recording_st->enable)
|
if (recording_st->enable)
|
||||||
@ -2381,6 +2440,10 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
#endif
|
#endif
|
||||||
if (!command_event_main_state(cmd))
|
if (!command_event_main_state(cmd))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
command_event(CMD_EVENT_PREEMPT_RESET_BUFFER, NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_UNDO_LOAD_STATE:
|
case CMD_EVENT_UNDO_LOAD_STATE:
|
||||||
@ -2427,6 +2490,9 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
if (settings->bools.video_frame_delay_auto)
|
if (settings->bools.video_frame_delay_auto)
|
||||||
video_st->frame_delay_target = 0;
|
video_st->frame_delay_target = 0;
|
||||||
|
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
command_event(CMD_EVENT_PREEMPT_RESET_BUFFER, NULL);
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
case CMD_EVENT_SAVE_STATE:
|
case CMD_EVENT_SAVE_STATE:
|
||||||
case CMD_EVENT_SAVE_STATE_TO_RAM:
|
case CMD_EVENT_SAVE_STATE_TO_RAM:
|
||||||
@ -2977,6 +3043,9 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
* RetroArch */
|
* RetroArch */
|
||||||
if (!(runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_AVAILABLE))
|
if (!(runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_AVAILABLE))
|
||||||
runloop_runahead_clear_variables(runloop_st);
|
runloop_runahead_clear_variables(runloop_st);
|
||||||
|
|
||||||
|
/* Deallocate preemptive frames */
|
||||||
|
runloop_preempt_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (hwr)
|
if (hwr)
|
||||||
@ -3512,6 +3581,10 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
/* Deinit preemptive frames; not compatible with netplay */
|
||||||
|
runloop_preempt_deinit();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_NETPLAY_DISCONNECT:
|
case CMD_EVENT_NETPLAY_DISCONNECT:
|
||||||
@ -6171,6 +6244,12 @@ bool retroarch_main_init(int argc, char *argv[])
|
|||||||
audio_driver_load_system_sounds();
|
audio_driver_load_system_sounds();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_RUNAHEAD) && defined(HAVE_NETWORKING)
|
||||||
|
if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
|
||||||
|
#elif defined(HAVE_RUNAHEAD)
|
||||||
|
runloop_preempt_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
384
runloop.c
384
runloop.c
@ -4974,6 +4974,380 @@ force_input_dirty:
|
|||||||
core_run();
|
core_run();
|
||||||
runloop_st->flags |= RUNLOOP_FLAG_RUNAHEAD_FORCE_INPUT_DIRTY;
|
runloop_st->flags |= RUNLOOP_FLAG_RUNAHEAD_FORCE_INPUT_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Preemptive Frames */
|
||||||
|
|
||||||
|
static int16_t preempt_input_state(unsigned port,
|
||||||
|
unsigned device, unsigned index, unsigned id)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
runloop_state_t *runloop_st = &runloop_state;
|
||||||
|
preempt_t *preempt = runloop_st->preempt_data;
|
||||||
|
unsigned device_class = device & RETRO_DEVICE_MASK;
|
||||||
|
unsigned *port_map = settings->uints.input_remap_port_map[port];
|
||||||
|
uint8_t p;
|
||||||
|
|
||||||
|
switch (device_class)
|
||||||
|
{
|
||||||
|
case RETRO_DEVICE_ANALOG:
|
||||||
|
/* Add requested inputs to mask */
|
||||||
|
while ((p = *(port_map++)) < MAX_USERS)
|
||||||
|
preempt->analog_mask[p] |= (1 << (id + index * 2));
|
||||||
|
break;
|
||||||
|
case RETRO_DEVICE_LIGHTGUN:
|
||||||
|
case RETRO_DEVICE_MOUSE:
|
||||||
|
case RETRO_DEVICE_POINTER:
|
||||||
|
/* Set pointing device for this port */
|
||||||
|
while ((p = *(port_map++)) < MAX_USERS)
|
||||||
|
preempt->ptr_dev[p] = device_class;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return input_driver_state_wrapper(port, device, index, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* preempt_allocate(const uint8_t frames)
|
||||||
|
{
|
||||||
|
runloop_state_t *runloop_st = &runloop_state;
|
||||||
|
preempt_t *preempt = (preempt_t*)calloc(1, sizeof(preempt_t));
|
||||||
|
retro_ctx_size_info_t info;
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
if (!(runloop_st->preempt_data = preempt))
|
||||||
|
return msg_hash_to_str(MSG_PREEMPT_FAILED_TO_ALLOCATE);
|
||||||
|
|
||||||
|
core_serialize_size_special(&info);
|
||||||
|
if (!info.size)
|
||||||
|
return msg_hash_to_str(MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_SAVESTATES);
|
||||||
|
|
||||||
|
preempt->state_size = info.size;
|
||||||
|
preempt->frames = frames;
|
||||||
|
|
||||||
|
for (i = 0; i < frames; i++)
|
||||||
|
{
|
||||||
|
preempt->buffer[i] = malloc(preempt->state_size);
|
||||||
|
if (!preempt->buffer[i])
|
||||||
|
return msg_hash_to_str(MSG_PREEMPT_FAILED_TO_ALLOCATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* runloop_preempt_init:
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure
|
||||||
|
*
|
||||||
|
* Allocates savestate buffer and sets overrides for preemptive frames.
|
||||||
|
**/
|
||||||
|
bool runloop_preempt_init(void)
|
||||||
|
{
|
||||||
|
runloop_state_t *runloop_st = &runloop_state;
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
const char *failed_str = NULL;
|
||||||
|
|
||||||
|
if ( runloop_st->preempt_data
|
||||||
|
|| !settings->bools.preemptive_frames_enable
|
||||||
|
|| !settings->uints.run_ahead_frames
|
||||||
|
|| !(runloop_st->current_core.flags & RETRO_CORE_FLAG_GAME_LOADED))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check if supported - same requirements as runahead */
|
||||||
|
if (!core_info_current_supports_runahead())
|
||||||
|
{
|
||||||
|
failed_str = msg_hash_to_str(MSG_PREEMPT_CORE_DOES_NOT_SUPPORT_PREEMPT);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set flags to block runahead and request 'same instance' states */
|
||||||
|
runloop_st->flags &= ~(RUNLOOP_FLAG_RUNAHEAD_AVAILABLE
|
||||||
|
| RUNLOOP_FLAG_RUNAHEAD_SECONDARY_CORE_AVAILABLE);
|
||||||
|
|
||||||
|
/* Allocate - same 'frames' setting as runahead */
|
||||||
|
if ((failed_str = preempt_allocate(settings->uints.run_ahead_frames)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Only poll in preempt_run() */
|
||||||
|
runloop_st->current_core.retro_set_input_poll(retro_input_poll_null);
|
||||||
|
/* Track requested analog states and pointing device types */
|
||||||
|
runloop_st->current_core.retro_set_input_state(preempt_input_state);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
runloop_preempt_deinit();
|
||||||
|
|
||||||
|
if (!config_get_ptr()->bools.preemptive_frames_hide_warnings)
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
failed_str, 0, 2 * 60, true,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
RARCH_WARN("[Preemptive Frames]: %s\n", failed_str);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* runloop_preempt_deinit:
|
||||||
|
*
|
||||||
|
* Frees preempt object and unsets overrides.
|
||||||
|
**/
|
||||||
|
void runloop_preempt_deinit(void)
|
||||||
|
{
|
||||||
|
runloop_state_t *runloop_st = &runloop_state;
|
||||||
|
preempt_t *preempt = runloop_st->preempt_data;
|
||||||
|
struct retro_core_t *current_core = &runloop_st->current_core;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (preempt == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Free memory */
|
||||||
|
for (i = 0; i < preempt->frames; i++)
|
||||||
|
free(preempt->buffer[i]);
|
||||||
|
|
||||||
|
free(preempt);
|
||||||
|
runloop_st->preempt_data = NULL;
|
||||||
|
|
||||||
|
/* Undo overrides */
|
||||||
|
runloop_st->flags |= (RUNLOOP_FLAG_RUNAHEAD_AVAILABLE
|
||||||
|
| RUNLOOP_FLAG_RUNAHEAD_SECONDARY_CORE_AVAILABLE);
|
||||||
|
|
||||||
|
if (current_core->retro_set_input_poll)
|
||||||
|
current_core->retro_set_input_poll(runloop_st->input_poll_callback_original);
|
||||||
|
if (current_core->retro_set_input_state)
|
||||||
|
current_core->retro_set_input_state(runloop_st->retro_ctx.state_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool preempt_analog_input_dirty(preempt_t *preempt,
|
||||||
|
retro_input_state_t state_cb, unsigned port, unsigned mapped_port)
|
||||||
|
{
|
||||||
|
int16_t state[20] = {0};
|
||||||
|
uint8_t base, i;
|
||||||
|
|
||||||
|
/* axes */
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
base = i * 2;
|
||||||
|
if (preempt->analog_mask[port] & (1 << (base )))
|
||||||
|
state[base ] = state_cb(mapped_port, RETRO_DEVICE_ANALOG, i, 0);
|
||||||
|
if (preempt->analog_mask[port] & (1 << (base + 1)))
|
||||||
|
state[base + 1] = state_cb(mapped_port, RETRO_DEVICE_ANALOG, i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buttons */
|
||||||
|
for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
|
||||||
|
{
|
||||||
|
if (preempt->analog_mask[port] & (1 << (i + 4)))
|
||||||
|
state[i + 4] = state_cb(mapped_port, RETRO_DEVICE_ANALOG,
|
||||||
|
RETRO_DEVICE_INDEX_ANALOG_BUTTON, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(preempt->analog_state[port], state, sizeof(state)) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(preempt->analog_state[port], state, sizeof(state));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool preempt_ptr_input_dirty(preempt_t *preempt,
|
||||||
|
retro_input_state_t state_cb, unsigned device,
|
||||||
|
unsigned port, unsigned mapped_port)
|
||||||
|
{
|
||||||
|
int16_t state[4] = {0};
|
||||||
|
unsigned count_id = 0;
|
||||||
|
unsigned x_id = 0;
|
||||||
|
unsigned id, max_id;
|
||||||
|
|
||||||
|
switch (device)
|
||||||
|
{
|
||||||
|
case RETRO_DEVICE_MOUSE:
|
||||||
|
max_id = RETRO_DEVICE_ID_MOUSE_BUTTON_5;
|
||||||
|
break;
|
||||||
|
case RETRO_DEVICE_LIGHTGUN:
|
||||||
|
x_id = RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X;
|
||||||
|
max_id = RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT;
|
||||||
|
break;
|
||||||
|
case RETRO_DEVICE_POINTER:
|
||||||
|
max_id = RETRO_DEVICE_ID_POINTER_PRESSED;
|
||||||
|
count_id = RETRO_DEVICE_ID_POINTER_COUNT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* x, y */
|
||||||
|
state[0] = state_cb(mapped_port, device, 0, x_id );
|
||||||
|
state[1] = state_cb(mapped_port, device, 0, x_id + 1);
|
||||||
|
|
||||||
|
/* buttons */
|
||||||
|
for (id = 2; id <= max_id; id++)
|
||||||
|
state[2] |= state_cb(mapped_port, device, 0, id) ? 1 << id : 0;
|
||||||
|
|
||||||
|
/* ptr count */
|
||||||
|
if (count_id)
|
||||||
|
state[3] = state_cb(mapped_port, device, 0, count_id);
|
||||||
|
|
||||||
|
if (memcmp(preempt->ptrdev_state[port], state, sizeof(state)) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(preempt->ptrdev_state[port], state, sizeof(state));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void preempt_input_poll(preempt_t *preempt)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
runloop_state_t *runloop_st = &runloop_state;
|
||||||
|
retro_input_state_t state_cb = input_driver_state_wrapper;
|
||||||
|
unsigned max_users = settings->uints.input_max_users;
|
||||||
|
int16_t joypad_state;
|
||||||
|
unsigned p;
|
||||||
|
|
||||||
|
input_driver_poll();
|
||||||
|
|
||||||
|
/* Check for input state changes */
|
||||||
|
for (p = 0; p < max_users; p++)
|
||||||
|
{
|
||||||
|
unsigned mapped_port = settings->uints.input_remap_ports[p];
|
||||||
|
unsigned device = settings->uints.input_libretro_device[mapped_port]
|
||||||
|
& RETRO_DEVICE_MASK;
|
||||||
|
|
||||||
|
switch (device)
|
||||||
|
{
|
||||||
|
case RETRO_DEVICE_JOYPAD:
|
||||||
|
case RETRO_DEVICE_ANALOG:
|
||||||
|
/* Check full digital joypad */
|
||||||
|
joypad_state = state_cb(mapped_port, RETRO_DEVICE_JOYPAD,
|
||||||
|
0, RETRO_DEVICE_ID_JOYPAD_MASK);
|
||||||
|
if (joypad_state != preempt->joypad_state[p])
|
||||||
|
{
|
||||||
|
preempt->joypad_state[p] = joypad_state;
|
||||||
|
runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check requested analogs */
|
||||||
|
if ( preempt->analog_mask[p]
|
||||||
|
&& preempt_analog_input_dirty(preempt, state_cb, p, mapped_port))
|
||||||
|
runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY;
|
||||||
|
break;
|
||||||
|
case RETRO_DEVICE_MOUSE:
|
||||||
|
case RETRO_DEVICE_LIGHTGUN:
|
||||||
|
case RETRO_DEVICE_POINTER:
|
||||||
|
/* Check full device state */
|
||||||
|
if (preempt_ptr_input_dirty(
|
||||||
|
preempt, state_cb, preempt->ptr_dev[p], p, mapped_port))
|
||||||
|
runloop_st->flags |= RUNLOOP_FLAG_INPUT_IS_DIRTY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear requested inputs */
|
||||||
|
memset(preempt->analog_mask, 0, max_users * sizeof(uint32_t));
|
||||||
|
memset(preempt->ptr_dev, 0, max_users * sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void preempt_suspend_av(bool suspend)
|
||||||
|
{
|
||||||
|
audio_driver_state_t *audio_st = audio_state_get_ptr();
|
||||||
|
video_driver_state_t *video_st = video_state_get_ptr();
|
||||||
|
|
||||||
|
if (suspend)
|
||||||
|
{
|
||||||
|
audio_st->flags |= AUDIO_FLAG_SUSPENDED;
|
||||||
|
video_st->flags &= ~VIDEO_FLAG_ACTIVE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audio_st->flags &= ~AUDIO_FLAG_SUSPENDED;
|
||||||
|
video_st->flags |= VIDEO_FLAG_ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* macro for preempt_run */
|
||||||
|
#define PREEMPT_NEXT_PTR(x) ((x + 1) % preempt->frames)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* preempt_run:
|
||||||
|
* @preempt : pointer to preemptive frames object
|
||||||
|
*
|
||||||
|
* Call in place of core_run() for preemptive frames.
|
||||||
|
**/
|
||||||
|
static void preempt_run(preempt_t *preempt)
|
||||||
|
{
|
||||||
|
runloop_state_t *runloop_st = &runloop_state;
|
||||||
|
struct retro_core_t *current_core = &runloop_st->current_core;
|
||||||
|
const char *failed_str = NULL;
|
||||||
|
|
||||||
|
/* Poll and check for dirty input */
|
||||||
|
preempt_input_poll(preempt);
|
||||||
|
|
||||||
|
runloop_st->flags |= RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE;
|
||||||
|
|
||||||
|
if ((runloop_st->flags & RUNLOOP_FLAG_INPUT_IS_DIRTY)
|
||||||
|
&& preempt->frame_count >= preempt->frames)
|
||||||
|
{
|
||||||
|
/* Suspend A/V and run preemptive frames */
|
||||||
|
preempt_suspend_av(true);
|
||||||
|
|
||||||
|
if (!current_core->retro_unserialize(
|
||||||
|
preempt->buffer[preempt->start_ptr], preempt->state_size))
|
||||||
|
{
|
||||||
|
failed_str = msg_hash_to_str(MSG_PREEMPT_FAILED_TO_LOAD_STATE);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_core->retro_run();
|
||||||
|
preempt->replay_ptr = PREEMPT_NEXT_PTR(preempt->start_ptr);
|
||||||
|
|
||||||
|
while (preempt->replay_ptr != preempt->start_ptr)
|
||||||
|
{
|
||||||
|
if (!current_core->retro_serialize(
|
||||||
|
preempt->buffer[preempt->replay_ptr], preempt->state_size))
|
||||||
|
{
|
||||||
|
failed_str = msg_hash_to_str(MSG_PREEMPT_FAILED_TO_SAVE_STATE);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_core->retro_run();
|
||||||
|
preempt->replay_ptr = PREEMPT_NEXT_PTR(preempt->replay_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
preempt_suspend_av(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save current state and set start_ptr to oldest state */
|
||||||
|
if (!current_core->retro_serialize(
|
||||||
|
preempt->buffer[preempt->start_ptr], preempt->state_size))
|
||||||
|
{
|
||||||
|
failed_str = msg_hash_to_str(MSG_PREEMPT_FAILED_TO_SAVE_STATE);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
preempt->start_ptr = PREEMPT_NEXT_PTR(preempt->start_ptr);
|
||||||
|
runloop_st->flags &= ~(RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE
|
||||||
|
| RUNLOOP_FLAG_INPUT_IS_DIRTY);
|
||||||
|
|
||||||
|
/* Run normal frame */
|
||||||
|
current_core->retro_run();
|
||||||
|
preempt->frame_count++;
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
runloop_st->flags &= ~(RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE
|
||||||
|
| RUNLOOP_FLAG_INPUT_IS_DIRTY);
|
||||||
|
preempt_suspend_av(false);
|
||||||
|
runloop_preempt_deinit();
|
||||||
|
|
||||||
|
if (!config_get_ptr()->bools.preemptive_frames_hide_warnings)
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
failed_str, 0, 2 * 60, true,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
RARCH_ERR("[Preemptive Frames]: %s\n", failed_str);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static retro_time_t runloop_core_runtime_tick(
|
static retro_time_t runloop_core_runtime_tick(
|
||||||
@ -5583,6 +5957,8 @@ static void core_init_libretro_cbs(runloop_state_t *runloop_st,
|
|||||||
runloop_st->current_core.retro_set_input_state(state_cb);
|
runloop_st->current_core.retro_set_input_state(state_cb);
|
||||||
runloop_st->current_core.retro_set_input_poll(core_input_state_poll_maybe);
|
runloop_st->current_core.retro_set_input_poll(core_input_state_poll_maybe);
|
||||||
|
|
||||||
|
runloop_st->input_poll_callback_original = core_input_state_poll_maybe;
|
||||||
|
|
||||||
core_set_default_callbacks(cbs);
|
core_set_default_callbacks(cbs);
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKING
|
#ifdef HAVE_NETWORKING
|
||||||
@ -7169,6 +7545,9 @@ static enum runloop_state_enum runloop_check_state(
|
|||||||
/* Check if we have pressed the Run-Ahead toggle button */
|
/* Check if we have pressed the Run-Ahead toggle button */
|
||||||
HOTKEY_CHECK(RARCH_RUNAHEAD_TOGGLE, CMD_EVENT_RUNAHEAD_TOGGLE, true, NULL);
|
HOTKEY_CHECK(RARCH_RUNAHEAD_TOGGLE, CMD_EVENT_RUNAHEAD_TOGGLE, true, NULL);
|
||||||
|
|
||||||
|
/* Check if we have pressed the Preemptive Frames toggle button */
|
||||||
|
HOTKEY_CHECK(RARCH_PREEMPT_TOGGLE, CMD_EVENT_PREEMPT_TOGGLE, true, NULL);
|
||||||
|
|
||||||
/* Check if we have pressed the AI Service toggle button */
|
/* Check if we have pressed the AI Service toggle button */
|
||||||
HOTKEY_CHECK(RARCH_AI_SERVICE, CMD_EVENT_AI_SERVICE_TOGGLE, true, NULL);
|
HOTKEY_CHECK(RARCH_AI_SERVICE, CMD_EVENT_AI_SERVICE_TOGGLE, true, NULL);
|
||||||
|
|
||||||
@ -8004,6 +8383,8 @@ int runloop_iterate(void)
|
|||||||
run_ahead_num_frames,
|
run_ahead_num_frames,
|
||||||
run_ahead_hide_warnings,
|
run_ahead_hide_warnings,
|
||||||
run_ahead_secondary_instance);
|
run_ahead_secondary_instance);
|
||||||
|
else if (runloop_st->preempt_data)
|
||||||
|
preempt_run(runloop_st->preempt_data);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
core_run();
|
core_run();
|
||||||
@ -8522,6 +8903,9 @@ bool core_unserialize(retro_ctx_serialize_info_t *info)
|
|||||||
#ifdef HAVE_NETWORKING
|
#ifdef HAVE_NETWORKING
|
||||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, info);
|
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, info);
|
||||||
#endif
|
#endif
|
||||||
|
#if HAVE_RUNAHEAD
|
||||||
|
command_event(CMD_EVENT_PREEMPT_RESET_BUFFER, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
36
runloop.h
36
runloop.h
@ -159,7 +159,9 @@ typedef struct core_options_callbacks
|
|||||||
} core_options_callbacks_t;
|
} core_options_callbacks_t;
|
||||||
|
|
||||||
#ifdef HAVE_RUNAHEAD
|
#ifdef HAVE_RUNAHEAD
|
||||||
typedef bool (*runahead_load_state_function)(const void*, size_t);
|
#define MAX_RUNAHEAD_FRAMES 12
|
||||||
|
|
||||||
|
typedef bool(*runahead_load_state_function)(const void*, size_t);
|
||||||
|
|
||||||
typedef void *(*constructor_t)(void);
|
typedef void *(*constructor_t)(void);
|
||||||
typedef void (*destructor_t )(void*);
|
typedef void (*destructor_t )(void*);
|
||||||
@ -172,6 +174,33 @@ typedef struct my_list_t
|
|||||||
int capacity;
|
int capacity;
|
||||||
int size;
|
int size;
|
||||||
} my_list;
|
} my_list;
|
||||||
|
|
||||||
|
typedef struct preemptive_frames_data
|
||||||
|
{
|
||||||
|
/* Savestate buffer */
|
||||||
|
void* buffer[MAX_RUNAHEAD_FRAMES];
|
||||||
|
size_t state_size;
|
||||||
|
|
||||||
|
/* Number of latency frames to remove */
|
||||||
|
uint8_t frames;
|
||||||
|
|
||||||
|
/* Buffer indexes for replays */
|
||||||
|
uint8_t start_ptr;
|
||||||
|
uint8_t replay_ptr;
|
||||||
|
|
||||||
|
/* Frame count since buffer init/reset */
|
||||||
|
uint64_t frame_count;
|
||||||
|
|
||||||
|
/* Input states. Replays triggered on changes */
|
||||||
|
int16_t joypad_state[MAX_USERS];
|
||||||
|
int16_t analog_state[MAX_USERS][20];
|
||||||
|
int16_t ptrdev_state[MAX_USERS][4];
|
||||||
|
|
||||||
|
/* Pointing device requested */
|
||||||
|
uint8_t ptr_dev[MAX_USERS];
|
||||||
|
/* Mask of analog states requested */
|
||||||
|
uint32_t analog_mask[MAX_USERS];
|
||||||
|
} preempt_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct runloop
|
struct runloop
|
||||||
@ -197,6 +226,7 @@ struct runloop
|
|||||||
#endif
|
#endif
|
||||||
my_list *runahead_save_state_list;
|
my_list *runahead_save_state_list;
|
||||||
my_list *input_state_list;
|
my_list *input_state_list;
|
||||||
|
preempt_t *preempt_data;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_REWIND
|
#ifdef HAVE_REWIND
|
||||||
@ -208,6 +238,7 @@ struct runloop
|
|||||||
struct retro_subsystem_info subsystem_data[SUBSYSTEM_MAX_SUBSYSTEMS];
|
struct retro_subsystem_info subsystem_data[SUBSYSTEM_MAX_SUBSYSTEMS];
|
||||||
struct retro_callbacks retro_ctx; /* ptr alignment */
|
struct retro_callbacks retro_ctx; /* ptr alignment */
|
||||||
msg_queue_t msg_queue; /* ptr alignment */
|
msg_queue_t msg_queue; /* ptr alignment */
|
||||||
|
retro_input_poll_t input_poll_callback_original; /* ptr alignment */
|
||||||
retro_input_state_t input_state_callback_original; /* ptr alignment */
|
retro_input_state_t input_state_callback_original; /* ptr alignment */
|
||||||
#ifdef HAVE_RUNAHEAD
|
#ifdef HAVE_RUNAHEAD
|
||||||
function_t retro_reset_callback_original; /* ptr alignment */
|
function_t retro_reset_callback_original; /* ptr alignment */
|
||||||
@ -384,6 +415,9 @@ void runloop_event_deinit_core(void);
|
|||||||
|
|
||||||
#ifdef HAVE_RUNAHEAD
|
#ifdef HAVE_RUNAHEAD
|
||||||
void runloop_runahead_clear_variables(runloop_state_t *runloop_st);
|
void runloop_runahead_clear_variables(runloop_state_t *runloop_st);
|
||||||
|
|
||||||
|
bool runloop_preempt_init(void);
|
||||||
|
void runloop_preempt_deinit(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool runloop_event_init_core(
|
bool runloop_event_init_core(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user