Skip to content

Commit

Permalink
Squashed commit of the following: (libretro#16142)
Browse files Browse the repository at this point in the history
commit 793d41c
Author: Ophidon <jrogers2@gmail.com>
Date:   Fri Jan 19 23:12:31 2024 -0500

    Build Fix 2

    Move declarations of iterators.

commit c0e959b
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 fc5506c
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.
  • Loading branch information
Ophidon authored Jan 20, 2024
1 parent c03dead commit 72c901a
Show file tree
Hide file tree
Showing 26 changed files with 635 additions and 66 deletions.
10 changes: 8 additions & 2 deletions config.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
1 change: 1 addition & 0 deletions configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion gfx/common/d3d10_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
};


Expand Down
3 changes: 2 additions & 1 deletion gfx/common/d3d11_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions gfx/common/d3d12_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -350,7 +351,7 @@ typedef struct
#ifdef DEBUG
D3D12Debug debugController;
#endif
uint16_t flags;
uint32_t flags;
} d3d12_video_t;

/* end of auto-generated */
Expand Down
3 changes: 2 additions & 1 deletion gfx/common/gl1_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion gfx/common/gl2_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion gfx/common/gl3_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 49 additions & 0 deletions gfx/drivers/d3d10.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down
48 changes: 48 additions & 0 deletions gfx/drivers/d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
88 changes: 88 additions & 0 deletions gfx/drivers/d3d12.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
Loading

0 comments on commit 72c901a

Please sign in to comment.