From e14d6d595c36a38b4798e0774154aac7c578905a Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Thu, 1 Aug 2024 21:05:50 +0200 Subject: [PATCH] Ported RetroArch Aperture CRT shader but not much better than Easymode --- base/devtools.cfg | 3 +- neo/framework/Console.cpp | 4 +- neo/renderer/RenderProgs.cpp | 2 +- neo/shaders/builtin/post/crt_aperture.ps.hlsl | 294 ++++++++++-------- neo/shaders/builtin/post/crt_easymode.ps.hlsl | 2 +- neo/shaders/shaders.cfg | 2 + 6 files changed, 165 insertions(+), 142 deletions(-) diff --git a/base/devtools.cfg b/base/devtools.cfg index 48cbfb30..7144cf0d 100644 --- a/base/devtools.cfg +++ b/base/devtools.cfg @@ -8,7 +8,8 @@ bind "F2" "toggle r_showTris 1 2 0" bind "F3" "toggle r_forceAmbient 0.5 1.0 0" bind "F4" "toggle r_skipInteractions" bind "F5" "savegame quick" -bind "F6" "toggle r_showLightGrid 1 3 4 0" +//bind "F6" "toggle r_showLightGrid 1 3 4 0" +bind "F6" "toggle r_renderMode 0 1 3 5 7 9 11" bind "F7" "toggle r_renderMode 0 1 2 3 4 5 6 7 8 9 10 11" bind "F8" "toggle r_useCRTPostFX 0 1 2 3" bind "F9" "loadgame quick" diff --git a/neo/framework/Console.cpp b/neo/framework/Console.cpp index 9d333c55..54332f47 100644 --- a/neo/framework/Console.cpp +++ b/neo/framework/Console.cpp @@ -455,8 +455,8 @@ float idConsoleLocal::DrawFPS( float y ) "CPC Hi", "NES", "NES Hi", - "Sega", - "Sega Hi", + "Sega MD", + "Sega MD Hi", "Sony PSX", }; diff --git a/neo/renderer/RenderProgs.cpp b/neo/renderer/RenderProgs.cpp index c27f75c9..674766f4 100644 --- a/neo/renderer/RenderProgs.cpp +++ b/neo/renderer/RenderProgs.cpp @@ -539,7 +539,7 @@ void idRenderProgManager::Init( nvrhi::IDevice* device ) { BUILTIN_POSTPROCESS_RETRO_PSX, "builtin/post/retro_ps1", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL }, { BUILTIN_CRT_MATTIAS, "builtin/post/crt_mattias", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL }, { BUILTIN_CRT_NUPIXIE, "builtin/post/crt_newpixie", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL }, - { BUILTIN_CRT_EASYMODE, "builtin/post/crt_easymode", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL }, + { BUILTIN_CRT_EASYMODE, "builtin/post/crt_aperture", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL }, { BUILTIN_SCREEN, "builtin/post/screen", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT }, { BUILTIN_TONEMAP, "builtin/post/tonemap", "", { { "BRIGHTPASS", "0" }, { "HDR_DEBUG", "0"} }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT }, diff --git a/neo/shaders/builtin/post/crt_aperture.ps.hlsl b/neo/shaders/builtin/post/crt_aperture.ps.hlsl index aee8b8a4..87e1ced7 100644 --- a/neo/shaders/builtin/post/crt_aperture.ps.hlsl +++ b/neo/shaders/builtin/post/crt_aperture.ps.hlsl @@ -51,7 +51,7 @@ struct PS_OUT }; // *INDENT-ON* -#define TEX2D(c) dilate(t_CurrentRender.Sample( s_LinearClamp, c ).rgba) +#define TEX2D(c) dilate(t_CurrentRender.Sample( s_LinearClamp, c ).rgb) #define FIX(c) max(abs(c), 1e-5) // Set to 0 to use linear filter and gain speed @@ -59,16 +59,40 @@ struct PS_OUT #define RESOLUTION_DIVISOR 4.0 -float4 dilate( float4 col ) +struct Params +{ + float4 sourceSize; + float4 outputSize; + uint FrameCount; + + float SHARPNESS_IMAGE; + float SHARPNESS_EDGES; + float GLOW_WIDTH; + float GLOW_HEIGHT; + float GLOW_HALATION; + float GLOW_DIFFUSION; + float MASK_COLORS; + float MASK_STRENGTH; + float MASK_SIZE; + float SCANLINE_SIZE_MIN; + float SCANLINE_SIZE_MAX; + float SCANLINE_SHAPE; + float SCANLINE_OFFSET; + float GAMMA_INPUT; + float GAMMA_OUTPUT; + float BRIGHTNESS; +}; + +float3 dilate( float3 col ) { -#if 1 // FIXME - //float4 x = lerp( _float4( 1.0 ), col, params.DILATION ); - float4 x = lerp( _float4( 1.0 ), col, 1.0 ); - return col * x; -#else - return col; -#endif + //return pow(col, float3(params.GAMMA_INPUT)) + return pow( col, _float3( 2.4 ) ); +} + +float mod( float x, float y ) +{ + return x - y * floor( x / y ); } float curve_distance( float x, float sharp ) @@ -85,31 +109,106 @@ float curve_distance( float x, float sharp ) return lerp( x, curve, sharp ); } -float4x4 get_color_matrix( float2 co, float2 dx ) +float3x3 get_color_matrix( float2 co, float2 dx ) { - return float4x4( TEX2D( co - dx ), TEX2D( co ), TEX2D( co + dx ), TEX2D( co + 2.0 * dx ) ); + return float3x3( TEX2D( co - dx ), TEX2D( co ), TEX2D( co + dx ) ); +} +float3 blur( float3x3 m, float dist, float rad ) +{ + float3 x = float3( dist - 1.0, dist, dist + 1.0 ) / rad; + float3 w = exp2( x * x * -1.0 ); - // transpose for HLSL - //m = transpose(m); - //return m; + return ( m[0] * w.x + m[1] * w.y + m[2] * w.z ) / ( w.x + w.y + w.z ); } -float3 filter_lanczos( float4 coeffs, float4x4 color_matrix ) +float3 filter_gaussian( float2 co, float2 tex_size, Params params ) { - float4 col = mul( color_matrix, coeffs ); - float4 sample_min = min( color_matrix[1], color_matrix[2] ); - float4 sample_max = max( color_matrix[1], color_matrix[2] ); + float2 dx = float2( 1.0 / tex_size.x, 0.0 ); + float2 dy = float2( 0.0, 1.0 / tex_size.y ); + float2 pix_co = co * tex_size; + float2 tex_co = ( floor( pix_co ) + 0.5 ) / tex_size; + float2 dist = ( frac( pix_co ) - 0.5 ) * -1.0; + + float3x3 line0 = get_color_matrix( tex_co - dy, dx ); + float3x3 line1 = get_color_matrix( tex_co, dx ); + float3x3 line2 = get_color_matrix( tex_co + dy, dx ); + float3x3 column = float3x3( blur( line0, dist.x, params.GLOW_WIDTH ), + blur( line1, dist.x, params.GLOW_WIDTH ), + blur( line2, dist.x, params.GLOW_WIDTH ) ); + + return blur( column, dist.y, params.GLOW_HEIGHT ); +} + +float3 filter_lanczos2( float4 coeffs, float3x3 color_matrix ) +{ + float3 col = mul( color_matrix, coeffs.rgb ); + float3 sample_min = min( color_matrix[1], color_matrix[2] ); + float3 sample_max = max( color_matrix[1], color_matrix[2] ); col = clamp( col, sample_min, sample_max ); return col.rgb; } -float mod( float x, float y ) +float3 filter_lanczos( float2 co, float2 tex_size, float sharp ) { - return x - y * floor( x / y ); + tex_size.x *= sharp; + + float2 dx = float2( 1.0 / tex_size.x, 0.0 ); + float2 pix_co = co * tex_size - float2( 0.5, 0.0 ); + float2 tex_co = ( floor( pix_co ) + float2( 0.5, 0.001 ) ) / tex_size; + float2 dist = frac( pix_co ); + float4 coef = PI * float4( dist.x + 1.0, dist.x, dist.x - 1.0, dist.x - 2.0 ); + + coef = FIX( coef ); + coef = 2.0 * sin( coef ) * sin( coef / 2.0 ) / ( coef * coef ); + coef /= dot( coef, _float4( 1.0 ) ); + +#if 0 + float4 col1 = float4( TEX2D( tex_co ), 1.0 ); + float4 col2 = float4( TEX2D( tex_co + dx ), 1.0 ); + + return ( mul( float4x4( col1, col1, col2, col2 ), coef ) ).rgb; +#else + float3 col = filter_lanczos2( coef, get_color_matrix( tex_co, _float2( 0 ) ) ); + float3 col2 = filter_lanczos2( coef, get_color_matrix( tex_co, dx ) ); + + //col = lerp( col, col2, curve_distance( dist.y, params.SHARPNESS_V ) ); + col = lerp( col, col2, sharp ); + + return col; +#endif } +float3 get_scanline_weight( float x, float3 col, Params params ) +{ + float3 beam = lerp( _float3( params.SCANLINE_SIZE_MIN ), _float3( params.SCANLINE_SIZE_MAX ), pow( col, _float3( 1.0 / params.SCANLINE_SHAPE ) ) ); + float3 x_mul = 2.0 / beam; + float3 x_offset = x_mul * 0.5; + + return smoothstep( 0.0, 1.0, 1.0 - abs( x * x_mul - x_offset ) ) * x_offset; +} + +float3 get_mask_weight( float x, Params params ) +{ + float i = mod( floor( x * params.outputSize.x * params.sourceSize.x / ( params.sourceSize.x * params.MASK_SIZE ) ), params.MASK_COLORS ); + + if( i == 0.0 ) + { + return lerp( float3( 1.0, 0.0, 1.0 ), float3( 1.0, 0.0, 0.0 ), params.MASK_COLORS - 2.0 ); + } + else if( i == 1.0 ) + { + return float3( 0.0, 1.0, 0.0 ); + } + else + { + return float3( 0.0, 0.0, 1.0 ); + } +} + + + float2 curve( float2 uv, float curvature ) { uv = ( uv - 0.5 ) * curvature; @@ -125,137 +224,58 @@ void main( PS_IN fragment, out PS_OUT result ) { // revised version from RetroArch - struct Params - { - float BRIGHT_BOOST; - float DILATION; - float GAMMA_INPUT; - float GAMMA_OUTPUT; - float MASK_SIZE; - float MASK_STAGGER; - float MASK_STRENGTH; - float MASK_DOT_HEIGHT; - float MASK_DOT_WIDTH; - float SCANLINE_CUTOFF; - float SCANLINE_BEAM_WIDTH_MAX; - float SCANLINE_BEAM_WIDTH_MIN; - float SCANLINE_BRIGHT_MAX; - float SCANLINE_BRIGHT_MIN; - float SCANLINE_STRENGTH; - float SHARPNESS_H; - float SHARPNESS_V; - }; - Params params; - params.BRIGHT_BOOST = 1.2; - params.DILATION = 1.0; - params.GAMMA_INPUT = 2.0; - params.GAMMA_OUTPUT = 1.8; + params.FrameCount = int( rpJitterTexOffset.w ); + params.SHARPNESS_IMAGE = 1.0; + params.SHARPNESS_EDGES = 3.0; + params.GLOW_WIDTH = 0.5; + params.GLOW_HEIGHT = 0.5; + params.GLOW_HALATION = 0.1; + params.GLOW_DIFFUSION = 0.05; + params.MASK_COLORS = 2.0; + params.MASK_STRENGTH = 0.3; params.MASK_SIZE = 1.0; - params.MASK_STAGGER = 0.0; - params.MASK_STRENGTH = 0.8; - params.MASK_DOT_HEIGHT = 1.0; - params.MASK_DOT_WIDTH = 1.0; - params.SCANLINE_CUTOFF = 400.0; - params.SCANLINE_BEAM_WIDTH_MAX = 1.5; - params.SCANLINE_BEAM_WIDTH_MIN = 1.5; - params.SCANLINE_BRIGHT_MAX = 0.65; - params.SCANLINE_BRIGHT_MIN = 0.35; - params.SCANLINE_STRENGTH = 1.0; - params.SHARPNESS_H = 0.5; - params.SHARPNESS_V = 1.0; - + params.SCANLINE_SIZE_MIN = 0.5; + params.SCANLINE_SIZE_MAX = 1.5; + params.SCANLINE_SHAPE = 2.5; + params.SCANLINE_OFFSET = 1.0; + params.GAMMA_INPUT = 2.4; + params.GAMMA_OUTPUT = 2.4; + params.BRIGHTNESS = 1.5; float4 outputSize; outputSize.xy = rpWindowCoord.zw; outputSize.zw = float2( 1.0, 1.0 ) / rpWindowCoord.zw; -#if 1 float4 sourceSize = outputSize; -#else - float4 sourceSize; - sourceSize.xy = rpWindowCoord.zw / float2( 4, 4.4 ); //RESOLUTION_DIVISOR; - sourceSize.zw = float2( 1.0, 1.0 ) / sourceSize.xy; -#endif - float2 vTexCoord = fragment.texcoord0.xy; + params.sourceSize = sourceSize; + params.outputSize = outputSize; -#if 0 - if( rpWindowCoord.x > 0.0 ) + float scale = floor( outputSize.y * sourceSize.w ); + float offset = 1.0 / scale * 0.5; + + if( bool( mod( scale, 2.0 ) ) ) { - vTexCoord = curve( vTexCoord, 2.0 ); - } -#endif - - float2 dx = float2( sourceSize.z, 0.0 ); - float2 dy = float2( 0.0, sourceSize.w ); - float2 pix_co = vTexCoord * sourceSize.xy - float2( 0.5, 0.5 ); - float2 tex_co = ( floor( pix_co ) + float2( 0.5, 0.5 ) ) * sourceSize.zw; - float2 dist = frac( pix_co ); - float curve_x; - float3 col, col2; - -#if ENABLE_LANCZOS - curve_x = curve_distance( dist.x, params.SHARPNESS_H * params.SHARPNESS_H ); - - float4 coeffs = PI * float4( 1.0 + curve_x, curve_x, 1.0 - curve_x, 2.0 - curve_x ); - - coeffs = FIX( coeffs ); - coeffs = 2.0 * sin( coeffs ) * sin( coeffs * 0.5 ) / ( coeffs * coeffs ); - coeffs /= dot( coeffs, _float4( 1.0 ) ); - - col = filter_lanczos( coeffs, get_color_matrix( tex_co, dx ) ); - col2 = filter_lanczos( coeffs, get_color_matrix( tex_co + dy, dx ) ); -#else - curve_x = curve_distance( dist.x, params.SHARPNESS_H ); - - col = lerp( TEX2D( tex_co ).rgb, TEX2D( tex_co + dx ).rgb, curve_x ); - col2 = lerp( TEX2D( tex_co + dy ).rgb, TEX2D( tex_co + dx + dy ).rgb, curve_x ); -#endif - - col = lerp( col, col2, curve_distance( dist.y, params.SHARPNESS_V ) ); - col = pow( col, _float3( params.GAMMA_INPUT / ( params.DILATION + 1.0 ) ) ); - - float luma = dot( float3( 0.2126, 0.7152, 0.0722 ), col ); - float bright = ( max( col.r, max( col.g, col.b ) ) + luma ) * 0.5; - float scan_bright = clamp( bright, params.SCANLINE_BRIGHT_MIN, params.SCANLINE_BRIGHT_MAX ); - float scan_beam = clamp( bright * params.SCANLINE_BEAM_WIDTH_MAX, params.SCANLINE_BEAM_WIDTH_MIN, params.SCANLINE_BEAM_WIDTH_MAX ); - float scan_weight = 1.0 - pow( cos( vTexCoord.y * 2.0 * PI * sourceSize.y / RESOLUTION_DIVISOR ) * 0.5 + 0.5, scan_beam ) * params.SCANLINE_STRENGTH; - - float mask = 1.0 - params.MASK_STRENGTH; - float2 mod_fac = floor( vTexCoord * outputSize.xy * sourceSize.xy / ( sourceSize.xy * float2( params.MASK_SIZE, params.MASK_DOT_HEIGHT * params.MASK_SIZE ) ) ); - int dot_no = int( mod( ( mod_fac.x + mod( mod_fac.y, 2.0 ) * params.MASK_STAGGER ) / params.MASK_DOT_WIDTH, 3.0 ) ); - float3 mask_weight; - - if( dot_no == 0 ) - { - mask_weight = float3( 1.0, mask, mask ); - } - else if( dot_no == 1 ) - { - mask_weight = float3( mask, 1.0, mask ); - } - else - { - mask_weight = float3( mask, mask, 1.0 ); + offset = 0.0; } -#if 0 - if( sourceSize.y >= params.SCANLINE_CUTOFF ) - { - scan_weight = 1.0; - } -#endif + float2 vTexCoord = abs( fragment.texcoord0.xy ); - col2 = col.rgb; - col *= _float3( scan_weight ); - col = lerp( col, col2, scan_bright ); - col *= mask_weight; - col = pow( col, _float3( 1.0 / params.GAMMA_OUTPUT ) ); + float2 co = ( vTexCoord * sourceSize.xy - float2( 0.0, offset * params.SCANLINE_OFFSET ) ) * sourceSize.zw; + float3 col_glow = filter_gaussian( co, sourceSize.xy, params ); + float3 col_soft = filter_lanczos( co, sourceSize.xy, params.SHARPNESS_IMAGE ); + float3 col_sharp = filter_lanczos( co, sourceSize.xy, params.SHARPNESS_EDGES ); + float3 col = sqrt( col_sharp * col_soft ); - //col = col2; - //col = _float3( scan_weight ); - //col = float3( scan_bright, scan_beam, scan_weight ); + col *= get_scanline_weight( frac( co.y * sourceSize.y / RESOLUTION_DIVISOR ), col_soft, params ); + col_glow = saturate( col_glow - col ); + col += col_glow * col_glow * params.GLOW_HALATION; + col = lerp( col, col * get_mask_weight( vTexCoord.x, params ) * params.MASK_COLORS, params.MASK_STRENGTH ); + col += col_glow * params.GLOW_DIFFUSION; + col = pow( col * params.BRIGHTNESS, _float3( 1.0 / params.GAMMA_OUTPUT ) ); - result.color = float4( col * params.BRIGHT_BOOST, 1.0 ); + //col = col_soft; + + result.color = float4( col, 1.0 ); } diff --git a/neo/shaders/builtin/post/crt_easymode.ps.hlsl b/neo/shaders/builtin/post/crt_easymode.ps.hlsl index aee8b8a4..b694349f 100644 --- a/neo/shaders/builtin/post/crt_easymode.ps.hlsl +++ b/neo/shaders/builtin/post/crt_easymode.ps.hlsl @@ -57,7 +57,7 @@ struct PS_OUT // Set to 0 to use linear filter and gain speed #define ENABLE_LANCZOS 1 -#define RESOLUTION_DIVISOR 4.0 +#define RESOLUTION_DIVISOR 6.0 float4 dilate( float4 col ) { diff --git a/neo/shaders/shaders.cfg b/neo/shaders/shaders.cfg index de3e1843..17161de7 100644 --- a/neo/shaders/shaders.cfg +++ b/neo/shaders/shaders.cfg @@ -70,6 +70,8 @@ builtin/post/crt_newpixie.vs.hlsl -T vs builtin/post/crt_newpixie.ps.hlsl -T ps builtin/post/crt_easymode.vs.hlsl -T vs builtin/post/crt_easymode.ps.hlsl -T ps +builtin/post/crt_aperture.vs.hlsl -T vs +builtin/post/crt_aperture.ps.hlsl -T ps builtin/post/screen.vs.hlsl -T vs builtin/post/screen.ps.hlsl -T ps builtin/post/tonemap.vs.hlsl -T vs -D BRIGHTPASS={0,1} -D HDR_DEBUG={0,1}