1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-08 12:15:49 +00:00

Merge pull request #12795 from sonninnos/video-rate-switch

Automatic PAL/NTSC refresh rate switch where available
This commit is contained in:
Autechre 2021-09-12 16:15:04 +02:00 committed by GitHub
commit cfcd0a7a0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 5 deletions

View File

@ -1931,8 +1931,7 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use,
* for black frame insertion using video_refresh_rate set to a portion
* of the display refresh rate, as well as higher vsync swap intervals. */
float refresh_mod = bfi + 1.0f;
unsigned refresh = roundf(video_refresh * refresh_mod
* swap_interval);
float refresh_rate = (video_refresh * refresh_mod * swap_interval);
if (windowed_full)
{
@ -1945,7 +1944,7 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use,
*style = WS_POPUP | WS_VISIBLE;
if (!win32_monitor_set_fullscreen(*width, *height,
refresh, current_mon->szDevice)) { }
(int)refresh_rate, current_mon->szDevice)) { }
/* Display settings might have changed, get new coordinates. */
GetMonitorInfo(*hm_to_use, (LPMONITORINFO)current_mon);

View File

@ -239,7 +239,7 @@ static bool win32_display_server_set_resolution(void *data,
if (serv->orig_height == 0)
serv->orig_height = GetSystemMetrics(SM_CYSCREEN);
if (serv->orig_refresh == 0)
serv->orig_refresh = dm.dmDisplayFrequency;
serv->orig_refresh = video_driver_get_refresh_rate();
/* Used to stop super resolution bug */
if (width == dm.dmPelsWidth)

View File

@ -87,6 +87,12 @@ bool video_display_server_can_set_screen_orientation(void);
bool video_display_server_has_resolution_list(void);
bool video_display_server_set_refresh_rate(float hz);
bool video_display_server_has_refresh_rate(float hz);
void video_display_server_restore_refresh_rate(void);
enum rotation video_display_server_get_screen_orientation(void);
extern const video_display_server_t dispserv_win32;

View File

@ -9424,6 +9424,11 @@ static void command_event_deinit_core(
uninit_libretro_symbols(p_rarch, &p_rarch->current_core);
p_rarch->current_core.symbols_inited = false;
/* Restore original refresh rate, if it has been changed
* automatically in SET_SYSTEM_AV_INFO */
if (p_rarch->video_refresh_rate_original)
video_display_server_restore_refresh_rate();
if (reinit)
driver_uninit(p_rarch, DRIVERS_CMD_ALL);
@ -14428,13 +14433,67 @@ static bool rarch_environment_cb(unsigned cmd, void *data)
if (data)
{
settings_t *settings = p_rarch->configuration_settings;
float refresh_rate = (*info)->timing.fps;
unsigned crt_switch_resolution = settings->uints.crt_switch_resolution;
bool video_fullscreen = settings->bools.video_fullscreen;
const bool no_video_reinit = (
bool video_has_resolution_list = video_display_server_has_resolution_list();
bool video_switch_refresh_rate = false;
bool no_video_reinit = true;
/* Refresh rate switch for regular displays */
if (video_has_resolution_list)
{
float refresh_mod = 0.0f;
float video_refresh_rate = settings->floats.video_refresh_rate;
unsigned video_swap_interval = settings->uints.video_swap_interval;
unsigned video_bfi = settings->uints.video_black_frame_insertion;
bool video_windowed_full = settings->bools.video_windowed_fullscreen;
bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
/* Roundings to PAL & NTSC standards */
refresh_rate = (refresh_rate > 54 && refresh_rate < 60) ? 59.94f : refresh_rate;
refresh_rate = (refresh_rate > 49 && refresh_rate < 55) ? 50.00f : refresh_rate;
/* Black frame insertion + swap interval multiplier */
refresh_mod = video_bfi + 1.0f;
refresh_rate = (refresh_rate * refresh_mod * video_swap_interval);
/* Fallback when target refresh rate is not exposed */
if (!video_display_server_has_refresh_rate(refresh_rate))
refresh_rate = (60.0f * refresh_mod * video_swap_interval);
/* Store original refresh rate on automatic change, and
* restore it in deinit_core and main_quit, because not all
* cores announce refresh rate via SET_SYSTEM_AV_INFO */
if (!p_rarch->video_refresh_rate_original)
p_rarch->video_refresh_rate_original = video_refresh_rate;
/* Try to switch display rate when:
* - Not already at correct rate
* - In exclusive fullscreen
* - 'CRT SwitchRes' OFF & 'Sync to Exact Content Framerate' OFF
*/
video_switch_refresh_rate = (
refresh_rate != video_refresh_rate &&
!crt_switch_resolution && !vrr_runloop_enable &&
video_fullscreen && !video_windowed_full);
}
no_video_reinit = (
crt_switch_resolution == 0
&& video_switch_refresh_rate == false
&& data
&& ((*info)->geometry.max_width == av_info->geometry.max_width)
&& ((*info)->geometry.max_height == av_info->geometry.max_height));
/* First set new refresh rate and display rate, then after REINIT do
* another display rate change to make sure the change stays */
if (video_switch_refresh_rate)
{
video_monitor_set_refresh_rate(refresh_rate);
video_display_server_set_refresh_rate(refresh_rate);
}
/* When not doing video reinit, we also must not do input and menu
* reinit, otherwise the input driver crashes and the menu gets
* corrupted. */
@ -14453,6 +14512,9 @@ static bool rarch_environment_cb(unsigned cmd, void *data)
if (no_video_reinit)
video_driver_set_aspect_ratio();
if (video_switch_refresh_rate)
video_display_server_set_refresh_rate(refresh_rate);
/* Cannot continue recording with different parameters.
* Take the easiest route out and just restart the recording. */
if (p_rarch->recording_data)
@ -23883,6 +23945,58 @@ void *video_display_server_get_resolution_list(unsigned *size)
return NULL;
}
bool video_display_server_has_refresh_rate(float hz)
{
unsigned i, size = 0;
bool rate_exists = false;
struct video_display_config *video_list = (struct video_display_config*)
video_display_server_get_resolution_list(&size);
if (video_list)
{
struct rarch_state *p_rarch = &rarch_st;
unsigned video_driver_width = p_rarch->video_driver_width;
unsigned video_driver_height = p_rarch->video_driver_height;
for (i = 0; i < size && !rate_exists; i++)
{
if (video_list[i].width == video_driver_width &&
video_list[i].height == video_driver_height &&
video_list[i].refreshrate == floor(hz))
rate_exists = true;
}
free(video_list);
}
return rate_exists;
}
bool video_display_server_set_refresh_rate(float hz)
{
struct rarch_state *p_rarch = &rarch_st;
if (current_display_server && current_display_server->set_resolution)
return current_display_server->set_resolution(
p_rarch->current_display_server_data, 0, 0, (int)hz,
hz, 0, 0, 0, 0);
return false;
}
void video_display_server_restore_refresh_rate(void)
{
struct rarch_state *p_rarch = &rarch_st;
settings_t *settings = p_rarch->configuration_settings;
float refresh_rate_original = p_rarch->video_refresh_rate_original;
float refresh_rate_current = settings->floats.video_refresh_rate;
if (!refresh_rate_original || refresh_rate_current == refresh_rate_original)
return;
video_monitor_set_refresh_rate(refresh_rate_original);
video_display_server_set_refresh_rate(refresh_rate_original);
}
const char *video_display_server_get_output_options(void)
{
struct rarch_state *p_rarch = &rarch_st;
@ -31492,6 +31606,11 @@ bool retroarch_main_quit(void)
discord_is_inited = false;
#endif
/* Restore original refresh rate, if it has been changed
* automatically in SET_SYSTEM_AV_INFO */
if (p_rarch->video_refresh_rate_original)
video_display_server_restore_refresh_rate();
if (!runloop_state.shutdown_initiated)
{
command_event_save_auto_state(

View File

@ -1542,6 +1542,7 @@ struct rarch_state
float *audio_driver_input_data;
float video_driver_core_hz;
float video_driver_aspect_ratio;
float video_refresh_rate_original;
#ifdef HAVE_AUDIOMIXER
float audio_driver_mixer_volume_gain;