Variable BFI

BFI support added for 180hz / 240hz / etc. Solves issue with image retention from voltage issues at 120hz BFI. Also disabled BFI while in menu, as if set to an incorrect value for the current refresh rate, could cause severe flickering and difficulty reverting to the correct value.
This commit is contained in:
Ophidon 2020-09-18 11:57:32 -04:00
parent 45bef61e36
commit 2f36c94f3f
16 changed files with 120 additions and 88 deletions

View File

@ -259,12 +259,13 @@
*/
#define DEFAULT_FRAME_DELAY 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).
/* Inserts black frame(s) inbetween frames.
* Useful for Higher Hz monitors (set to multiples of 60 Hz) 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 multiple of 60 Hz).
*/
#define DEFAULT_BLACK_FRAME_INSERTION false
#define DEFAULT_BLACK_FRAME_INSERTION 0
/* Uses a custom swap interval for VSync.
* Set this to effectively halve monitor refresh rate.

View File

@ -1466,7 +1466,6 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, DEFAULT_VSYNC, false);
SETTING_BOOL("video_adaptive_vsync", &settings->bools.video_adaptive_vsync, true, DEFAULT_ADAPTIVE_VSYNC, false);
SETTING_BOOL("video_hard_sync", &settings->bools.video_hard_sync, true, DEFAULT_HARD_SYNC, false);
SETTING_BOOL("video_black_frame_insertion", &settings->bools.video_black_frame_insertion, true, DEFAULT_BLACK_FRAME_INSERTION, false);
SETTING_BOOL("video_disable_composition", &settings->bools.video_disable_composition, true, DEFAULT_DISABLE_COMPOSITION, false);
SETTING_BOOL("pause_nonactive", &settings->bools.pause_nonactive, true, DEFAULT_PAUSE_NONACTIVE, false);
SETTING_BOOL("video_gpu_screenshot", &settings->bools.video_gpu_screenshot, true, DEFAULT_GPU_SCREENSHOT, false);
@ -2008,6 +2007,7 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("core_updater_auto_backup_history_size", &settings->uints.core_updater_auto_backup_history_size, true, DEFAULT_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, false);
SETTING_UINT("video_black_frame_insertion", &settings->uints.video_black_frame_insertion, true, DEFAULT_BLACK_FRAME_INSERTION, false);
*size = count;
return tmp;

View File

@ -269,6 +269,7 @@ typedef struct settings
unsigned ai_service_source_lang;
unsigned core_updater_auto_backup_history_size;
unsigned video_black_frame_insertion;
} uints;
struct
@ -447,7 +448,6 @@ typedef struct settings
bool video_vsync;
bool video_adaptive_vsync;
bool video_hard_sync;
bool video_black_frame_insertion;
bool video_vfilter;
bool video_smooth;
bool video_ctx_scaling;

View File

@ -1600,7 +1600,7 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use,
bool video_window_save_positions = settings->bools.video_window_save_positions;
float video_refresh = settings->floats.video_refresh_rate;
unsigned swap_interval = settings->uints.video_swap_interval;
bool bfi = settings->bools.video_black_frame_insertion;
unsigned bfi = settings->uints.video_black_frame_insertion;
unsigned window_position_x = settings->uints.window_position_x;
unsigned window_position_y = settings->uints.window_position_y;
unsigned window_position_width = settings->uints.window_position_width;
@ -1610,9 +1610,9 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use,
{
/* Windows only reports the refresh rates for modelines as
* an integer, so video_refresh_rate needs to be rounded. Also, account
* for black frame insertion using video_refresh_rate set to half
* 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 ? 2.0f : 1.0f;
float refresh_mod = bfi + 1.0f;
unsigned refresh = roundf(video_refresh * refresh_mod
* swap_interval);

View File

@ -268,7 +268,7 @@ static bool get_video_mode(
float minimum_fps_diff = 0.0f;
XF86VidModeModeInfo **modes = NULL;
settings_t *settings = config_get_ptr();
bool black_frame_insertion = settings->bools.video_black_frame_insertion;
unsigned black_frame_insertion = settings->uints.video_black_frame_insertion;
float video_refresh_rate = settings->floats.video_refresh_rate;
XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &num_modes, &modes);
@ -283,7 +283,7 @@ static bool get_video_mode(
/* If we use black frame insertion, we fake a 60 Hz monitor
* for 120 Hz one, etc, so try to match that. */
refresh_mod = black_frame_insertion ? 0.5f : 1.0f;
refresh_mod = 1.0f / (black_frame_insertion + 1.0f);
for (i = 0; i < num_modes; i++)
{

View File

@ -1497,7 +1497,7 @@ static bool d3d8_frame(void *data, const void *frame,
&video_info->osd_stat_params;
const char *stat_text = video_info->stat_text;
bool statistics_show = video_info->statistics_show;
bool black_frame_insertion = video_info->black_frame_insertion;
unsigned black_frame_insertion = video_info->black_frame_insertion;
#ifdef HAVE_MENU
bool menu_is_alive = video_info->menu_is_alive;
#endif
@ -1538,14 +1538,6 @@ static bool d3d8_frame(void *data, const void *frame,
d3d8_set_viewports(d3d->dev, &screen_vp);
d3d8_clear(d3d->dev, 0, 0, D3DCLEAR_TARGET, 0, 1, 0);
/* Insert black frame first, so we
* can screenshot, etc. */
if (black_frame_insertion)
{
if (!d3d8_swap(d3d, d3d->dev) || d3d->needs_restore)
return true;
d3d8_clear(d3d->dev, 0, 0, D3DCLEAR_TARGET, 0, 1, 0);
}
if (!d3d8_renderchain_render(
d3d,
@ -1556,6 +1548,16 @@ static bool d3d8_frame(void *data, const void *frame,
return false;
}
if (black_frame_insertion && !d3d->menu->enabled)
{
for ( int i = 0; i < video_info->black_frame_insertion; ++i)
{
if (!d3d8_swap(d3d, d3d->dev) || d3d->needs_restore)
return true;
d3d8_clear(d3d->dev, 0, 0, D3DCLEAR_TARGET, 0, 1, 0);
}
}
#ifdef HAVE_MENU
if (d3d->menu && d3d->menu->enabled)
{

View File

@ -1532,7 +1532,7 @@ static bool d3d9_frame(void *data, const void *frame,
unsigned width = video_info->width;
unsigned height = video_info->height;
bool statistics_show = video_info->statistics_show;
bool black_frame_insertion = video_info->black_frame_insertion;
unsigned black_frame_insertion = video_info->black_frame_insertion;
struct font_params *osd_params = (struct font_params*)
&video_info->osd_stat_params;
const char *stat_text = video_info->stat_text;
@ -1581,15 +1581,6 @@ static bool d3d9_frame(void *data, const void *frame,
d3d9_set_viewports(d3d->dev, &screen_vp);
d3d9_clear(d3d->dev, 0, 0, D3DCLEAR_TARGET, 0, 1, 0);
/* Insert black frame first, so we
* can screenshot, etc. */
if (black_frame_insertion)
{
if (!d3d9_swap(d3d, d3d->dev) || d3d->needs_restore)
return true;
d3d9_clear(d3d->dev, 0, 0, D3DCLEAR_TARGET, 0, 1, 0);
}
if (!d3d->renderchain_driver->render(
d3d, frame, frame_width, frame_height,
pitch, d3d->dev_rotation))
@ -1597,6 +1588,16 @@ static bool d3d9_frame(void *data, const void *frame,
RARCH_ERR("[D3D9]: Failed to render scene.\n");
return false;
}
if (black_frame_insertion && !d3d->menu->enabled)
{
for ( int i = 0; i < video_info->black_frame_insertion; ++i)
{
if (!d3d9_swap(d3d, d3d->dev) || d3d->needs_restore)
return true;
d3d9_clear(d3d->dev, 0, 0, D3DCLEAR_TARGET, 0, 1, 0);
}
}
#ifdef HAVE_MENU
if (d3d->menu && d3d->menu->enabled)

View File

@ -2808,6 +2808,7 @@ static bool gl2_frame(void *data, const void *frame,
bool use_rgba = video_info->use_rgba;
bool statistics_show = video_info->statistics_show;
bool msg_bgcolor_enable = video_info->msg_bgcolor_enable;
unsigned black_frame_insertion = video_info->black_frame_insertion;
bool input_driver_nonblock_state = video_info->input_driver_nonblock_state;
bool hard_sync = video_info->hard_sync;
unsigned hard_sync_frames = video_info->hard_sync_frames;
@ -2823,7 +2824,6 @@ static bool gl2_frame(void *data, const void *frame,
#ifndef EMSCRIPTEN
bool runloop_is_slowmotion = video_info->runloop_is_slowmotion;
bool runloop_is_paused = video_info->runloop_is_paused;
bool black_frame_insertion = video_info->black_frame_insertion;
#endif
if (!gl)
@ -3088,24 +3088,31 @@ static bool gl2_frame(void *data, const void *frame,
#endif
gl2_pbo_async_readback(gl);
/* Emscripten has to do black frame insertion in its main loop */
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
/* Emscripten has to do black frame insertion in its main loop */
#ifndef EMSCRIPTEN
/* Disable BFI during fast forward, slow-motion,
* and pause to prevent flicker. */
if (
if (
black_frame_insertion
&& !input_driver_nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused)
{
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
glClear(GL_COLOR_BUFFER_BIT);
}
#endif
&& !runloop_is_paused
&& !gl->menu_texture_enable)
{
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
for (int i = 0; i < black_frame_insertion; ++i)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
}
}
#endif
/* check if we are fast forwarding or in menu,
* if we are ignore hard sync */

View File

@ -899,7 +899,11 @@ static bool gl1_gfx_frame(void *data, const void *frame,
4, GL_RGBA, GL_UNSIGNED_BYTE,
gl1->readback_buffer_screenshot);
/* Emscripten has to do black frame insertion in its main loop */
if (gl1->ctx_driver->swap_buffers)
gl1->ctx_driver->swap_buffers(gl1->ctx_data);
/* Emscripten has to do black frame insertion in its main loop */
#ifndef EMSCRIPTEN
/* Disable BFI during fast forward, slow-motion,
* and pause to prevent flicker. */
@ -907,16 +911,20 @@ static bool gl1_gfx_frame(void *data, const void *frame,
video_info->black_frame_insertion
&& !video_info->input_driver_nonblock_state
&& !video_info->runloop_is_slowmotion
&& !video_info->runloop_is_paused)
&& !video_info->runloop_is_paused
&& !gl1->menu_texture_enable)
{
if (gl1->ctx_driver->swap_buffers)
gl1->ctx_driver->swap_buffers(gl1->ctx_data);
glClear(GL_COLOR_BUFFER_BIT);
}
#endif
if (gl1->ctx_driver->swap_buffers)
gl1->ctx_driver->swap_buffers(gl1->ctx_data);
for (int i = 0; i < video_info->black_frame_insertion; ++i)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (gl1->ctx_driver->swap_buffers)
gl1->ctx_driver->swap_buffers(gl1->ctx_data);
}
}
#endif
/* check if we are fast forwarding or in menu, if we are ignore hard sync */
if (hard_sync

View File

@ -1853,7 +1853,8 @@ static bool gl_core_frame(void *data, const void *frame,
const char *stat_text = video_info->stat_text;
bool statistics_show = video_info->statistics_show;
bool msg_bgcolor_enable = video_info->msg_bgcolor_enable;
bool black_frame_insertion = video_info->black_frame_insertion;
unsigned black_frame_insertion = video_info->black_frame_insertion;
unsigned hard_sync_frames = video_info->hard_sync_frames;
bool runloop_is_paused = video_info->runloop_is_paused;
bool runloop_is_slowmotion = video_info->runloop_is_slowmotion;
@ -1989,22 +1990,33 @@ static bool gl_core_frame(void *data, const void *frame,
gl_core_pbo_async_readback(gl);
}
/* Disable BFI during fast forward, slow-motion,
* and pause to prevent flicker. */
if (
black_frame_insertion
&& !input_driver_nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused)
{
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
glClear(GL_COLOR_BUFFER_BIT);
}
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
/* Emscripten has to do black frame insertion in its main loop */
#ifndef EMSCRIPTEN
/* Disable BFI during fast forward, slow-motion,
* and pause to prevent flicker. */
if (
black_frame_insertion
&& !input_driver_nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& !gl->menu_texture_enable)
{
for (int i = 0; i < black_frame_insertion; ++i)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
}
}
#endif
if (hard_sync &&
!input_driver_nonblock_state &&
!gl->menu_texture_enable)

View File

@ -1724,7 +1724,7 @@ static bool vulkan_frame(void *data, const void *frame,
unsigned height = video_info->height;
bool statistics_show = video_info->statistics_show;
const char *stat_text = video_info->stat_text;
bool black_frame_insertion = video_info->black_frame_insertion;
unsigned black_frame_insertion = video_info->black_frame_insertion;
bool input_driver_nonblock_state = video_info->input_driver_nonblock_state;
bool runloop_is_slowmotion = video_info->runloop_is_slowmotion;
bool runloop_is_paused = video_info->runloop_is_paused;
@ -2258,18 +2258,22 @@ static bool vulkan_frame(void *data, const void *frame,
vk->should_resize = false;
}
vulkan_check_swapchain(vk);
vulkan_check_swapchain(vk);
/* Disable BFI during fast forward, slow-motion,
* and pause to prevent flicker. */
if (
backbuffer->image != VK_NULL_HANDLE
backbuffer->image != VK_NULL_HANDLE
&& vk->context->has_acquired_swapchain
&& black_frame_insertion
&& !input_driver_nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused)
vulkan_inject_black_frame(vk, video_info, vk->ctx_data);
&& !runloop_is_paused
&& !vk->menu.enable)
for ( int i = 0; i < black_frame_insertion; ++i)
{
vulkan_inject_black_frame(vk, video_info, vk->ctx_data);
}
/* Vulkan doesn't directly support swap_interval > 1,
* so we fake it by duping out more frames. */

View File

@ -620,7 +620,7 @@ static bool gfx_ctx_drm_set_video_mode(void *data,
struct drm_fb *fb = NULL;
gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data;
settings_t *settings = config_get_ptr();
bool black_frame_insertion = settings->bools.video_black_frame_insertion;
unsigned black_frame_insertion = settings->uints.video_black_frame_insertion;
float video_refresh_rate = settings->floats.video_refresh_rate;
if (!drm)
@ -631,8 +631,7 @@ static bool gfx_ctx_drm_set_video_mode(void *data,
/* If we use black frame insertion,
* we fake a 60 Hz monitor for 120 Hz one,
* etc, so try to match that. */
refresh_mod = black_frame_insertion
? 0.5f : 1.0f;
refresh_mod = 1.0f / (black_frame_insertion + 1.0f);
/* Find desired video mode, and use that.
* If not fullscreen, we get desired windowed size,

View File

@ -5673,7 +5673,7 @@ unsigned menu_displaylist_build_list(
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION,
PARSE_ONLY_BOOL, false) == 0)
PARSE_ONLY_UINT, false) == 0)
count++;
#ifdef HAVE_SCREENSHOTS
if (video_driver_supports_viewport_read())

View File

@ -10823,23 +10823,21 @@ static bool setting_append_list(
#if !defined(RARCH_MOBILE)
if (video_driver_test_all_flags(GFX_CTX_FLAGS_BLACK_FRAME_INSERTION))
{
CONFIG_BOOL(
CONFIG_UINT(
list, list_info,
&settings->bools.video_black_frame_insertion,
&settings->uints.video_black_frame_insertion,
MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION,
DEFAULT_BLACK_FRAME_INSERTION,
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
);
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED);
}
general_read_handler);
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
menu_settings_list_current_add_range(list, list_info, 0, 5, 1, true, true);
}
#endif
END_SUB_GROUP(list, list_info, parent_group);
START_SUB_GROUP(

View File

@ -17842,7 +17842,7 @@ void emscripten_mainloop(void)
static unsigned emscripten_frame_count = 0;
struct rarch_state *p_rarch = &rarch_st;
settings_t *settings = p_rarch->configuration_settings;
bool black_frame_insertion = settings->bools.video_black_frame_insertion;
bool black_frame_insertion = settings->uints.video_black_frame_insertion;
bool input_driver_nonblock_state = p_rarch->input_driver_nonblock_state;
bool runloop_is_slowmotion = p_rarch->runloop_slowmotion;
bool runloop_is_paused = p_rarch->runloop_paused;
@ -17859,7 +17859,7 @@ void emscripten_mainloop(void)
&& !runloop_is_slowmotion
&& !runloop_is_paused)
{
if ((emscripten_frame_count & 1) == 0)
if ((emscripten_frame_count % (black_frame_insertion+1)) != 0)
{
glClear(GL_COLOR_BUFFER_BIT);
if (p_rarch->current_video_context.swap_buffers)
@ -33869,7 +33869,7 @@ void video_driver_build_info(video_frame_info_t *video_info)
video_info->crt_switch_resolution_super = settings->uints.crt_switch_resolution_super;
video_info->crt_switch_center_adjust = settings->ints.crt_switch_center_adjust;
video_info->crt_switch_porch_adjust = settings->ints.crt_switch_porch_adjust;
video_info->black_frame_insertion = settings->bools.video_black_frame_insertion;
video_info->black_frame_insertion = settings->uints.video_black_frame_insertion;
video_info->hard_sync = settings->bools.video_hard_sync;
video_info->hard_sync_frames = settings->uints.video_hard_sync_frames;
video_info->fps_show = settings->bools.video_fps_show;
@ -39740,7 +39740,7 @@ static enum runloop_state runloop_check_state(
if (p_rarch->runloop_slowmotion)
{
if (settings->bools.video_black_frame_insertion)
if (settings->uints.video_black_frame_insertion)
if (!p_rarch->runloop_idle)
video_driver_cached_frame();

View File

@ -1137,6 +1137,7 @@ typedef struct video_frame_info
unsigned custom_vp_height;
unsigned custom_vp_full_width;
unsigned custom_vp_full_height;
unsigned black_frame_insertion;
float menu_wallpaper_opacity;
float menu_framebuffer_opacity;
@ -1178,7 +1179,6 @@ typedef struct video_frame_info
bool widgets_is_rewinding;
bool input_menu_swap_ok_cancel_buttons;
bool input_driver_nonblock_state;
bool black_frame_insertion;
bool hard_sync;
bool fps_show;
bool memory_show;