Merge pull request #13927 from jdgleaver/auto-video-swap-interval

Enable automatic configuration of 'VSync Swap Interval'
This commit is contained in:
LibretroAdmin 2022-05-13 14:17:56 +01:00 committed by GitHub
commit dc0054a747
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 152 additions and 24 deletions

View File

@ -954,10 +954,10 @@ float audio_driver_monitor_adjust_system_rates(
unsigned video_swap_interval,
float audio_max_timing_skew)
{
float inp_sample_rate = input_sample_rate;
const float target_video_sync_rate = video_refresh_rate
/ video_swap_interval;
float timing_skew =
float inp_sample_rate = input_sample_rate;
float target_video_sync_rate = video_refresh_rate
/ (float)video_swap_interval;
float timing_skew =
fabs(1.0f - input_fps / target_video_sync_rate);
if (timing_skew <= audio_max_timing_skew)
return (inp_sample_rate * target_video_sync_rate / input_fps);

View File

@ -1740,7 +1740,7 @@ void command_event_reinit(const int flags)
struct menu_state *menu_st = menu_state_get_ptr();
bool video_fullscreen = settings->bools.video_fullscreen;
bool adaptive_vsync = settings->bools.video_adaptive_vsync;
unsigned swap_interval = settings->uints.video_swap_interval;
unsigned swap_interval_config = settings->uints.video_swap_interval;
#endif
enum input_game_focus_cmd_type
game_focus_cmd = GAME_FOCUS_CMD_REAPPLY;
@ -1775,6 +1775,6 @@ void command_event_reinit(const int flags)
video_st->data, false,
video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
adaptive_vsync,
swap_interval);
runloop_get_video_swap_interval(swap_interval_config));
#endif
}

View File

@ -3520,7 +3520,7 @@ static bool config_load_file(global_t *global,
if (settings->uints.video_frame_delay > MAXIMUM_FRAME_DELAY)
settings->uints.video_frame_delay = MAXIMUM_FRAME_DELAY;
settings->uints.video_swap_interval = MAX(settings->uints.video_swap_interval, 1);
settings->uints.video_swap_interval = MAX(settings->uints.video_swap_interval, 0);
settings->uints.video_swap_interval = MIN(settings->uints.video_swap_interval, 4);
audio_set_float(AUDIO_ACTION_VOLUME_GAIN, settings->floats.audio_volume);

View File

@ -308,6 +308,18 @@ static void driver_adjust_system_rates(
double input_sample_rate = info->sample_rate;
double input_fps = info->fps;
/* Update video swap interval if automatic
* switching is enabled */
runloop_set_video_swap_interval(
vrr_runloop_enable,
video_st->crt_switching_active,
video_swap_interval,
audio_max_timing_skew,
video_refresh_rate,
input_fps);
video_swap_interval = runloop_get_video_swap_interval(
video_swap_interval);
if (input_sample_rate > 0.0)
{
audio_driver_state_t *audio_st = audio_state_get_ptr();
@ -341,6 +353,7 @@ static void driver_adjust_system_rates(
video_refresh_rate,
vrr_runloop_enable,
audio_max_timing_skew,
video_swap_interval,
input_fps))
{
/* We won't be able to do VSync reliably
@ -389,7 +402,8 @@ void driver_set_nonblock_state(void)
bool audio_sync = settings->bools.audio_sync;
bool video_vsync = settings->bools.video_vsync;
bool adaptive_vsync = settings->bools.video_adaptive_vsync;
unsigned swap_interval = settings->uints.video_swap_interval;
unsigned swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
bool video_driver_active = video_st->active;
bool audio_driver_active = audio_st->active;
bool runloop_force_nonblock = runloop_st->force_nonblock;

View File

@ -702,7 +702,8 @@ void d3d9_make_d3dpp(d3d9_video_t *d3d,
if (info->vsync)
{
settings_t *settings = config_get_ptr();
unsigned video_swap_interval = settings->uints.video_swap_interval;
unsigned video_swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
switch (video_swap_interval)
{

View File

@ -584,7 +584,8 @@ static void d3d8_make_d3dpp(void *data,
if (info->vsync)
{
settings_t *settings = config_get_ptr();
unsigned video_swap_interval = settings->uints.video_swap_interval;
unsigned video_swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
switch (video_swap_interval)
{

View File

@ -894,12 +894,16 @@ bool video_driver_monitor_adjust_system_rates(
float video_refresh_rate,
bool vrr_runloop_enable,
float audio_max_timing_skew,
unsigned video_swap_interval,
double input_fps)
{
float target_video_sync_rate = timing_skew_hz
/ (float)video_swap_interval;
if (!vrr_runloop_enable)
{
float timing_skew = fabs(
1.0f - input_fps / timing_skew_hz);
1.0f - input_fps / target_video_sync_rate);
/* We don't want to adjust pitch too much. If we have extreme cases,
* just don't readjust at all. */
if (timing_skew <= audio_max_timing_skew)
@ -909,7 +913,7 @@ bool video_driver_monitor_adjust_system_rates(
video_refresh_rate,
(float)input_fps);
}
return input_fps <= timing_skew_hz;
return input_fps <= target_video_sync_rate;
}
void video_driver_reset_custom_viewport(settings_t *settings)
@ -1166,7 +1170,8 @@ void video_switch_refresh_rate_maybe(
float refresh_rate = *refresh_rate_suggest;
float video_refresh_rate = settings->floats.video_refresh_rate;
unsigned crt_switch_resolution = settings->uints.crt_switch_resolution;
unsigned video_swap_interval = settings->uints.video_swap_interval;
unsigned video_swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
unsigned video_bfi = settings->uints.video_black_frame_insertion;
bool video_fullscreen = settings->bools.video_fullscreen;
bool video_windowed_full = settings->bools.video_windowed_fullscreen;
@ -3432,7 +3437,8 @@ bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
!runloop_st->force_nonblock;
video.force_aspect = settings->bools.video_force_aspect;
video.font_enable = settings->bools.video_font_enable;
video.swap_interval = settings->uints.video_swap_interval;
video.swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
video.adaptive_vsync = settings->bools.video_adaptive_vsync;
#ifdef GEKKO
video.viwidth = settings->uints.video_viwidth;

View File

@ -1177,6 +1177,7 @@ bool video_driver_monitor_adjust_system_rates(
float video_refresh_rate,
bool vrr_runloop_enable,
float audio_max_timing_skew,
unsigned video_swap_interval,
double input_fps);
void crt_switch_driver_refresh(void);

View File

@ -1998,7 +1998,11 @@ MSG_HASH(
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL,
"Use a custom swap interval for VSync. Set this to effectively halve monitor refresh rate."
"Use a custom swap interval for VSync. Effectively reduces monitor refresh rate by the specified factor. 'Auto' sets factor based on core-reported frame rate, providing improved frame pacing when running e.g. 30 fps content on a 60 Hz display or 60 fps content on a 120 Hz display."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL_AUTO,
"Auto"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_ADAPTIVE_VSYNC,

View File

@ -6726,7 +6726,6 @@ void menu_driver_toggle(
bool input_overlay_enable = false;
#endif
bool video_adaptive_vsync = false;
bool video_swap_interval = false;
if (settings)
{
@ -6744,7 +6743,6 @@ void menu_driver_toggle(
input_overlay_enable = settings->bools.input_overlay_enable;
#endif
video_adaptive_vsync = settings->bools.video_adaptive_vsync;
video_swap_interval = settings->uints.video_swap_interval;
}
if (on)
@ -6796,15 +6794,18 @@ void menu_driver_toggle(
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
/* Menu should always run with vsync on. */
/* Menu should always run with vsync on and
* a video swap interval of 1 */
if (current_video->set_nonblock_state)
{
current_video->set_nonblock_state(
video_driver_data,
false,
video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC) &&
video_adaptive_vsync,
video_swap_interval
1
);
}
/* Stop all rumbling before entering the menu. */
command_event(CMD_EVENT_RUMBLE_STOP, NULL);

View File

@ -6319,6 +6319,18 @@ static void setting_get_string_representation_uint_cheat_browse_address(
}
#endif
static void setting_get_string_representation_video_swap_interval(rarch_setting_t *setting,
char *s, size_t len)
{
if (!setting)
return;
if (*setting->value.target.unsigned_integer == 0)
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL_AUTO), len);
else
snprintf(s, len, "%u", *setting->value.target.unsigned_integer);
}
static void setting_get_string_representation_uint_video_rotation(rarch_setting_t *setting,
char *s, size_t len)
{
@ -12430,9 +12442,10 @@ static bool setting_append_list(
general_write_handler,
general_read_handler);
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
(*list)[list_info->index - 1].offset_by = 1;
MENU_SETTINGS_LIST_CURRENT_ADD_CMD(list, list_info, CMD_EVENT_VIDEO_SET_BLOCKING_STATE);
menu_settings_list_current_add_range(list, list_info, 1, 4, 1, true, true);
(*list)[list_info->index - 1].get_string_representation =
&setting_get_string_representation_video_swap_interval;
MENU_SETTINGS_LIST_CURRENT_ADD_CMD(list, list_info, CMD_EVENT_REINIT);
menu_settings_list_current_add_range(list, list_info, 0, 4, 1, true, true);
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_CMD_APPLY_AUTO);
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED);

View File

@ -1138,6 +1138,8 @@ enum msg_hash_enums
MENU_LABEL(VIDEO_THREADED),
MENU_LABEL(VIDEO_SWAP_INTERVAL),
MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL_AUTO,
MENU_LABEL(VIDEO_FULLSCREEN),
MENU_LABEL(VIDEO_MONITOR_INDEX),
MENU_LABEL(VIDEO_WIIU_PREFER_DRC),

View File

@ -2405,7 +2405,8 @@ bool command_event(enum event_command cmd, void *data)
case CMD_EVENT_VIDEO_SET_BLOCKING_STATE:
{
bool adaptive_vsync = settings->bools.video_adaptive_vsync;
unsigned swap_interval = settings->uints.video_swap_interval;
unsigned swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
video_driver_state_t
*video_st = video_state_get_ptr();
@ -5786,6 +5787,7 @@ bool retroarch_ctl(enum rarch_ctl_state state, void *data)
input_game_focus_free();
runloop_fastmotion_override_free();
runloop_core_options_cb_free();
runloop_st->video_swap_interval_auto = 1;
memset(&input_st->analog_requested, 0,
sizeof(input_st->analog_requested));
}

View File

@ -3589,6 +3589,7 @@ static void uninit_libretro_symbols(
input_game_focus_free();
runloop_fastmotion_override_free();
runloop_core_options_cb_free();
runloop_st->video_swap_interval_auto = 1;
camera_st->active = false;
location_st->active = false;
@ -5210,6 +5211,76 @@ float runloop_get_fastforward_ratio(
return settings->floats.fastforward_ratio;
}
void runloop_set_video_swap_interval(
bool vrr_runloop_enable,
bool crt_switching_active,
unsigned swap_interval_config,
float audio_max_timing_skew,
float video_refresh_rate,
double input_fps)
{
runloop_state_t *runloop_st = &runloop_state;
float core_hz = input_fps;
float timing_hz = crt_switching_active ?
input_fps : video_refresh_rate;
float swap_ratio;
unsigned swap_integer;
float timing_skew;
/* If automatic swap interval selection is
* disabled, just record user-set value */
if (swap_interval_config != 0)
{
runloop_st->video_swap_interval_auto =
swap_interval_config;
return;
}
/* > If VRR is enabled, swap interval is irrelevant,
* just set to 1
* > If core fps is higher than display refresh rate,
* set swap interval to 1
* > If core fps or display refresh rate are zero,
* set swap interval to 1 */
if (vrr_runloop_enable ||
(core_hz > timing_hz) ||
(core_hz <= 0.0f) ||
(timing_hz <= 0.0f))
{
runloop_st->video_swap_interval_auto = 1;
return;
}
/* Check whether display refresh rate is an integer
* multiple of core fps (within timing skew tolerance) */
swap_ratio = timing_hz / core_hz;
swap_integer = (unsigned)(swap_ratio + 0.5f);
/* > Sanity check: swap interval must be in the
* range [1,4] - if we are outside this, then
* bail... */
if ((swap_integer < 1) || (swap_integer > 4))
{
runloop_st->video_swap_interval_auto = 1;
return;
}
timing_skew = fabs(1.0f - core_hz / (timing_hz / (float)swap_integer));
runloop_st->video_swap_interval_auto =
(timing_skew <= audio_max_timing_skew) ?
swap_integer : 1;
}
unsigned runloop_get_video_swap_interval(
unsigned swap_interval_config)
{
runloop_state_t *runloop_st = &runloop_state;
return (swap_interval_config == 0) ?
runloop_st->video_swap_interval_auto :
swap_interval_config;
}
unsigned int retroarch_get_rotation(void)
{
settings_t *settings = config_get_ptr();
@ -7634,7 +7705,8 @@ int runloop_iterate(void)
if (settings->bools.video_frame_delay_auto)
{
float refresh_rate = settings->floats.video_refresh_rate;
unsigned video_swap_interval = settings->uints.video_swap_interval;
unsigned video_swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
unsigned video_bfi = settings->uints.video_black_frame_insertion;
unsigned frame_time_interval = 8;
bool frame_time_update =

View File

@ -219,6 +219,7 @@ struct runloop
unsigned perf_ptr_libretro;
unsigned subsystem_current_count;
unsigned entry_state_slot;
unsigned video_swap_interval_auto;
fastmotion_overrides_t fastmotion_override; /* float alignment */
@ -415,6 +416,16 @@ float runloop_get_fastforward_ratio(
settings_t *settings,
struct retro_fastforwarding_override *fastmotion_override);
void runloop_set_video_swap_interval(
bool vrr_runloop_enable,
bool crt_switching_active,
unsigned swap_interval_config,
float audio_max_timing_skew,
float video_refresh_rate,
double input_fps);
unsigned runloop_get_video_swap_interval(
unsigned swap_interval_config);
void runloop_task_msg_queue_push(
retro_task_t *task, const char *msg,
unsigned prio, unsigned duration,