diff --git a/config.def.h b/config.def.h index a677cc2778..f86e82610a 100644 --- a/config.def.h +++ b/config.def.h @@ -215,6 +215,10 @@ static const bool hard_sync = false; // 2: Etc ... static const unsigned hard_sync_frames = 0; +// Inserts a black frame inbetween frames. +// 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; + // 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 a3293785ed..9839c7718b 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -118,6 +118,7 @@ typedef enum RGUI_SETTINGS_VIDEO_VSYNC, RGUI_SETTINGS_VIDEO_HARD_SYNC, RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES, + RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION, 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 7ae5533490..47779775bc 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -598,6 +598,9 @@ static void render_text(rgui_handle_t *rgui) case RGUI_SETTINGS_VIDEO_HARD_SYNC: strlcpy(type_str, g_settings.video.hard_sync ? "ON" : "OFF", sizeof(type_str)); break; + 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_HARD_SYNC_FRAMES: snprintf(type_str, sizeof(type_str), "%u", g_settings.video.hard_sync_frames); break; @@ -1505,6 +1508,7 @@ static void rgui_settings_video_options_populate_entries(rgui_handle_t *rgui) rgui_list_push(rgui->selection_buf, "VSync", RGUI_SETTINGS_VIDEO_VSYNC, 0); 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, "Estimated Monitor FPS", RGUI_SETTINGS_VIDEO_REFRESH_RATE_AUTO, 0); } @@ -1932,6 +1936,24 @@ static int video_option_toggle_setting(rgui_handle_t *rgui, unsigned setting, rg } break; + case RGUI_SETTINGS_VIDEO_BLACK_FRAME_INSERTION: + switch (action) + { + case RGUI_ACTION_START: + g_settings.video.black_frame_insertion = false; + break; + + case RGUI_ACTION_LEFT: + case RGUI_ACTION_RIGHT: + case RGUI_ACTION_OK: + g_settings.video.black_frame_insertion = !g_settings.video.black_frame_insertion; + break; + + default: + break; + } + break; + case RGUI_SETTINGS_VIDEO_HARD_SYNC_FRAMES: switch (action) { diff --git a/general.h b/general.h index 09364943c7..34b52acdfb 100644 --- a/general.h +++ b/general.h @@ -159,6 +159,7 @@ struct settings unsigned fullscreen_y; bool vsync; bool hard_sync; + bool black_frame_insertion; unsigned hard_sync_frames; bool smooth; bool force_aspect; diff --git a/gfx/d3d9/d3d9.cpp b/gfx/d3d9/d3d9.cpp index c4de8cf9c1..31eeb062be 100644 --- a/gfx/d3d9/d3d9.cpp +++ b/gfx/d3d9/d3d9.cpp @@ -614,6 +614,17 @@ bool D3DVideo::frame(const void *frame, dev->SetViewport(&screen_vp); dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0); + // Insert black frame first, so we can screenshot, etc. + if (g_settings.video.black_frame_insertion) + { + if (dev->Present(nullptr, nullptr, nullptr, nullptr) != D3D_OK) + { + needs_restore = true; + return true; + } + dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0); + } + if (!chain->render(frame, width, height, pitch, rotation)) { RARCH_ERR("[D3D9]: Failed to render scene.\n"); diff --git a/gfx/gl.c b/gfx/gl.c index 7a62910a78..fc8d5904ed 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1454,6 +1454,11 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei memcpy(tex_info.coord, gl->tex_coords, sizeof(gl->tex_coords)); glClear(GL_COLOR_BUFFER_BIT); + if (g_settings.video.black_frame_insertion) + { + context_swap_buffers_func(); + glClear(GL_COLOR_BUFFER_BIT); + } if (gl->shader) gl->shader->set_params(width, height, diff --git a/retroarch.cfg b/retroarch.cfg index dafd3b0847..ebf66a1b85 100644 --- a/retroarch.cfg +++ b/retroarch.cfg @@ -89,6 +89,11 @@ # Maximum is 3. # video_hard_sync_frames = 0 +# Inserts a black frame inbetween frames. +# 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). +# video_black_frame_insertion = false + # Use threaded video driver. Using this might improve performance at possible cost of latency and more video stuttering. # video_threaded = false diff --git a/settings.c b/settings.c index 8a9563e2e5..b68df94c86 100644 --- a/settings.c +++ b/settings.c @@ -168,6 +168,7 @@ void config_set_defaults(void) g_settings.video.vsync = vsync; 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.threaded = video_threaded; g_settings.video.smooth = video_smooth; g_settings.video.force_aspect = force_aspect; @@ -491,6 +492,7 @@ bool config_load_file(const char *path) if (g_settings.video.hard_sync_frames > 3) g_settings.video.hard_sync_frames = 3; + CONFIG_GET_BOOL(video.black_frame_insertion, "video_black_frame_insertion"); CONFIG_GET_BOOL(video.threaded, "video_threaded"); CONFIG_GET_BOOL(video.smooth, "video_smooth"); CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect"); @@ -976,6 +978,7 @@ bool config_save_file(const char *path) config_set_bool(conf, "video_vsync", g_settings.video.vsync); 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, "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);