Squashed commit of the following: (#16142)

commit 793d41c303206b43932ddcefd44a45836def55eb
Author: Ophidon <jrogers2@gmail.com>
Date:   Fri Jan 19 23:12:31 2024 -0500

    Build Fix 2

    Move declarations of iterators.

commit c0e959b3d3cd773a66a17cfe034f08eaa53d525a
Author: Ophidon <jrogers2@gmail.com>
Date:   Fri Jan 19 22:57:01 2024 -0500

    Build Fix

    Help string was 14 characters too long for c89.

commit fc5506c7906bf82d6f88b7b0d7e4764d58d90622
Author: Ophidon <jrogers2@gmail.com>
Date:   Fri Jan 19 22:40:45 2024 -0500

    BFI Updates

    Significant BFI updates.

    - Adds BFI to dx10/11/12 in general.

    - Updates existing BFI menu option descriptions to be somewhat more clear in how to use correctly.

    - Adds Variable Strobe length via new 'Dark Frames' bfi sub-choice. Only valid at 180hz and above, as it must work with whole frames.

    - Algorithm to auto select 'decent' Dark Frames choice, for any given selected BFI refresh rate. Will also avoid defaults that can cause Image Retention at any Hz higher than 120. (Impossible to avoid at 120 if you have an affected screen... get an OLED :D ) .

    - Some sanity checking on selecting BFI or the other synchronizations options like Swap Interval > 1, that don't play well with BFI.
This commit is contained in:
Ophidon 2024-01-20 02:11:31 -05:00 committed by GitHub
parent c03deadb12
commit 72c901a90e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 632 additions and 63 deletions

View file

@ -396,11 +396,17 @@
/* 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).
* material with CRT-like motion clarity.
*/
#define DEFAULT_BLACK_FRAME_INSERTION 0
/* Black Frame Insertion Dark Frames.
* Increase for more clarity at the cost of lower brightness. Adjusting can also eliminate
* any temporary image retention if noticed. Only useful at 180hz or higher 60hz multiples,
* as 120hz only has one total extra frame for BFI to work with.
*/
#define DEFAULT_BFI_DARK_FRAMES 1
/* Uses a custom swap interval for VSync.
* Set this to effectively halve monitor refresh rate.
*/

View file

@ -2393,6 +2393,7 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("video_max_swapchain_images", &settings->uints.video_max_swapchain_images, true, DEFAULT_MAX_SWAPCHAIN_IMAGES, false);
SETTING_UINT("video_max_frame_latency", &settings->uints.video_max_frame_latency, true, DEFAULT_MAX_FRAME_LATENCY, false);
SETTING_UINT("video_black_frame_insertion", &settings->uints.video_black_frame_insertion, true, DEFAULT_BLACK_FRAME_INSERTION, false);
SETTING_UINT("video_bfi_dark_frames", &settings->uints.video_bfi_dark_frames, true, DEFAULT_BFI_DARK_FRAMES, false);
SETTING_UINT("video_swap_interval", &settings->uints.video_swap_interval, true, DEFAULT_SWAP_INTERVAL, false);
SETTING_UINT("video_rotation", &settings->uints.video_rotation, true, ORIENTATION_NORMAL, false);
SETTING_UINT("screen_orientation", &settings->uints.screen_orientation, true, ORIENTATION_NORMAL, false);

View file

@ -345,6 +345,7 @@ typedef struct settings
unsigned core_updater_auto_backup_history_size;
unsigned video_black_frame_insertion;
unsigned video_bfi_dark_frames;
unsigned video_autoswitch_refresh_rate;
unsigned quit_on_close_content;

View file

@ -42,7 +42,8 @@ enum d3d10_video_flags
D3D10_ST_FLAG_OVERLAYS_ENABLE = (1 << 7),
D3D10_ST_FLAG_OVERLAYS_FULLSCREEN = (1 << 8),
D3D10_ST_FLAG_MENU_ENABLE = (1 << 9),
D3D10_ST_FLAG_MENU_FULLSCREEN = (1 << 10)
D3D10_ST_FLAG_MENU_FULLSCREEN = (1 << 10),
D3D10_ST_FLAG_FRAME_DUPE_LOCK = (1 << 11)
};

View file

@ -54,7 +54,8 @@ enum d3d11_state_flags
D3D11_ST_FLAG_OVERLAYS_ENABLE = (1 << 14),
D3D11_ST_FLAG_OVERLAYS_FULLSCREEN = (1 << 15),
D3D11_ST_FLAG_MENU_ENABLE = (1 << 16),
D3D11_ST_FLAG_MENU_FULLSCREEN = (1 << 17)
D3D11_ST_FLAG_MENU_FULLSCREEN = (1 << 17),
D3D11_ST_FLAG_FRAME_DUPE_LOCK = (1 << 18)
};
enum d3d11_feature_level_hint

View file

@ -62,7 +62,8 @@ enum d3d12_video_flags
D3D12_ST_FLAG_VSYNC = (1 << 12),
D3D12_ST_FLAG_WAITABLE_SWAPCHAINS = (1 << 13),
D3D12_ST_FLAG_WAIT_FOR_VBLANK = (1 << 14),
D3D12_ST_FLAG_HW_IFACE_ENABLE = (1 << 15)
D3D12_ST_FLAG_HW_IFACE_ENABLE = (1 << 15),
D3D12_ST_FLAG_FRAME_DUPE_LOCK = (1 << 16)
};
typedef enum
@ -350,7 +351,7 @@ typedef struct
#ifdef DEBUG
D3D12Debug debugController;
#endif
uint16_t flags;
uint32_t flags;
} d3d12_video_t;
/* end of auto-generated */

View file

@ -65,7 +65,8 @@ enum gl1_flags
GL1_FLAG_SMOOTH = (1 << 8),
GL1_FLAG_MENU_SMOOTH = (1 << 9),
GL1_FLAG_OVERLAY_ENABLE = (1 << 10),
GL1_FLAG_OVERLAY_FULLSCREEN = (1 << 11)
GL1_FLAG_OVERLAY_FULLSCREEN = (1 << 11),
GL1_FLAG_FRAME_DUPE_LOCK = (1 << 12)
};
typedef struct gl1

View file

@ -185,7 +185,8 @@ enum gl2_flags
GL2_FLAG_OVERLAY_FULLSCREEN = (1 << 18),
GL2_FLAG_MENU_TEXTURE_ENABLE = (1 << 19),
GL2_FLAG_MENU_TEXTURE_FULLSCREEN= (1 << 20),
GL2_FLAG_NONE = (1 << 21)
GL2_FLAG_NONE = (1 << 21),
GL2_FLAG_FRAME_DUPE_LOCK = (1 << 22)
};
struct gl2

View file

@ -56,7 +56,8 @@ enum gl3_flags
GL3_FLAG_FULLSCREEN = (1 << 9),
GL3_FLAG_QUITTING = (1 << 10),
GL3_FLAG_SHOULD_RESIZE = (1 << 11),
GL3_FLAG_KEEP_ASPECT = (1 << 12)
GL3_FLAG_KEEP_ASPECT = (1 << 12),
GL3_FLAG_FRAME_DUPE_LOCK = (1 << 13)
};
struct gl3_streamed_texture

View file

@ -2167,6 +2167,13 @@ static bool d3d10_gfx_frame(
const char *stat_text = video_info->stat_text;
bool menu_is_alive = (video_info->menu_st_flags & MENU_ST_FLAG_ALIVE) ? true : false;
bool overlay_behind_menu = video_info->overlay_behind_menu;
unsigned black_frame_insertion = video_info->black_frame_insertion;
int bfi_light_frames;
unsigned n;
bool 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;
#ifdef HAVE_GFX_WIDGETS
bool widgets_active = video_info->widgets_active;
#endif
@ -2542,6 +2549,47 @@ static bool d3d10_gfx_frame(
#endif
DXGIPresent(d3d10->swapChain, d3d10->swap_interval, 0);
if (
black_frame_insertion
&& !(d3d10->flags & D3D10_ST_FLAG_MENU_ENABLE)
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused)
{
if (video_info->bfi_dark_frames > video_info->black_frame_insertion)
video_info->bfi_dark_frames = video_info->black_frame_insertion;
/* BFI now handles variable strobe strength, like on-off-off, vs on-on-off for 180hz.
This needs to be done with duping frames instead of increased swap intervals for
a couple reasons. Swap interval caps out at 4 in most all apis as of coding,
and seems to be flat ignored >1 at least in modern Windows for some older APIs. */
bfi_light_frames = video_info->black_frame_insertion - video_info->bfi_dark_frames;
if (bfi_light_frames > 0 && !(d3d10->flags & D3D10_ST_FLAG_FRAME_DUPE_LOCK))
{
d3d10->flags |= D3D10_ST_FLAG_FRAME_DUPE_LOCK;
while (bfi_light_frames > 0)
{
if (!(d3d10_gfx_frame(d3d10, NULL, 0, 0, frame_count, 0, msg, video_info)))
{
d3d10->flags &= ~D3D10_ST_FLAG_FRAME_DUPE_LOCK;
return false;
}
--bfi_light_frames;
}
d3d10->flags &= ~D3D10_ST_FLAG_FRAME_DUPE_LOCK;
}
for (n = 0; n < video_info->bfi_dark_frames; ++n)
{
if (!(d3d10->flags & D3D10_ST_FLAG_FRAME_DUPE_LOCK))
{
context->lpVtbl->OMSetRenderTargets(context, 1, &d3d10->renderTargetView, NULL);
context->lpVtbl->ClearRenderTargetView(context, d3d10->renderTargetView, d3d10->clearcolor);
DXGIPresent(d3d10->swapChain, d3d10->swap_interval, 0);
}
}
}
return true;
}
@ -2764,6 +2812,7 @@ static uint32_t d3d10_get_flags(void *data)
BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
BIT32_SET(flags, GFX_CTX_FLAGS_OVERLAY_BEHIND_MENU_SUPPORTED);
BIT32_SET(flags, GFX_CTX_FLAGS_BLACK_FRAME_INSERTION);
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG);
#endif

View file

@ -997,6 +997,7 @@ static uint32_t d3d11_get_flags(void *data)
BIT32_SET(flags, GFX_CTX_FLAGS_CUSTOMIZABLE_FRAME_LATENCY);
BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
BIT32_SET(flags, GFX_CTX_FLAGS_OVERLAY_BEHIND_MENU_SUPPORTED);
BIT32_SET(flags, GFX_CTX_FLAGS_BLACK_FRAME_INSERTION);
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG);
#endif
@ -2793,6 +2794,12 @@ static bool d3d11_gfx_frame(
struct font_params* osd_params = (struct font_params*)&video_info->osd_stat_params;
bool menu_is_alive = (video_info->menu_st_flags & MENU_ST_FLAG_ALIVE) ? true : false;
bool overlay_behind_menu = video_info->overlay_behind_menu;
unsigned black_frame_insertion = video_info->black_frame_insertion;
int bfi_light_frames;
unsigned n;
bool 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;
#ifdef HAVE_GFX_WIDGETS
bool widgets_active = video_info->widgets_active;
#endif
@ -3375,6 +3382,47 @@ static bool d3d11_gfx_frame(
Release(pOutput);
}
if (
black_frame_insertion
&& !(d3d11->flags & D3D11_ST_FLAG_MENU_ENABLE)
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused)
{
if (video_info->bfi_dark_frames > video_info->black_frame_insertion)
video_info->bfi_dark_frames = video_info->black_frame_insertion;
/* BFI now handles variable strobe strength, like on-off-off, vs on-on-off for 180hz.
This needs to be done with duping frames instead of increased swap intervals for
a couple reasons. Swap interval caps out at 4 in most all apis as of coding,
and seems to be flat ignored >1 at least in modern Windows for some older APIs. */
bfi_light_frames = video_info->black_frame_insertion - video_info->bfi_dark_frames;
if (bfi_light_frames > 0 && !(d3d11->flags & D3D11_ST_FLAG_FRAME_DUPE_LOCK))
{
d3d11->flags |= D3D11_ST_FLAG_FRAME_DUPE_LOCK;
while (bfi_light_frames > 0)
{
if (!(d3d11_gfx_frame(d3d11, NULL, 0, 0, frame_count, 0, msg, video_info)))
{
d3d11->flags &= ~D3D11_ST_FLAG_FRAME_DUPE_LOCK;
return false;
}
--bfi_light_frames;
}
d3d11->flags &= ~D3D11_ST_FLAG_FRAME_DUPE_LOCK;
}
for (n = 0; n < video_info->bfi_dark_frames; ++n)
{
if (!(d3d11->flags & D3D11_ST_FLAG_FRAME_DUPE_LOCK))
{
context->lpVtbl->OMSetRenderTargets(context, 1, &rtv, NULL);
context->lpVtbl->ClearRenderTargetView(context, rtv, d3d11->clearcolor);
DXGIPresent(d3d11->swapChain, d3d11->swap_interval, present_flags);
}
}
}
Release(rtv);
return true;

View file

@ -1145,6 +1145,7 @@ static uint32_t d3d12_get_flags(void *data)
BIT32_SET(flags, GFX_CTX_FLAGS_CUSTOMIZABLE_FRAME_LATENCY);
BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
BIT32_SET(flags, GFX_CTX_FLAGS_OVERLAY_BEHIND_MENU_SUPPORTED);
BIT32_SET(flags, GFX_CTX_FLAGS_BLACK_FRAME_INSERTION);
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG);
#endif
@ -3189,6 +3190,48 @@ static void d3d12_init_render_targets(d3d12_video_t* d3d12, unsigned width, unsi
d3d12->flags &= ~D3D12_ST_FLAG_RESIZE_RTS;
}
static void dx12_inject_black_frame(d3d12_video_t* d3d12)
{
D3D12GraphicsCommandList cmd = d3d12->queue.cmd;
D3D12_GFX_SYNC();
d3d12->queue.allocator->lpVtbl->Reset(d3d12->queue.allocator);
cmd->lpVtbl->Reset(cmd, d3d12->queue.allocator,
d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
d3d12->chain.frame_index = DXGIGetCurrentBackBufferIndex(
d3d12->chain.handle);
D3D12_RESOURCE_TRANSITION(
cmd,
d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET);
cmd->lpVtbl->OMSetRenderTargets(
cmd, 1, &d3d12->chain.desc_handles[d3d12->chain.frame_index],
FALSE, NULL);
cmd->lpVtbl->ClearRenderTargetView(
cmd,
d3d12->chain.desc_handles[d3d12->chain.frame_index],
d3d12->chain.clearcolor,
0, NULL);
D3D12_RESOURCE_TRANSITION(
cmd,
d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT);
cmd->lpVtbl->Close(cmd);
d3d12->queue.handle->lpVtbl->ExecuteCommandLists(d3d12->queue.handle, 1,
(ID3D12CommandList* const*)&d3d12->queue.cmd);
DXGIPresent(d3d12->chain.handle, d3d12->chain.swap_interval, 0);
}
static bool d3d12_gfx_frame(
void* data,
const void* frame,
@ -3213,6 +3256,12 @@ static bool d3d12_gfx_frame(
&video_info->osd_stat_params;
bool menu_is_alive = (video_info->menu_st_flags & MENU_ST_FLAG_ALIVE) ? true : false;
bool overlay_behind_menu = video_info->overlay_behind_menu;
unsigned black_frame_insertion = video_info->black_frame_insertion;
int bfi_light_frames;
unsigned n;
bool 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;
#ifdef HAVE_GFX_WIDGETS
bool widgets_active = video_info->widgets_active;
#endif
@ -3923,6 +3972,45 @@ static bool d3d12_gfx_frame(
Release(pOutput);
}
if (
black_frame_insertion
&& !(d3d12->flags & D3D12_ST_FLAG_MENU_ENABLE)
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused)
{
if (video_info->bfi_dark_frames > video_info->black_frame_insertion)
video_info->bfi_dark_frames = video_info->black_frame_insertion;
/* BFI now handles variable strobe strength, like on-off-off, vs on-on-off for 180hz.
This needs to be done with duping frames instead of increased swap intervals for
a couple reasons. Swap interval caps out at 4 in most all apis as of coding,
and seems to be flat ignored >1 at least in modern Windows for some older APIs. */
bfi_light_frames = video_info->black_frame_insertion - video_info->bfi_dark_frames;
if (bfi_light_frames > 0 && !(d3d12->flags & D3D12_ST_FLAG_FRAME_DUPE_LOCK))
{
d3d12->flags |= D3D12_ST_FLAG_FRAME_DUPE_LOCK;
while (bfi_light_frames > 0)
{
if (!(d3d12_gfx_frame(d3d12, NULL, 0, 0, frame_count, 0, msg, video_info)))
{
d3d12->flags &= ~D3D12_ST_FLAG_FRAME_DUPE_LOCK;
return false;
}
--bfi_light_frames;
}
d3d12->flags &= ~D3D12_ST_FLAG_FRAME_DUPE_LOCK;
}
for (n = 0; n < video_info->bfi_dark_frames; ++n)
{
if (!(d3d12->flags & D3D12_ST_FLAG_FRAME_DUPE_LOCK))
{
dx12_inject_black_frame(d3d12);
}
}
}
return true;
}

View file

@ -1481,6 +1481,8 @@ static bool gl1_frame(void *data, const void *frame,
unsigned pot_height = 0;
unsigned video_width = video_info->width;
unsigned video_height = video_info->height;
int bfi_light_frames;
unsigned n;
#ifdef HAVE_MENU
bool menu_is_alive = (video_info->menu_st_flags & MENU_ST_FLAG_ALIVE) ? true : false;
#endif
@ -1715,22 +1717,51 @@ static bool gl1_frame(void *data, const void *frame,
&& !video_info->runloop_is_paused
&& !(gl1->flags & GL1_FLAG_MENU_TEXTURE_ENABLE))
{
int n;
for (n = 0; n < (int)video_info->black_frame_insertion; ++n)
{
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);
}
if (video_info->bfi_dark_frames > video_info->black_frame_insertion)
video_info->bfi_dark_frames = video_info->black_frame_insertion;
/* BFI now handles variable strobe strength, like on-off-off, vs on-on-off for 180hz.
This needs to be done with duping frames instead of increased swap intervals for
a couple reasons. Swap interval caps out at 4 in most all apis as of coding,
and seems to be flat ignored >1 at least in modern Windows for some older APIs. */
bfi_light_frames = video_info->black_frame_insertion - video_info->bfi_dark_frames;
if (bfi_light_frames > 0 && !(gl1->flags & GL1_FLAG_FRAME_DUPE_LOCK))
{
gl1->flags |= GL1_FLAG_FRAME_DUPE_LOCK;
while (bfi_light_frames > 0)
{
if (!(gl1_frame(gl1, frame, 0, 0, frame_count, 0, msg, video_info)))
{
gl1->flags &= ~GL1_FLAG_FRAME_DUPE_LOCK;
return false;
}
--bfi_light_frames;
}
gl1->flags &= ~GL1_FLAG_FRAME_DUPE_LOCK;
}
for (n = 0; n < video_info->bfi_dark_frames; ++n)
{
if (!(gl1->flags & GL1_FLAG_FRAME_DUPE_LOCK))
{
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
&& !video_info->input_driver_nonblock_state
)
{
glClear(GL_COLOR_BUFFER_BIT);
@ -1742,7 +1773,6 @@ static bool gl1_frame(void *data, const void *frame,
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
return true;
}

View file

@ -3429,6 +3429,8 @@ static bool gl2_frame(void *data, const void *frame,
#ifndef EMSCRIPTEN
unsigned black_frame_insertion = video_info->black_frame_insertion;
#endif
int bfi_light_frames;
unsigned n;
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;
@ -3711,23 +3713,50 @@ static bool gl2_frame(void *data, const void *frame,
#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->flags & GL2_FLAG_MENU_TEXTURE_ENABLE)))
{
size_t n;
for (n = 0; n < black_frame_insertion; ++n)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (
video_info->black_frame_insertion
&& !video_info->input_driver_nonblock_state
&& !video_info->runloop_is_slowmotion
&& !video_info->runloop_is_paused
&& !(gl->flags & GL2_FLAG_MENU_TEXTURE_ENABLE))
{
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
}
}
if (video_info->bfi_dark_frames > video_info->black_frame_insertion)
video_info->bfi_dark_frames = video_info->black_frame_insertion;
/* BFI now handles variable strobe strength, like on-off-off, vs on-on-off for 180hz.
This needs to be done with duping frames instead of increased swap intervals for
a couple reasons. Swap interval caps out at 4 in most all apis as of coding,
and seems to be flat ignored >1 at least in modern Windows for some older APIs. */
bfi_light_frames = video_info->black_frame_insertion - video_info->bfi_dark_frames;
if (bfi_light_frames > 0 && !(gl->flags & GL2_FLAG_FRAME_DUPE_LOCK))
{
gl->flags |= GL2_FLAG_FRAME_DUPE_LOCK;
while (bfi_light_frames > 0)
{
if (!(gl2_frame(gl, NULL, 0, 0, frame_count, 0, msg, video_info)))
{
gl->flags &= ~GL2_FLAG_FRAME_DUPE_LOCK;
return false;
}
--bfi_light_frames;
}
gl->flags &= ~GL2_FLAG_FRAME_DUPE_LOCK;
}
for (n = 0; n < video_info->bfi_dark_frames; ++n)
{
if (!(gl->flags & GL2_FLAG_FRAME_DUPE_LOCK))
{
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,

View file

@ -2504,7 +2504,8 @@ static bool gl3_frame(void *data, const void *frame,
bool msg_bgcolor_enable = video_info->msg_bgcolor_enable;
#endif
unsigned black_frame_insertion = video_info->black_frame_insertion;
int bfi_light_frames;
unsigned n;
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;
@ -2672,23 +2673,50 @@ static bool gl3_frame(void *data, const void *frame,
#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->flags & GL3_FLAG_MENU_TEXTURE_ENABLE)))
{
size_t n;
for (n = 0; n < black_frame_insertion; ++n)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (
video_info->black_frame_insertion
&& !video_info->input_driver_nonblock_state
&& !video_info->runloop_is_slowmotion
&& !video_info->runloop_is_paused
&& !(gl->flags & GL3_FLAG_MENU_TEXTURE_ENABLE))
{
if (gl->ctx_driver->swap_buffers)
gl->ctx_driver->swap_buffers(gl->ctx_data);
}
}
if (video_info->bfi_dark_frames > video_info->black_frame_insertion)
video_info->bfi_dark_frames = video_info->black_frame_insertion;
/* BFI now handles variable strobe strength, like on-off-off, vs on-on-off for 180hz.
This needs to be done with duping frames instead of increased swap intervals for
a couple reasons. Swap interval caps out at 4 in most all apis as of coding,
and seems to be flat ignored >1 at least in modern Windows for some older APIs. */
bfi_light_frames = video_info->black_frame_insertion - video_info->bfi_dark_frames;
if (bfi_light_frames > 0 && !(gl->flags & GL3_FLAG_FRAME_DUPE_LOCK))
{
gl->flags |= GL3_FLAG_FRAME_DUPE_LOCK;
while (bfi_light_frames > 0)
{
if (!(gl3_frame(gl, NULL, 0, 0, frame_count, 0, msg, video_info)))
{
gl->flags &= ~GL3_FLAG_FRAME_DUPE_LOCK;
return false;
}
--bfi_light_frames;
}
gl->flags &= ~GL3_FLAG_FRAME_DUPE_LOCK;
}
for (n = 0; n < video_info->bfi_dark_frames; ++n)
{
if (!(gl->flags & GL3_FLAG_FRAME_DUPE_LOCK))
{
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

View file

@ -2504,7 +2504,6 @@ static uint32_t metal_get_flags(void *data)
uint32_t flags = 0;
BIT32_SET(flags, GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES);
BIT32_SET(flags, GFX_CTX_FLAGS_BLACK_FRAME_INSERTION);
BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
BIT32_SET(flags, GFX_CTX_FLAGS_SCREENSHOTS_SUPPORTED);

View file

@ -4064,6 +4064,8 @@ static bool vulkan_frame(void *data, const void *frame,
bool statistics_show = video_info->statistics_show;
const char *stat_text = video_info->stat_text;
unsigned black_frame_insertion = video_info->black_frame_insertion;
int bfi_light_frames;
unsigned n;
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;
@ -4870,7 +4872,7 @@ static bool vulkan_frame(void *data, const void *frame,
vulkan_check_swapchain(vk);
/* Disable BFI during fast forward, slow-motion,
* and pause to prevent flicker. */
* pause, and menu to prevent flicker. */
if (
(backbuffer->image != VK_NULL_HANDLE)
&& (vk->context->flags & VK_CTX_FLAG_HAS_ACQUIRED_SWAPCHAIN)
@ -4880,12 +4882,37 @@ static bool vulkan_frame(void *data, const void *frame,
&& !runloop_is_paused
&& (!(vk->flags & VK_FLAG_MENU_ENABLE)))
{
int n;
for (n = 0; n < (int) black_frame_insertion; ++n)
if (video_info->bfi_dark_frames > video_info->black_frame_insertion)
video_info->bfi_dark_frames = video_info->black_frame_insertion;
/* BFI now handles variable strobe strength, like on-off-off, vs on-on-off for 180hz.
This needs to be done with duping frames instead of increased swap intervals for
a couple reasons. Swap interval caps out at 4 in most all apis as of coding,
and seems to be flat ignored >1 at least in modern Windows for some older APIs. */
bfi_light_frames = video_info->black_frame_insertion - video_info->bfi_dark_frames;
if (bfi_light_frames > 0 && !(vk->context->flags & VK_CTX_FLAG_SWAP_INTERVAL_EMULATION_LOCK))
{
vulkan_inject_black_frame(vk, video_info);
if (vk->ctx_driver->swap_buffers)
vk->ctx_driver->swap_buffers(vk->ctx_data);
vk->context->flags |= VK_CTX_FLAG_SWAP_INTERVAL_EMULATION_LOCK;
while (bfi_light_frames > 0)
{
if (!(vulkan_frame(vk, NULL, 0, 0, frame_count, 0, msg, video_info)))
{
vk->context->flags &= ~VK_CTX_FLAG_SWAP_INTERVAL_EMULATION_LOCK;
return false;
}
--bfi_light_frames;
}
vk->context->flags &= ~VK_CTX_FLAG_SWAP_INTERVAL_EMULATION_LOCK;
}
for (n = 0; n < video_info->bfi_dark_frames; ++n)
{
if (!(vk->context->flags & VK_CTX_FLAG_SWAP_INTERVAL_EMULATION_LOCK))
{
vulkan_inject_black_frame(vk, video_info);
if (vk->ctx_driver->swap_buffers)
vk->ctx_driver->swap_buffers(vk->ctx_data);
}
}
}

View file

@ -2551,6 +2551,7 @@ void video_driver_build_info(video_frame_info_t *video_info)
video_info->crt_switch_porch_adjust = settings->ints.crt_switch_porch_adjust;
video_info->crt_switch_hires_menu = settings->bools.crt_switch_hires_menu;
video_info->black_frame_insertion = settings->uints.video_black_frame_insertion;
video_info->bfi_dark_frames = settings->uints.video_bfi_dark_frames;
video_info->hard_sync = settings->bools.video_hard_sync;
video_info->hard_sync_frames = settings->uints.video_hard_sync_frames;
video_info->runahead = settings->bools.run_ahead_enabled;

View file

@ -415,6 +415,7 @@ typedef struct video_frame_info
unsigned custom_vp_full_width;
unsigned custom_vp_full_height;
unsigned black_frame_insertion;
unsigned bfi_dark_frames;
unsigned fps_update_interval;
unsigned memory_update_interval;
unsigned msg_queue_delay;

View file

@ -4031,6 +4031,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION,
"video_black_frame_insertion"
)
MSG_HASH(
MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES,
"video_bfi_dark_frames"
)
MSG_HASH(
MENU_ENUM_LABEL_VIDEO_CROP_OVERSCAN,
"video_crop_overscan"

View file

@ -419,6 +419,9 @@ int msg_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len)
case MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION), len);
break;
case MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_HELP_VIDEO_BFI_DARK_FRAMES), len);
break;
case MENU_ENUM_LABEL_SAVEFILE_DIRECTORY:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_HELP_SAVEFILE_DIRECTORY), len);
break;

View file

@ -1920,11 +1920,87 @@ MSG_HASH(
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION,
"Insert a black frame between frames. Useful on some high refresh rate screens to eliminate ghosting."
"Insert black frame(s) between frames. Can greatly reduce motion blur by emulating CRT scan out, but at cost of brightness. Do not combine with Swap Interval > 1 (Auto is ok), Frame Delay, or Sync to Exact Content Framerate."
)
MSG_HASH(
MENU_ENUM_LABEL_HELP_VIDEO_BLACK_FRAME_INSERTION,
"Inserts a black frame inbetween frames. Useful for 120 Hz monitors 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 for enhanced motion clarity. Only use option designated for your current display refresh rate. Not for use at refresh rates that are non-multiples of 60Hz such as 144Hz, 165Hz, etc. Do not combine with Swap Interval > 1 (Auto is ok), Frame Delay, or Sync to Exact Content Framerate. Leaving system VRR on is ok, just not that setting. If you notice -any- temporary image retention, you should disable at 120hz, and for higher hz adjust the dark frames setting below."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_OFF,
"Off"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_120,
"1 - For 120Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_180,
"2 - For 180Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_240,
"3 - For 240Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_300,
"4 - For 300Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_360,
"5 - For 360Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_420,
"6 - For 420Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_480,
"7 - For 480Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_540,
"8 - For 540Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_600,
"9 - For 600Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_660,
"10 - For 660Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_720,
"11 - For 720Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_780,
"12 - For 780Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_840,
"13 - For 840Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_900,
"14 - For 900Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_960,
"15 - For 960Hz Display Refresh Rate"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_BFI_DARK_FRAMES,
"Black Frame Insertion - Dark Frames"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_BFI_DARK_FRAMES,
"Adjust number of black frames in total BFI scan out sequence. More equals higher motion clarity, less equals higher brightness. Not applicable at 120hz as there is only 1 BFI frame to work with total. Settings higher than possible will limit you to the maximum possible for your chosen refresh rate."
)
MSG_HASH(
MENU_ENUM_LABEL_HELP_VIDEO_BFI_DARK_FRAMES,
"Adjusts the number of frames displayed in the bfi sequence that are black. More black frames increases motion clarity but reduces brightness. Not applicable at 120hz as there is only one total extra 60hz frame, so it must be black otherwise BFI would not be active at all."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT,

View file

@ -493,6 +493,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_frame_delay, MENU_
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_frame_delay_auto, MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY_AUTO)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_shader_delay, MENU_ENUM_SUBLABEL_VIDEO_SHADER_DELAY)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_black_frame_insertion, MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_bfi_dark_frames, MENU_ENUM_SUBLABEL_VIDEO_BFI_DARK_FRAMES)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_toggle_gamepad_combo, MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_quit_gamepad_combo, MENU_ENUM_SUBLABEL_INPUT_QUIT_GAMEPAD_COMBO)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_show_hidden_files, MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES)
@ -4739,6 +4740,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_black_frame_insertion);
break;
case MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_bfi_dark_frames);
break;
case MENU_ENUM_LABEL_VIDEO_FRAME_DELAY:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_frame_delay);
break;

View file

@ -9316,6 +9316,7 @@ unsigned menu_displaylist_build_list(
bool video_vsync = settings->bools.video_vsync;
bool video_hard_sync = settings->bools.video_hard_sync;
bool video_wait_swap = settings->bools.video_waitable_swapchains;
unsigned bfi = settings->uints.video_black_frame_insertion;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_VSYNC,
@ -9332,6 +9333,14 @@ unsigned menu_displaylist_build_list(
MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION,
PARSE_ONLY_UINT, false) == 0)
count++;
if (bfi > 0)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES,
PARSE_ONLY_UINT, false) == 0)
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_ADAPTIVE_VSYNC,
PARSE_ONLY_BOOL, false) == 0)

View file

@ -6392,6 +6392,65 @@ static void setting_get_string_representation_video_swap_interval(rarch_setting_
snprintf(s, len, "%u", *setting->value.target.unsigned_integer);
}
static void setting_get_string_representation_black_frame_insertion(rarch_setting_t *setting,
char *s, size_t len)
{
if (!setting)
return;
switch (*setting->value.target.unsigned_integer)
{
case 0:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_OFF), len);
break;
case 1:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_120), len);
break;
case 2:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_180), len);
break;
case 3:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_240), len);
break;
case 4:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_300), len);
break;
case 5:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_360), len);
break;
case 6:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_420), len);
break;
case 7:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_480), len);
break;
case 8:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_540), len);
break;
case 9:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_600), len);
break;
case 10:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_660), len);
break;
case 11:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_720), len);
break;
case 12:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_780), len);
break;
case 13:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_840), len);
break;
case 14:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_900), len);
break;
case 15:
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_960), len);
break;
}
}
static void setting_get_string_representation_video_frame_delay(rarch_setting_t *setting,
char *s, size_t len)
{
@ -8105,14 +8164,79 @@ static void general_write_handler(rarch_setting_t *setting)
settings->floats.audio_max_timing_skew,
*setting->value.target.fraction);
break;
case MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION:
/* If enabling BFI, auto disable other sync settings
that do not work together with BFI */
if (*setting->value.target.unsigned_integer > 0)
{
configuration_set_uint(settings,
settings->uints.video_swap_interval,
0);
configuration_set_uint(settings,
settings->uints.video_frame_delay,
0);
configuration_set_bool(settings,
settings->bools.video_frame_delay_auto,
0);
configuration_set_bool(settings,
settings->bools.vrr_runloop_enable,
0);
/* Set reasonable default for dark frames for current BFI value.
Even results OR odd 60hz multiples should be mostly immune to lcd voltage retention.
Nothing to be done for 120hz except phase retention usage if needed. */
if (*setting->value.target.unsigned_integer == 1)
{
configuration_set_uint(settings,
settings->uints.video_bfi_dark_frames,
1);
}
/* Odd 60hz multiples, safe to nudge result over 50% for more clarity by default */
else if ((*setting->value.target.unsigned_integer + 1) % 2 != 0)
{
configuration_set_uint(settings,
settings->uints.video_bfi_dark_frames,
((*setting->value.target.unsigned_integer + 1) / 2) + 1);
}
/* Odd result on even multiple, bump result up one */
else if (((*setting->value.target.unsigned_integer + 1) / 2) % 2 != 0)
{
configuration_set_uint(settings,
settings->uints.video_bfi_dark_frames,
((*setting->value.target.unsigned_integer + 1) / 2) + 1);
}
/* Even result on even multiple, leave alone */
else
{
configuration_set_uint(settings,
settings->uints.video_bfi_dark_frames,
((*setting->value.target.unsigned_integer + 1) / 2));
}
}
#ifdef HAVE_CHEEVOS
rcheevos_validate_config_settings();
#endif
break;
case MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES:
/* Limit choice to max possible for current BFI Hz Setting */
if (*setting->value.target.unsigned_integer > settings->uints.video_black_frame_insertion)
configuration_set_uint(settings,
settings->uints.video_bfi_dark_frames,
settings->uints.video_black_frame_insertion);
break;
case MENU_ENUM_LABEL_VIDEO_FRAME_DELAY:
case MENU_ENUM_LABEL_VIDEO_FRAME_DELAY_AUTO:
case MENU_ENUM_LABEL_VIDEO_SWAP_INTERVAL:
case MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION:
case MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE:
/* BFI doesn't play nice with any of these */
configuration_set_bool(settings,
settings->uints.video_black_frame_insertion,
0);
#ifdef HAVE_CHEEVOS
rcheevos_validate_config_settings();
break;
#endif
break;
case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE_AUTO:
driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, setting->value.target.fraction);
@ -13449,9 +13573,26 @@ static bool setting_append_list(
general_write_handler,
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);
(*list)[list_info->index - 1].get_string_representation =
&setting_get_string_representation_black_frame_insertion;
menu_settings_list_current_add_range(list, list_info, 0, 15, 1, true, true);
MENU_SETTINGS_LIST_CURRENT_ADD_CMD(list, list_info, CMD_EVENT_REINIT);
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_CMD_APPLY_AUTO);
CONFIG_UINT(
list, list_info,
&settings->uints.video_bfi_dark_frames,
MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES,
MENU_ENUM_LABEL_VALUE_VIDEO_BFI_DARK_FRAMES,
DEFAULT_BFI_DARK_FRAMES,
&group_info,
&subgroup_info,
parent_group,
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_range(list, list_info, 1, 15, 1, true, true);
}
}
#endif

View file

@ -1347,6 +1347,7 @@ enum msg_hash_enums
MENU_LABEL(VIDEO_MAX_FRAME_LATENCY),
MENU_LABEL(VIDEO_GPU_SCREENSHOT),
MENU_LBL_H(VIDEO_BLACK_FRAME_INSERTION),
MENU_LBL_H(VIDEO_BFI_DARK_FRAMES),
MENU_LBL_H(VIDEO_FRAME_DELAY),
MENU_LBL_H(VIDEO_FRAME_DELAY_AUTO),
MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTOMATIC,
@ -1412,6 +1413,23 @@ enum msg_hash_enums
MENU_LABEL(VIDEO_SWAP_INTERVAL),
MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL_AUTO,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_120,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_180,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_240,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_300,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_360,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_420,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_480,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_540,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_600,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_660,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_720,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_780,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_840,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_900,
MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION_VALUE_960,
MENU_LABEL(VIDEO_FULLSCREEN),
MENU_LBL_H(VIDEO_MONITOR_INDEX),
MENU_LABEL(VIDEO_WIIU_PREFER_DRC),