From 32aa24f6fd78a22be294c869efe757c88c7c7b6a Mon Sep 17 00:00:00 2001 From: KrossX Date: Wed, 21 Dec 2022 14:12:50 -0300 Subject: [PATCH] GS: Add fancy downsampling shaders. --- bin/resources/shaders/dx11/present.fx | 42 +++++++++++++++++++ bin/resources/shaders/opengl/present.glsl | 45 +++++++++++++++++++++ bin/resources/shaders/vulkan/present.glsl | 40 ++++++++++++++++++ pcsx2-qt/Settings/GraphicsSettingsWidget.ui | 10 +++++ pcsx2/GS/Renderers/Common/GSDevice.cpp | 14 ++++--- pcsx2/GS/Renderers/Common/GSDevice.h | 2 + pcsx2/GS/Renderers/Common/GSRenderer.cpp | 5 ++- pcsx2/GS/Renderers/Metal/present.metal | 37 +++++++++++++++++ pcsx2/ImGui/FullscreenUI.cpp | 2 +- 9 files changed, 188 insertions(+), 9 deletions(-) diff --git a/bin/resources/shaders/dx11/present.fx b/bin/resources/shaders/dx11/present.fx index ca682a9f20..986e380a7e 100644 --- a/bin/resources/shaders/dx11/present.fx +++ b/bin/resources/shaders/dx11/present.fx @@ -395,4 +395,46 @@ PS_OUTPUT ps_filter_lottes(PS_INPUT input) return output; } +PS_OUTPUT ps_4x_rgss(PS_INPUT input) +{ + PS_OUTPUT output; + + float2 dxy = float2(ddx(input.t.x), ddy(input.t.y)); + float3 color = 0; + + float s = 1.0/8.0; + float l = 3.0/8.0; + + color += sample_c(input.t + float2( s, l) * dxy).rgb; + color += sample_c(input.t + float2( l,-s) * dxy).rgb; + color += sample_c(input.t + float2(-s,-l) * dxy).rgb; + color += sample_c(input.t + float2(-l, s) * dxy).rgb; + + output.c = float4(color * 0.25,1); + return output; +} + +PS_OUTPUT ps_automagical_supersampling(PS_INPUT input) +{ + PS_OUTPUT output; + + float2 ratio = (u_source_size / u_target_size) * 0.5; + float2 steps = floor(ratio); + float3 col = sample_c(input.t).rgb; + float div = 1; + + for (float y = 0; y < steps.y; y++) + { + for (float x = 0; x < steps.x; x++) + { + float2 offset = float2(x,y) - ratio * 0.5; + col += sample_c(input.t + offset * u_rcp_source_resolution * 2.0).rgb; + div++; + } + } + + output.c = float4(col / div, 1); + return output; +} + #endif diff --git a/bin/resources/shaders/opengl/present.glsl b/bin/resources/shaders/opengl/present.glsl index ce713965e0..9ab11b3ece 100644 --- a/bin/resources/shaders/opengl/present.glsl +++ b/bin/resources/shaders/opengl/present.glsl @@ -54,6 +54,11 @@ vec4 sample_c() return texture(TextureSampler, PSin_t); } +vec4 sample_c(vec2 uv) +{ + return texture(TextureSampler, uv); +} + vec4 ps_crt(uint i) { vec4 mask[4] = vec4[4]( @@ -384,4 +389,44 @@ void ps_filter_lottes() #endif +#ifdef ps_4x_rgss +void ps_4x_rgss() +{ + vec2 dxy = vec2(dFdx(PSin_t.x), dFdy(PSin_t.y)); + vec3 color = vec3(0); + + float s = 1.0/8.0; + float l = 3.0/8.0; + + color += sample_c(PSin_t + vec2( s, l) * dxy).rgb; + color += sample_c(PSin_t + vec2( l,-s) * dxy).rgb; + color += sample_c(PSin_t + vec2(-s,-l) * dxy).rgb; + color += sample_c(PSin_t + vec2(-l, s) * dxy).rgb; + + SV_Target0 = vec4(color * 0.25,1); +} +#endif + +#ifdef ps_automagical_supersampling +void ps_automagical_supersampling() +{ + vec2 ratio = (u_source_size / u_target_size) * 0.5; + vec2 steps = floor(ratio); + vec3 col = sample_c(PSin_t).rgb; + float div = 1; + + for (float y = 0; y < steps.y; y++) + { + for (float x = 0; x < steps.x; x++) + { + vec2 offset = vec2(x,y) - ratio * 0.5; + col += sample_c(PSin_t + offset * u_rcp_source_resolution * 2.0).rgb; + div++; + } + } + + SV_Target0 = vec4(col / div, 1); +} +#endif + #endif diff --git a/bin/resources/shaders/vulkan/present.glsl b/bin/resources/shaders/vulkan/present.glsl index f03082892e..f7eedb16aa 100644 --- a/bin/resources/shaders/vulkan/present.glsl +++ b/bin/resources/shaders/vulkan/present.glsl @@ -359,4 +359,44 @@ void ps_filter_lottes() #endif +#ifdef ps_4x_rgss +void ps_4x_rgss() +{ + vec2 dxy = vec2(dFdx(v_tex.x), dFdy(v_tex.y)); + vec3 color = vec3(0); + + float s = 1.0/8.0; + float l = 3.0/8.0; + + color += sample_c(v_tex + vec2( s, l) * dxy).rgb; + color += sample_c(v_tex + vec2( l,-s) * dxy).rgb; + color += sample_c(v_tex + vec2(-s,-l) * dxy).rgb; + color += sample_c(v_tex + vec2(-l, s) * dxy).rgb; + + o_col0 = vec4(color * 0.25,1); +} +#endif + +#ifdef ps_automagical_supersampling +void ps_automagical_supersampling() +{ + vec2 ratio = (u_source_size / u_target_size) * 0.5; + vec2 steps = floor(ratio); + vec3 col = sample_c(v_tex).rgb; + float div = 1; + + for (float y = 0; y < steps.y; y++) + { + for (float x = 0; x < steps.x; x++) + { + vec2 offset = vec2(x,y) - ratio * 0.5; + col += sample_c(v_tex + offset * u_rcp_source_resolution * 2.0).rgb; + div++; + } + } + + o_col0 = vec4(col / div, 1); +} +#endif + #endif diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui index 990cfa78b2..9e807996bb 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui @@ -1479,6 +1479,16 @@ Lottes CRT + + + 4xRGSS downsampling (4x Rotated Grid SuperSampling) + + + + + NxAGSS downsampling (Nx Automatic Grid SuperSampling) + + diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index a3d81862ec..f0c13acb80 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -68,12 +68,14 @@ const char* shaderName(PresentShader value) switch (value) { // clang-format off - case PresentShader::COPY: return "ps_copy"; - case PresentShader::SCANLINE: return "ps_filter_scanlines"; - case PresentShader::DIAGONAL_FILTER: return "ps_filter_diagonal"; - case PresentShader::TRIANGULAR_FILTER: return "ps_filter_triangular"; - case PresentShader::COMPLEX_FILTER: return "ps_filter_complex"; - case PresentShader::LOTTES_FILTER: return "ps_filter_lottes"; + case PresentShader::COPY: return "ps_copy"; + case PresentShader::SCANLINE: return "ps_filter_scanlines"; + case PresentShader::DIAGONAL_FILTER: return "ps_filter_diagonal"; + case PresentShader::TRIANGULAR_FILTER: return "ps_filter_triangular"; + case PresentShader::COMPLEX_FILTER: return "ps_filter_complex"; + case PresentShader::LOTTES_FILTER: return "ps_filter_lottes"; + case PresentShader::SUPERSAMPLE_4xRGSS: return "ps_4x_rgss"; + case PresentShader::SUPERSAMPLE_AUTO: return "ps_automagical_supersampling"; // clang-format on default: ASSERT(0); diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index 9427528327..2ceac2459b 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -131,6 +131,8 @@ enum class PresentShader TRIANGULAR_FILTER, COMPLEX_FILTER, LOTTES_FILTER, + SUPERSAMPLE_4xRGSS, + SUPERSAMPLE_AUTO, Count }; diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index 825c601957..3dfbce0e9f 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -44,10 +44,11 @@ #include #include -static constexpr std::array s_tv_shader_indices = { +static constexpr std::array s_tv_shader_indices = { PresentShader::COPY, PresentShader::SCANLINE, PresentShader::DIAGONAL_FILTER, PresentShader::TRIANGULAR_FILTER, - PresentShader::COMPLEX_FILTER, PresentShader::LOTTES_FILTER}; + PresentShader::COMPLEX_FILTER, PresentShader::LOTTES_FILTER, + PresentShader::SUPERSAMPLE_4xRGSS, PresentShader::SUPERSAMPLE_AUTO}; static std::deque s_screenshot_threads; static std::mutex s_screenshot_threads_mutex; diff --git a/pcsx2/GS/Renderers/Metal/present.metal b/pcsx2/GS/Renderers/Metal/present.metal index 96b5084770..a7e173b979 100644 --- a/pcsx2/GS/Renderers/Metal/present.metal +++ b/pcsx2/GS/Renderers/Metal/present.metal @@ -328,3 +328,40 @@ fragment float4 ps_filter_lottes(ConvertShaderData data [[stage_in]], ConvertPSR { return LottesCRTPass(res, uniform).Run(data.p); } + +fragment float4 ps_4x_rgss(ConvertShaderData data [[stage_in]], ConvertPSRes res) +{ + float2 dxy = float2(dfdx(data.t.x), dfdy(data.t.y)); + float3 color = 0; + + float s = 1.0/8.0; + float l = 3.0/8.0; + + color += res.sample(data.t + float2( s, l) * dxy).rgb; + color += res.sample(data.t + float2( l,-s) * dxy).rgb; + color += res.sample(data.t + float2(-s,-l) * dxy).rgb; + color += res.sample(data.t + float2(-l, s) * dxy).rgb; + + return float4(color * 0.25,1); +} + +fragment float4 ps_automagical_supersampling(ConvertShaderData data [[stage_in]], ConvertPSRes res, + constant GSMTLPresentPSUniform& cb [[buffer(GSMTLBufferIndexUniforms)]]) +{ + float2 ratio = (cb.source_size / cb.target_size) * 0.5; + float2 steps = floor(ratio); + float3 col = res.sample(data.t).rgb; + float div = 1; + + for (float y = 0; y < steps.y; y++) + { + for (float x = 0; x < steps.x; x++) + { + float2 offset = float2(x,y) - ratio * 0.5; + col += res.sample(data.t + offset * cb.rcp_source_resolution * 2.0).rgb; + div++; + } + } + + return float4(col / div, 1); +} diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index ff09f9a8ca..c3d13ba8e8 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -3349,7 +3349,7 @@ void FullscreenUI::DrawGraphicsSettingsPage() 1, 100, "%d", shadeboost_active); static constexpr const char* s_tv_shaders[] = { - "None (Default)", "Scanline Filter", "Diagonal Filter", "Triangular Filter", "Wave Filter", "Lottes CRT"}; + "None (Default)", "Scanline Filter", "Diagonal Filter", "Triangular Filter", "Wave Filter", "Lottes CRT", "4xRGSS", "NxAGSS"}; DrawIntListSetting( bsi, "TV Shaders", "Selects post-processing TV shader.", "EmuCore/GS", "TVShader", 0, s_tv_shaders, std::size(s_tv_shaders)); }