Skip to content

Commit

Permalink
Added rolling scan line simulation based on the shader subframe featu…
Browse files Browse the repository at this point in the history
…re. This is implemented with a scrolling scissor rect rather than in the shader itself as this is more efficient although may not work for every shader pass - we may need an option to exclude certain passes. The implementation simply divides the screen up by the number of sub frames and then moves the scissor rect down over the screen over the number of sub frames. (#16282)
  • Loading branch information
MajorPainTheCactus authored Mar 19, 2024
1 parent 5452999 commit eef34e9
Show file tree
Hide file tree
Showing 22 changed files with 517 additions and 23 deletions.
5 changes: 5 additions & 0 deletions config.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,11 @@
*/
#define DEFAULT_SHADER_SUBFRAMES 1

/* Divides implements basic rolling scanning of sub frames - does this simply by scrolling a
* a scissor rect down the screen according to how many sub frames there are
*/
#define DEFAULT_SCAN_SUBFRAMES false

/* 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 CRT-like motion clarity.
Expand Down
2 changes: 2 additions & 0 deletions configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -1809,6 +1809,8 @@ static struct config_bool_setting *populate_settings_bool(
/* Let implementation decide if automatic, or 1:1 PAR. */
SETTING_BOOL("video_aspect_ratio_auto", &settings->bools.video_aspect_ratio_auto, true, DEFAULT_ASPECT_RATIO_AUTO, false);

SETTING_BOOL("video_scan_subframes", &settings->bools.video_scan_subframes, true, DEFAULT_SCAN_SUBFRAMES, false);

SETTING_BOOL("video_allow_rotate", &settings->bools.video_allow_rotate, true, DEFAULT_ALLOW_ROTATE, false);
SETTING_BOOL("video_windowed_fullscreen", &settings->bools.video_windowed_fullscreen, true, DEFAULT_WINDOWED_FULLSCREEN, false);
SETTING_BOOL("video_crop_overscan", &settings->bools.video_crop_overscan, true, DEFAULT_CROP_OVERSCAN, false);
Expand Down
1 change: 1 addition & 0 deletions configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ typedef struct settings
bool video_shader_watch_files;
bool video_shader_remember_last_dir;
bool video_shader_preset_save_reference_enable;
bool video_scan_subframes;
bool video_threaded;
bool video_font_enable;
bool video_disable_composition;
Expand Down
79 changes: 79 additions & 0 deletions gfx/drivers/d3d10.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
#error "UWP does not support D3D10"
#endif

#define D3D10_ROLLING_SCANLINE_SIMULATION

typedef struct
{
d3d10_texture_t texture;
Expand Down Expand Up @@ -2417,6 +2419,41 @@ static bool d3d10_gfx_frame(
context->lpVtbl->RSSetViewports(context, 1,
&d3d10->pass[i].viewport);

#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !black_frame_insertion
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& (!(d3d10->flags & D3D10_ST_FLAG_MENU_ENABLE)))
{
D3D10_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = (unsigned int)(((float)d3d10->pass[i].viewport.Height / (float)video_info->shader_subframes)
* (float)video_info->current_subframe);
scissor_rect.right = d3d10->pass[i].viewport.Width ;
scissor_rect.bottom = (unsigned int)(((float)d3d10->pass[i].viewport.Height / (float)video_info->shader_subframes)
* (float)(video_info->current_subframe + 1));

d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
&scissor_rect);
}
else
{
D3D10_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = 0;
scissor_rect.right = d3d10->pass[i].viewport.Width;
scissor_rect.bottom = d3d10->pass[i].viewport.Height;

d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
&scissor_rect);
}
#endif // D3D10_ROLLING_SCANLINE_SIMULATION

context->lpVtbl->Draw(context, 4, 0);
texture = &d3d10->pass[i].rt;
}
Expand Down Expand Up @@ -2448,6 +2485,29 @@ static bool d3d10_gfx_frame(
d3d10->clearcolor);
context->lpVtbl->RSSetViewports(context, 1, &d3d10->frame.viewport);

#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !black_frame_insertion
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& (!(d3d10->flags & D3D10_ST_FLAG_MENU_ENABLE)))
{
D3D10_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
* (float)video_info->current_subframe);
scissor_rect.right = video_width ;
scissor_rect.bottom = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
* (float)(video_info->current_subframe + 1));

d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
&scissor_rect);
}
else
#endif // D3D10_ROLLING_SCANLINE_SIMULATION
{
D3D10_RECT scissor_rect;

Expand All @@ -2464,6 +2524,20 @@ static bool d3d10_gfx_frame(
context->lpVtbl->OMSetBlendState(context, d3d10->blend_enable, NULL,
D3D10_DEFAULT_SAMPLE_MASK);

#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
{
D3D10_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = 0;
scissor_rect.right = video_width;
scissor_rect.bottom = video_height;

d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
&scissor_rect);
}
#endif // D3D10_ROLLING_SCANLINE_SIMULATION

if ( (d3d10->flags & D3D10_ST_FLAG_MENU_ENABLE)
&& d3d10->menu.texture.handle)
{
Expand Down Expand Up @@ -2622,8 +2696,13 @@ static bool d3d10_gfx_frame(
&& (!(d3d10->flags & D3D10_ST_FLAG_FRAME_DUPE_LOCK)))
{
d3d10->flags |= D3D10_ST_FLAG_FRAME_DUPE_LOCK;

for (k = 1; k < video_info->shader_subframes; k++)
{
#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
video_info->current_subframe = k;
#endif // D3D10_ROLLING_SCANLINE_SIMULATION

if (d3d10->shader_preset)
for (m = 0; m < d3d10->shader_preset->passes; m++)
{
Expand Down
86 changes: 85 additions & 1 deletion gfx/drivers/d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ const GUID DECLSPEC_SELECTANY libretro_IID_IDXGIFactory5 = { 0x7632e1f5,0xee65,0
#endif
#endif

#define D3D11_ROLLING_SCANLINE_SIMULATION

/* Temporary workaround for d3d11 not being able to poll flags during init */
static gfx_ctx_driver_t d3d11_fake_context;

Expand Down Expand Up @@ -3025,7 +3027,23 @@ static bool d3d11_gfx_frame(
context, width, height, pitch, d3d11->format, frame, &d3d11->frame.texture[0]);
}

context->lpVtbl->RSSetState(context, d3d11->scissor_disabled);
#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !black_frame_insertion
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& (!(d3d11->flags & D3D11_ST_FLAG_MENU_ENABLE)))
{
context->lpVtbl->RSSetState(context, d3d11->scissor_enabled);
}
else
#endif // D3D11_ROLLING_SCANLINE_SIMULATION
{
context->lpVtbl->RSSetState(context, d3d11->scissor_disabled);
}

d3d11->context->lpVtbl->OMSetBlendState(
d3d11->context, d3d11->blend_disable,
NULL, D3D11_DEFAULT_SAMPLE_MASK);
Expand Down Expand Up @@ -3158,6 +3176,41 @@ static bool d3d11_gfx_frame(
&d3d11->pass[i].rt.rt_view, NULL);
context->lpVtbl->RSSetViewports(context, 1, &d3d11->pass[i].viewport);

#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !black_frame_insertion
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& (!(d3d11->flags & D3D11_ST_FLAG_MENU_ENABLE)))
{
D3D11_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = (unsigned int)(((float)d3d11->pass[i].viewport.Height / (float)video_info->shader_subframes)
* (float)video_info->current_subframe);
scissor_rect.right = d3d11->pass[i].viewport.Width ;
scissor_rect.bottom = (unsigned int)(((float)d3d11->pass[i].viewport.Height / (float)video_info->shader_subframes)
* (float)(video_info->current_subframe + 1));

d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1,
&scissor_rect);
}
else
{
D3D11_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = 0;
scissor_rect.right = d3d11->pass[i].viewport.Width;
scissor_rect.bottom = d3d11->pass[i].viewport.Height;

d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1,
&scissor_rect);
}
#endif // D3D11_ROLLING_SCANLINE_SIMULATION

if (i == d3d11->shader_preset->passes - 1)
context->lpVtbl->Draw(context, 4, 0);
else
Expand Down Expand Up @@ -3204,6 +3257,33 @@ static bool d3d11_gfx_frame(
context->lpVtbl->VSSetConstantBuffers(context, 0, 1, &d3d11->frame.ubo);
}

#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !black_frame_insertion
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& (!(d3d11->flags & D3D11_ST_FLAG_MENU_ENABLE)))
{
D3D11_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
* (float)video_info->current_subframe);
scissor_rect.right = video_width ;
scissor_rect.bottom = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
* (float)(video_info->current_subframe + 1));

d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1,
&scissor_rect);
}
else
{
d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1, &d3d11->scissor);
}
#endif // D3D11_ROLLING_SCANLINE_SIMULATION

context->lpVtbl->Draw(context, 4, 0);
context->lpVtbl->RSSetState(context, d3d11->scissor_enabled);
d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1, &d3d11->scissor);
Expand Down Expand Up @@ -3458,6 +3538,10 @@ static bool d3d11_gfx_frame(
d3d11->flags |= D3D11_ST_FLAG_FRAME_DUPE_LOCK;
for (k = 1; k < video_info->shader_subframes; k++)
{
#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
video_info->current_subframe = k;
#endif // D3D11_ROLLING_SCANLINE_SIMULATION

if (d3d11->shader_preset)
for (m = 0; m < d3d11->shader_preset->passes; m++)
{
Expand Down
62 changes: 59 additions & 3 deletions gfx/drivers/d3d12.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
} \
}

#define D3D12_ROLLING_SCANLINE_SIMULATION

typedef struct
{
d3d12_texture_t texture;
Expand Down Expand Up @@ -3748,8 +3750,33 @@ static bool d3d12_gfx_frame(
#endif
cmd->lpVtbl->RSSetViewports(cmd, 1,
&d3d12->pass[i].viewport);
cmd->lpVtbl->RSSetScissorRects(cmd, 1,
&d3d12->pass[i].scissorRect);

#ifdef D3D12_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !black_frame_insertion
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& (!(d3d12->flags & D3D12_ST_FLAG_MENU_ENABLE)))
{
D3D12_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = (unsigned int)(((float)d3d12->pass[i].viewport.Height / (float)video_info->shader_subframes)
* (float)video_info->current_subframe);
scissor_rect.right = d3d12->pass[i].viewport.Width;
scissor_rect.bottom = (unsigned int)(((float)d3d12->pass[i].viewport.Height / (float)video_info->shader_subframes)
* (float)(video_info->current_subframe + 1));

cmd->lpVtbl->RSSetScissorRects(cmd, 1, &scissor_rect);
}
else
#endif // D3D12_ROLLING_SCANLINE_SIMULATION
{
cmd->lpVtbl->RSSetScissorRects(cmd, 1,
&d3d12->pass[i].scissorRect);
}

if (i == d3d12->shader_preset->passes - 1)
start_vertex_location = 0;
Expand Down Expand Up @@ -3836,7 +3863,32 @@ static bool d3d12_gfx_frame(
}

cmd->lpVtbl->RSSetViewports(cmd, 1, &d3d12->frame.viewport);
cmd->lpVtbl->RSSetScissorRects(cmd, 1, &d3d12->frame.scissorRect);

#ifdef D3D12_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !black_frame_insertion
&& !nonblock_state
&& !runloop_is_slowmotion
&& !runloop_is_paused
&& (!(d3d12->flags & D3D12_ST_FLAG_MENU_ENABLE)))
{
D3D12_RECT scissor_rect;

scissor_rect.left = 0;
scissor_rect.top = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
* (float)video_info->current_subframe);
scissor_rect.right = video_width ;
scissor_rect.bottom = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
* (float)(video_info->current_subframe + 1));

cmd->lpVtbl->RSSetScissorRects(cmd, 1, &scissor_rect);
}
else
#endif // D3D12_ROLLING_SCANLINE_SIMULATION
{
cmd->lpVtbl->RSSetScissorRects(cmd, 1, &d3d12->frame.scissorRect);
}

cmd->lpVtbl->DrawInstanced(cmd, 4, 1, 0, 0);

Expand Down Expand Up @@ -4046,6 +4098,10 @@ static bool d3d12_gfx_frame(
d3d12->flags |= D3D12_ST_FLAG_FRAME_DUPE_LOCK;
for (k = 1; k < video_info->shader_subframes; k++)
{
#ifdef D3D12_ROLLING_SCANLINE_SIMULATION
video_info->current_subframe = k;
#endif // D3D12_ROLLING_SCANLINE_SIMULATION

if (d3d12->shader_preset)
for (m = 0; m < d3d12->shader_preset->passes; m++)
{
Expand Down
19 changes: 19 additions & 0 deletions gfx/drivers/gl3.c
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,25 @@ static bool gl3_frame(void *data, const void *frame,
gl->filter_chain, 1);
}

#ifdef GL3_ROLLING_SCANLINE_SIMULATION
if ( (video_info->shader_subframes > 1)
&& (video_info->scan_subframes)
&& !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)))
{
gl3_filter_chain_set_simulate_scanline(
gl->filter_chain, true);
}
else
{
gl3_filter_chain_set_simulate_scanline(
gl->filter_chain, false);
}
#endif // GL3_ROLLING_SCANLINE_SIMULATION

gl3_filter_chain_set_input_texture(gl->filter_chain, &texture);
gl3_filter_chain_build_offscreen_passes(gl->filter_chain,
&gl->filter_chain_vp);
Expand Down
Loading

0 comments on commit eef34e9

Please sign in to comment.