diff --git a/config.def.h b/config.def.h index f86e82610a..909f386bca 100644 --- a/config.def.h +++ b/config.def.h @@ -219,6 +219,10 @@ static const unsigned hard_sync_frames = 0; // Useful for 120 Hz monitors who want to play 60 Hz material with eliminated ghosting. video_refresh_rate should still be configured as if it is a 60 Hz monitor (divide refresh rate by 2). static bool black_frame_insertion = false; +// Uses a custom swap interval for VSync. +// Set this to effectively halve monitor refresh rate. +static unsigned swap_interval = 1; + // Threaded video. Will possibly increase performance significantly at cost of worse synchronization and latency. static const bool video_threaded = false; diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h index 9839c7718b..8a3a552ae5 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -119,6 +119,7 @@ typedef enum RGUI_SETTINGS_VIDEO_HARD_SYNC, RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES, RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION, + RGUI_SETTINGS_VIDEO_SWAP_INTERVAL, RGUI_SETTINGS_VIDEO_REFRESH_RATE_AUTO, RGUI_SETTINGS_VIDEO_OPTIONS_LAST, #ifdef HAVE_SHADER_MANAGER diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index 4fbec52210..9bb5c70d08 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -605,6 +605,9 @@ static void render_text(rgui_handle_t *rgui) case RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION: strlcpy(type_str, g_settings.video.black_frame_insertion ? "ON" : "OFF", sizeof(type_str)); break; + case RGUI_SETTINGS_VIDEO_SWAP_INTERVAL: + snprintf(type_str, sizeof(type_str), "%u", g_settings.video.swap_interval); + break; case RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES: snprintf(type_str, sizeof(type_str), "%u", g_settings.video.hard_sync_frames); break; @@ -1513,6 +1516,7 @@ static void rgui_settings_video_options_populate_entries(rgui_handle_t *rgui) rgui_list_push(rgui->selection_buf, "Hard GPU Sync", RGUI_SETTINGS_VIDEO_HARD_SYNC, 0); rgui_list_push(rgui->selection_buf, "Hard GPU Sync Frames", RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES, 0); rgui_list_push(rgui->selection_buf, "Black Frame Insertion", RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION, 0); + rgui_list_push(rgui->selection_buf, "VSync Swap Interval", RGUI_SETTINGS_VIDEO_SWAP_INTERVAL, 0); rgui_list_push(rgui->selection_buf, "Estimated Monitor FPS", RGUI_SETTINGS_VIDEO_REFRESH_RATE_AUTO, 0); } @@ -1958,6 +1962,36 @@ static int video_option_toggle_setting(rgui_handle_t *rgui, unsigned setting, rg } break; + case RGUI_SETTINGS_VIDEO_SWAP_INTERVAL: + { + unsigned old = g_settings.video.swap_interval; + switch (action) + { + case RGUI_ACTION_START: + g_settings.video.swap_interval = 1; + break; + + case RGUI_ACTION_LEFT: + g_settings.video.swap_interval--; + break; + + case RGUI_ACTION_RIGHT: + case RGUI_ACTION_OK: + g_settings.video.swap_interval++; + break; + + default: + break; + } + + g_settings.video.swap_interval = min(g_settings.video.swap_interval, 4); + g_settings.video.swap_interval = max(g_settings.video.swap_interval, 1); + if (old != g_settings.video.swap_interval && driver.video && driver.video_data) + video_set_nonblock_state_func(false); // This will update the current swap interval. Since we're in RGUI now, always apply VSync. + + break; + } + case RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES: switch (action) { diff --git a/general.h b/general.h index 34b52acdfb..0d187b688b 100644 --- a/general.h +++ b/general.h @@ -160,6 +160,7 @@ struct settings bool vsync; bool hard_sync; bool black_frame_insertion; + unsigned swap_interval; unsigned hard_sync_frames; bool smooth; bool force_aspect; diff --git a/gfx/context/drm_egl_ctx.c b/gfx/context/drm_egl_ctx.c index 67bda39585..995a9301c2 100644 --- a/gfx/context/drm_egl_ctx.c +++ b/gfx/context/drm_egl_ctx.c @@ -93,6 +93,8 @@ static void sighandler(int sig) static void gfx_ctx_swap_interval(unsigned interval) { g_interval = interval; + if (interval > 1) + RARCH_WARN("[KMS/EGL]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); } static void gfx_ctx_check_window(bool *quit, diff --git a/gfx/d3d9/d3d9.cpp b/gfx/d3d9/d3d9.cpp index 31eeb062be..a59aa5647c 100644 --- a/gfx/d3d9/d3d9.cpp +++ b/gfx/d3d9/d3d9.cpp @@ -145,7 +145,20 @@ void D3DVideo::make_d3dpp(const video_info_t &info, D3DPRESENT_PARAMETERS &d3dpp d3dpp.Windowed = g_settings.video.windowed_fullscreen || !info.fullscreen; - d3dpp.PresentationInterval = info.vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; + if (info.vsync) + { + switch (g_settings.video.swap_interval) + { + default: + case 1: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; break; + case 2: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_TWO; break; + case 3: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_THREE; break; + case 4: d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_FOUR; break; + } + } + else + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hWnd; d3dpp.BackBufferCount = 2; diff --git a/gfx/gl.c b/gfx/gl.c index fc8d5904ed..cc622d5726 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1628,7 +1628,7 @@ static void gl_set_nonblock_state(void *data, bool state) gl_t *gl = (gl_t*)data; (void)gl; - context_swap_interval_func(state ? 0 : 1); + context_swap_interval_func(state ? 0 : g_settings.video.swap_interval); } static bool resolve_extensions(gl_t *gl) diff --git a/settings.c b/settings.c index b68df94c86..fd95524334 100644 --- a/settings.c +++ b/settings.c @@ -169,6 +169,7 @@ void config_set_defaults(void) g_settings.video.hard_sync = hard_sync; g_settings.video.hard_sync_frames = hard_sync_frames; g_settings.video.black_frame_insertion = black_frame_insertion; + g_settings.video.swap_interval = swap_interval; g_settings.video.threaded = video_threaded; g_settings.video.smooth = video_smooth; g_settings.video.force_aspect = force_aspect; @@ -493,6 +494,9 @@ bool config_load_file(const char *path) g_settings.video.hard_sync_frames = 3; CONFIG_GET_BOOL(video.black_frame_insertion, "video_black_frame_insertion"); + CONFIG_GET_INT(video.swap_interval, "video_swap_interval"); + g_settings.video.swap_interval = max(g_settings.video.swap_interval, 1); + g_settings.video.swap_interval = min(g_settings.video.swap_interval, 4); CONFIG_GET_BOOL(video.threaded, "video_threaded"); CONFIG_GET_BOOL(video.smooth, "video_smooth"); CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect"); @@ -979,6 +983,7 @@ bool config_save_file(const char *path) config_set_bool(conf, "video_hard_sync", g_settings.video.hard_sync); config_set_int(conf, "video_hard_sync_frames", g_settings.video.hard_sync_frames); config_set_bool(conf, "video_black_frame_insertion", g_settings.video.black_frame_insertion); + config_set_int(conf, "video_swap_interval", g_settings.video.swap_interval); config_set_int(conf, "aspect_ratio_index", g_settings.video.aspect_ratio_idx); config_set_string(conf, "audio_device", g_settings.audio.device); config_set_bool(conf, "audio_rate_control", g_settings.audio.rate_control);