Skip to content

Commit eef34e9

Browse files
Added rolling scan line simulation based on the shader subframe feature. 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)
1 parent 5452999 commit eef34e9

22 files changed

Lines changed: 517 additions & 23 deletions

config.def.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,11 @@
401401
*/
402402
#define DEFAULT_SHADER_SUBFRAMES 1
403403

404+
/* Divides implements basic rolling scanning of sub frames - does this simply by scrolling a
405+
* a scissor rect down the screen according to how many sub frames there are
406+
*/
407+
#define DEFAULT_SCAN_SUBFRAMES false
408+
404409
/* Inserts black frame(s) inbetween frames.
405410
* Useful for Higher Hz monitors (set to multiples of 60 Hz) who want to play 60 Hz
406411
* material with CRT-like motion clarity.

configuration.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,8 @@ static struct config_bool_setting *populate_settings_bool(
18091809
/* Let implementation decide if automatic, or 1:1 PAR. */
18101810
SETTING_BOOL("video_aspect_ratio_auto", &settings->bools.video_aspect_ratio_auto, true, DEFAULT_ASPECT_RATIO_AUTO, false);
18111811

1812+
SETTING_BOOL("video_scan_subframes", &settings->bools.video_scan_subframes, true, DEFAULT_SCAN_SUBFRAMES, false);
1813+
18121814
SETTING_BOOL("video_allow_rotate", &settings->bools.video_allow_rotate, true, DEFAULT_ALLOW_ROTATE, false);
18131815
SETTING_BOOL("video_windowed_fullscreen", &settings->bools.video_windowed_fullscreen, true, DEFAULT_WINDOWED_FULLSCREEN, false);
18141816
SETTING_BOOL("video_crop_overscan", &settings->bools.video_crop_overscan, true, DEFAULT_CROP_OVERSCAN, false);

configuration.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ typedef struct settings
611611
bool video_shader_watch_files;
612612
bool video_shader_remember_last_dir;
613613
bool video_shader_preset_save_reference_enable;
614+
bool video_scan_subframes;
614615
bool video_threaded;
615616
bool video_font_enable;
616617
bool video_disable_composition;

gfx/drivers/d3d10.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#error "UWP does not support D3D10"
6161
#endif
6262

63+
#define D3D10_ROLLING_SCANLINE_SIMULATION
64+
6365
typedef struct
6466
{
6567
d3d10_texture_t texture;
@@ -2417,6 +2419,41 @@ static bool d3d10_gfx_frame(
24172419
context->lpVtbl->RSSetViewports(context, 1,
24182420
&d3d10->pass[i].viewport);
24192421

2422+
#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
2423+
if ( (video_info->shader_subframes > 1)
2424+
&& (video_info->scan_subframes)
2425+
&& !black_frame_insertion
2426+
&& !nonblock_state
2427+
&& !runloop_is_slowmotion
2428+
&& !runloop_is_paused
2429+
&& (!(d3d10->flags & D3D10_ST_FLAG_MENU_ENABLE)))
2430+
{
2431+
D3D10_RECT scissor_rect;
2432+
2433+
scissor_rect.left = 0;
2434+
scissor_rect.top = (unsigned int)(((float)d3d10->pass[i].viewport.Height / (float)video_info->shader_subframes)
2435+
* (float)video_info->current_subframe);
2436+
scissor_rect.right = d3d10->pass[i].viewport.Width ;
2437+
scissor_rect.bottom = (unsigned int)(((float)d3d10->pass[i].viewport.Height / (float)video_info->shader_subframes)
2438+
* (float)(video_info->current_subframe + 1));
2439+
2440+
d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
2441+
&scissor_rect);
2442+
}
2443+
else
2444+
{
2445+
D3D10_RECT scissor_rect;
2446+
2447+
scissor_rect.left = 0;
2448+
scissor_rect.top = 0;
2449+
scissor_rect.right = d3d10->pass[i].viewport.Width;
2450+
scissor_rect.bottom = d3d10->pass[i].viewport.Height;
2451+
2452+
d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
2453+
&scissor_rect);
2454+
}
2455+
#endif // D3D10_ROLLING_SCANLINE_SIMULATION
2456+
24202457
context->lpVtbl->Draw(context, 4, 0);
24212458
texture = &d3d10->pass[i].rt;
24222459
}
@@ -2448,6 +2485,29 @@ static bool d3d10_gfx_frame(
24482485
d3d10->clearcolor);
24492486
context->lpVtbl->RSSetViewports(context, 1, &d3d10->frame.viewport);
24502487

2488+
#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
2489+
if ( (video_info->shader_subframes > 1)
2490+
&& (video_info->scan_subframes)
2491+
&& !black_frame_insertion
2492+
&& !nonblock_state
2493+
&& !runloop_is_slowmotion
2494+
&& !runloop_is_paused
2495+
&& (!(d3d10->flags & D3D10_ST_FLAG_MENU_ENABLE)))
2496+
{
2497+
D3D10_RECT scissor_rect;
2498+
2499+
scissor_rect.left = 0;
2500+
scissor_rect.top = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
2501+
* (float)video_info->current_subframe);
2502+
scissor_rect.right = video_width ;
2503+
scissor_rect.bottom = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
2504+
* (float)(video_info->current_subframe + 1));
2505+
2506+
d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
2507+
&scissor_rect);
2508+
}
2509+
else
2510+
#endif // D3D10_ROLLING_SCANLINE_SIMULATION
24512511
{
24522512
D3D10_RECT scissor_rect;
24532513

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

2527+
#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
2528+
{
2529+
D3D10_RECT scissor_rect;
2530+
2531+
scissor_rect.left = 0;
2532+
scissor_rect.top = 0;
2533+
scissor_rect.right = video_width;
2534+
scissor_rect.bottom = video_height;
2535+
2536+
d3d10->device->lpVtbl->RSSetScissorRects(d3d10->device, 1,
2537+
&scissor_rect);
2538+
}
2539+
#endif // D3D10_ROLLING_SCANLINE_SIMULATION
2540+
24672541
if ( (d3d10->flags & D3D10_ST_FLAG_MENU_ENABLE)
24682542
&& d3d10->menu.texture.handle)
24692543
{
@@ -2622,8 +2696,13 @@ static bool d3d10_gfx_frame(
26222696
&& (!(d3d10->flags & D3D10_ST_FLAG_FRAME_DUPE_LOCK)))
26232697
{
26242698
d3d10->flags |= D3D10_ST_FLAG_FRAME_DUPE_LOCK;
2699+
26252700
for (k = 1; k < video_info->shader_subframes; k++)
26262701
{
2702+
#ifdef D3D10_ROLLING_SCANLINE_SIMULATION
2703+
video_info->current_subframe = k;
2704+
#endif // D3D10_ROLLING_SCANLINE_SIMULATION
2705+
26272706
if (d3d10->shader_preset)
26282707
for (m = 0; m < d3d10->shader_preset->passes; m++)
26292708
{

gfx/drivers/d3d11.c

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ const GUID DECLSPEC_SELECTANY libretro_IID_IDXGIFactory5 = { 0x7632e1f5,0xee65,0
7676
#endif
7777
#endif
7878

79+
#define D3D11_ROLLING_SCANLINE_SIMULATION
80+
7981
/* Temporary workaround for d3d11 not being able to poll flags during init */
8082
static gfx_ctx_driver_t d3d11_fake_context;
8183

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

3028-
context->lpVtbl->RSSetState(context, d3d11->scissor_disabled);
3030+
#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
3031+
if ( (video_info->shader_subframes > 1)
3032+
&& (video_info->scan_subframes)
3033+
&& !black_frame_insertion
3034+
&& !nonblock_state
3035+
&& !runloop_is_slowmotion
3036+
&& !runloop_is_paused
3037+
&& (!(d3d11->flags & D3D11_ST_FLAG_MENU_ENABLE)))
3038+
{
3039+
context->lpVtbl->RSSetState(context, d3d11->scissor_enabled);
3040+
}
3041+
else
3042+
#endif // D3D11_ROLLING_SCANLINE_SIMULATION
3043+
{
3044+
context->lpVtbl->RSSetState(context, d3d11->scissor_disabled);
3045+
}
3046+
30293047
d3d11->context->lpVtbl->OMSetBlendState(
30303048
d3d11->context, d3d11->blend_disable,
30313049
NULL, D3D11_DEFAULT_SAMPLE_MASK);
@@ -3158,6 +3176,41 @@ static bool d3d11_gfx_frame(
31583176
&d3d11->pass[i].rt.rt_view, NULL);
31593177
context->lpVtbl->RSSetViewports(context, 1, &d3d11->pass[i].viewport);
31603178

3179+
#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
3180+
if ( (video_info->shader_subframes > 1)
3181+
&& (video_info->scan_subframes)
3182+
&& !black_frame_insertion
3183+
&& !nonblock_state
3184+
&& !runloop_is_slowmotion
3185+
&& !runloop_is_paused
3186+
&& (!(d3d11->flags & D3D11_ST_FLAG_MENU_ENABLE)))
3187+
{
3188+
D3D11_RECT scissor_rect;
3189+
3190+
scissor_rect.left = 0;
3191+
scissor_rect.top = (unsigned int)(((float)d3d11->pass[i].viewport.Height / (float)video_info->shader_subframes)
3192+
* (float)video_info->current_subframe);
3193+
scissor_rect.right = d3d11->pass[i].viewport.Width ;
3194+
scissor_rect.bottom = (unsigned int)(((float)d3d11->pass[i].viewport.Height / (float)video_info->shader_subframes)
3195+
* (float)(video_info->current_subframe + 1));
3196+
3197+
d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1,
3198+
&scissor_rect);
3199+
}
3200+
else
3201+
{
3202+
D3D11_RECT scissor_rect;
3203+
3204+
scissor_rect.left = 0;
3205+
scissor_rect.top = 0;
3206+
scissor_rect.right = d3d11->pass[i].viewport.Width;
3207+
scissor_rect.bottom = d3d11->pass[i].viewport.Height;
3208+
3209+
d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1,
3210+
&scissor_rect);
3211+
}
3212+
#endif // D3D11_ROLLING_SCANLINE_SIMULATION
3213+
31613214
if (i == d3d11->shader_preset->passes - 1)
31623215
context->lpVtbl->Draw(context, 4, 0);
31633216
else
@@ -3204,6 +3257,33 @@ static bool d3d11_gfx_frame(
32043257
context->lpVtbl->VSSetConstantBuffers(context, 0, 1, &d3d11->frame.ubo);
32053258
}
32063259

3260+
#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
3261+
if ( (video_info->shader_subframes > 1)
3262+
&& (video_info->scan_subframes)
3263+
&& !black_frame_insertion
3264+
&& !nonblock_state
3265+
&& !runloop_is_slowmotion
3266+
&& !runloop_is_paused
3267+
&& (!(d3d11->flags & D3D11_ST_FLAG_MENU_ENABLE)))
3268+
{
3269+
D3D11_RECT scissor_rect;
3270+
3271+
scissor_rect.left = 0;
3272+
scissor_rect.top = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
3273+
* (float)video_info->current_subframe);
3274+
scissor_rect.right = video_width ;
3275+
scissor_rect.bottom = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
3276+
* (float)(video_info->current_subframe + 1));
3277+
3278+
d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1,
3279+
&scissor_rect);
3280+
}
3281+
else
3282+
{
3283+
d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1, &d3d11->scissor);
3284+
}
3285+
#endif // D3D11_ROLLING_SCANLINE_SIMULATION
3286+
32073287
context->lpVtbl->Draw(context, 4, 0);
32083288
context->lpVtbl->RSSetState(context, d3d11->scissor_enabled);
32093289
d3d11->context->lpVtbl->RSSetScissorRects(d3d11->context, 1, &d3d11->scissor);
@@ -3458,6 +3538,10 @@ static bool d3d11_gfx_frame(
34583538
d3d11->flags |= D3D11_ST_FLAG_FRAME_DUPE_LOCK;
34593539
for (k = 1; k < video_info->shader_subframes; k++)
34603540
{
3541+
#ifdef D3D11_ROLLING_SCANLINE_SIMULATION
3542+
video_info->current_subframe = k;
3543+
#endif // D3D11_ROLLING_SCANLINE_SIMULATION
3544+
34613545
if (d3d11->shader_preset)
34623546
for (m = 0; m < d3d11->shader_preset->passes; m++)
34633547
{

gfx/drivers/d3d12.c

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
} \
8080
}
8181

82+
#define D3D12_ROLLING_SCANLINE_SIMULATION
83+
8284
typedef struct
8385
{
8486
d3d12_texture_t texture;
@@ -3748,8 +3750,33 @@ static bool d3d12_gfx_frame(
37483750
#endif
37493751
cmd->lpVtbl->RSSetViewports(cmd, 1,
37503752
&d3d12->pass[i].viewport);
3751-
cmd->lpVtbl->RSSetScissorRects(cmd, 1,
3752-
&d3d12->pass[i].scissorRect);
3753+
3754+
#ifdef D3D12_ROLLING_SCANLINE_SIMULATION
3755+
if ( (video_info->shader_subframes > 1)
3756+
&& (video_info->scan_subframes)
3757+
&& !black_frame_insertion
3758+
&& !nonblock_state
3759+
&& !runloop_is_slowmotion
3760+
&& !runloop_is_paused
3761+
&& (!(d3d12->flags & D3D12_ST_FLAG_MENU_ENABLE)))
3762+
{
3763+
D3D12_RECT scissor_rect;
3764+
3765+
scissor_rect.left = 0;
3766+
scissor_rect.top = (unsigned int)(((float)d3d12->pass[i].viewport.Height / (float)video_info->shader_subframes)
3767+
* (float)video_info->current_subframe);
3768+
scissor_rect.right = d3d12->pass[i].viewport.Width;
3769+
scissor_rect.bottom = (unsigned int)(((float)d3d12->pass[i].viewport.Height / (float)video_info->shader_subframes)
3770+
* (float)(video_info->current_subframe + 1));
3771+
3772+
cmd->lpVtbl->RSSetScissorRects(cmd, 1, &scissor_rect);
3773+
}
3774+
else
3775+
#endif // D3D12_ROLLING_SCANLINE_SIMULATION
3776+
{
3777+
cmd->lpVtbl->RSSetScissorRects(cmd, 1,
3778+
&d3d12->pass[i].scissorRect);
3779+
}
37533780

37543781
if (i == d3d12->shader_preset->passes - 1)
37553782
start_vertex_location = 0;
@@ -3836,7 +3863,32 @@ static bool d3d12_gfx_frame(
38363863
}
38373864

38383865
cmd->lpVtbl->RSSetViewports(cmd, 1, &d3d12->frame.viewport);
3839-
cmd->lpVtbl->RSSetScissorRects(cmd, 1, &d3d12->frame.scissorRect);
3866+
3867+
#ifdef D3D12_ROLLING_SCANLINE_SIMULATION
3868+
if ( (video_info->shader_subframes > 1)
3869+
&& (video_info->scan_subframes)
3870+
&& !black_frame_insertion
3871+
&& !nonblock_state
3872+
&& !runloop_is_slowmotion
3873+
&& !runloop_is_paused
3874+
&& (!(d3d12->flags & D3D12_ST_FLAG_MENU_ENABLE)))
3875+
{
3876+
D3D12_RECT scissor_rect;
3877+
3878+
scissor_rect.left = 0;
3879+
scissor_rect.top = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
3880+
* (float)video_info->current_subframe);
3881+
scissor_rect.right = video_width ;
3882+
scissor_rect.bottom = (unsigned int)(((float)video_height / (float)video_info->shader_subframes)
3883+
* (float)(video_info->current_subframe + 1));
3884+
3885+
cmd->lpVtbl->RSSetScissorRects(cmd, 1, &scissor_rect);
3886+
}
3887+
else
3888+
#endif // D3D12_ROLLING_SCANLINE_SIMULATION
3889+
{
3890+
cmd->lpVtbl->RSSetScissorRects(cmd, 1, &d3d12->frame.scissorRect);
3891+
}
38403892

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

@@ -4046,6 +4098,10 @@ static bool d3d12_gfx_frame(
40464098
d3d12->flags |= D3D12_ST_FLAG_FRAME_DUPE_LOCK;
40474099
for (k = 1; k < video_info->shader_subframes; k++)
40484100
{
4101+
#ifdef D3D12_ROLLING_SCANLINE_SIMULATION
4102+
video_info->current_subframe = k;
4103+
#endif // D3D12_ROLLING_SCANLINE_SIMULATION
4104+
40494105
if (d3d12->shader_preset)
40504106
for (m = 0; m < d3d12->shader_preset->passes; m++)
40514107
{

gfx/drivers/gl3.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,6 +2604,25 @@ static bool gl3_frame(void *data, const void *frame,
26042604
gl->filter_chain, 1);
26052605
}
26062606

2607+
#ifdef GL3_ROLLING_SCANLINE_SIMULATION
2608+
if ( (video_info->shader_subframes > 1)
2609+
&& (video_info->scan_subframes)
2610+
&& !video_info->black_frame_insertion
2611+
&& !video_info->input_driver_nonblock_state
2612+
&& !video_info->runloop_is_slowmotion
2613+
&& !video_info->runloop_is_paused
2614+
&& (!(gl->flags & GL3_FLAG_MENU_TEXTURE_ENABLE)))
2615+
{
2616+
gl3_filter_chain_set_simulate_scanline(
2617+
gl->filter_chain, true);
2618+
}
2619+
else
2620+
{
2621+
gl3_filter_chain_set_simulate_scanline(
2622+
gl->filter_chain, false);
2623+
}
2624+
#endif // GL3_ROLLING_SCANLINE_SIMULATION
2625+
26072626
gl3_filter_chain_set_input_texture(gl->filter_chain, &texture);
26082627
gl3_filter_chain_build_offscreen_passes(gl->filter_chain,
26092628
&gl->filter_chain_vp);

0 commit comments

Comments
 (0)