Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rolling Scanline Simulation #16282

Merged
merged 1 commit into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1806,6 +1806,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 @@ -597,6 +597,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
Loading