From b26acad721db5a88958c4d292c6f0f5b39eed832 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 19 Mar 2023 16:39:57 +1000 Subject: [PATCH] GS: Sample LOD 0 explicitly in interlace shaders Can't use normal sampling because the derivates are undefined in non-uniform control flow (in MAD). --- bin/resources/shaders/dx11/interlace.fx | 26 ++++++++++---------- bin/resources/shaders/opengl/interlace.glsl | 26 ++++++++++---------- bin/resources/shaders/vulkan/interlace.glsl | 26 ++++++++++---------- pcsx2/GS/Renderers/Metal/GSMTLShaderCommon.h | 4 +++ pcsx2/GS/Renderers/Metal/interlace.metal | 26 ++++++++++---------- 5 files changed, 56 insertions(+), 52 deletions(-) diff --git a/bin/resources/shaders/dx11/interlace.fx b/bin/resources/shaders/dx11/interlace.fx index da9d711b37..2532c8fefd 100644 --- a/bin/resources/shaders/dx11/interlace.fx +++ b/bin/resources/shaders/dx11/interlace.fx @@ -23,7 +23,7 @@ float4 ps_main0(PS_INPUT input) : SV_Target0 const int vpos = int(input.p.y); // vertical position of destination texture if ((vpos & 1) == field) - return Texture.Sample(Sampler, input.t); + return Texture.SampleLevel(Sampler, input.t, 0); else discard; @@ -34,7 +34,7 @@ float4 ps_main0(PS_INPUT input) : SV_Target0 // Bob shader float4 ps_main1(PS_INPUT input) : SV_Target0 { - return Texture.Sample(Sampler, input.t); + return Texture.SampleLevel(Sampler, input.t, 0); } @@ -42,9 +42,9 @@ float4 ps_main1(PS_INPUT input) : SV_Target0 float4 ps_main2(PS_INPUT input) : SV_Target0 { float2 vstep = float2(0.0f, ZrH.y); - float4 c0 = Texture.Sample(Sampler, input.t - vstep); - float4 c1 = Texture.Sample(Sampler, input.t); - float4 c2 = Texture.Sample(Sampler, input.t + vstep); + float4 c0 = Texture.SampleLevel(Sampler, input.t - vstep, 0); + float4 c1 = Texture.SampleLevel(Sampler, input.t, 0); + float4 c2 = Texture.SampleLevel(Sampler, input.t + vstep, 0); return (c0 + c1 * 2 + c2) / 4; } @@ -74,7 +74,7 @@ float4 ps_main3(PS_INPUT input) : SV_Target0 // if the index of current destination line belongs to the current fiels we update it, otherwise // we leave the old line in the destination buffer if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field)) - return Texture.Sample(Sampler, iptr); + return Texture.SampleLevel(Sampler, iptr, 0); else discard; @@ -133,13 +133,13 @@ float4 ps_main4(PS_INPUT input) : SV_Target0 // calculating motion, only relevant for missing lines where the "center line" is pointed by p_t1 - float4 hn = Texture.Sample(Sampler, p_t0 - lofs); // new high pixel - float4 cn = Texture.Sample(Sampler, p_t1); // new center pixel - float4 ln = Texture.Sample(Sampler, p_t0 + lofs); // new low pixel + float4 hn = Texture.SampleLevel(Sampler, p_t0 - lofs, 0); // new high pixel + float4 cn = Texture.SampleLevel(Sampler, p_t1, 0); // new center pixel + float4 ln = Texture.SampleLevel(Sampler, p_t0 + lofs, 0); // new low pixel - float4 ho = Texture.Sample(Sampler, p_t2 - lofs); // old high pixel - float4 co = Texture.Sample(Sampler, p_t3); // old center pixel - float4 lo = Texture.Sample(Sampler, p_t2 + lofs); // old low pixel + float4 ho = Texture.SampleLevel(Sampler, p_t2 - lofs, 0); // old high pixel + float4 co = Texture.SampleLevel(Sampler, p_t3, 0); // old center pixel + float4 lo = Texture.SampleLevel(Sampler, p_t2 + lofs, 0); // old low pixel float3 mh = hn.rgb - ho.rgb; // high pixel motion float3 mc = cn.rgb - co.rgb; // center pixel motion @@ -164,7 +164,7 @@ float4 ps_main4(PS_INPUT input) : SV_Target0 if ((vpos & 1) == field) { // output coordinate present on current field - return Texture.Sample(Sampler, p_t0); + return Texture.SampleLevel(Sampler, p_t0, 0); } else if ((iptr.y > 0.5f - lofs.y) || (iptr.y < 0.0 + lofs.y)) { diff --git a/bin/resources/shaders/opengl/interlace.glsl b/bin/resources/shaders/opengl/interlace.glsl index 33d283a705..6c8f9e1644 100644 --- a/bin/resources/shaders/opengl/interlace.glsl +++ b/bin/resources/shaders/opengl/interlace.glsl @@ -19,7 +19,7 @@ void ps_main0() int vpos = int(gl_FragCoord.y); // vertical position of destination texture if ((vpos & 1) == field) - SV_Target0 = texture(TextureSampler, PSin_t); + SV_Target0 = textureLod(TextureSampler, PSin_t, 0); else discard; } @@ -28,7 +28,7 @@ void ps_main0() // Bob shader void ps_main1() { - SV_Target0 = texture(TextureSampler, PSin_t); + SV_Target0 = textureLod(TextureSampler, PSin_t, 0); } @@ -36,9 +36,9 @@ void ps_main1() void ps_main2() { vec2 vstep = vec2(0.0f, ZrH.y); - vec4 c0 = texture(TextureSampler, PSin_t - vstep); - vec4 c1 = texture(TextureSampler, PSin_t); - vec4 c2 = texture(TextureSampler, PSin_t + vstep); + vec4 c0 = textureLod(TextureSampler, PSin_t - vstep, 0); + vec4 c1 = textureLod(TextureSampler, PSin_t, 0); + vec4 c2 = textureLod(TextureSampler, PSin_t + vstep, 0); SV_Target0 = (c0 + c1 * 2.0f + c2) / 4.0f; } @@ -68,7 +68,7 @@ void ps_main3() // if the index of current destination line belongs to the current fiels we update it, otherwise // we leave the old line in the destination buffer if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field)) - SV_Target0 = texture(TextureSampler, iptr); + SV_Target0 = textureLod(TextureSampler, iptr, 0); else discard; } @@ -126,13 +126,13 @@ void ps_main4() // calculating motion, only relevant for missing lines where the "center line" is pointed // by p_t1 - vec4 hn = texture(TextureSampler, p_t0 - lofs); // new high pixel - vec4 cn = texture(TextureSampler, p_t1); // new center pixel - vec4 ln = texture(TextureSampler, p_t0 + lofs); // new low pixel + vec4 hn = textureLod(TextureSampler, p_t0 - lofs, 0); // new high pixel + vec4 cn = textureLod(TextureSampler, p_t1, 0); // new center pixel + vec4 ln = textureLod(TextureSampler, p_t0 + lofs, 0); // new low pixel - vec4 ho = texture(TextureSampler, p_t2 - lofs); // old high pixel - vec4 co = texture(TextureSampler, p_t3); // old center pixel - vec4 lo = texture(TextureSampler, p_t2 + lofs); // old low pixel + vec4 ho = textureLod(TextureSampler, p_t2 - lofs, 0); // old high pixel + vec4 co = textureLod(TextureSampler, p_t3, 0); // old center pixel + vec4 lo = textureLod(TextureSampler, p_t2 + lofs, 0); // old low pixel vec3 mh = hn.rgb - ho.rgb; // high pixel motion vec3 mc = cn.rgb - co.rgb; // center pixel motion @@ -158,7 +158,7 @@ void ps_main4() if ((vpos & 1) == field) { // output coordinate present on current field - SV_Target0 = texture(TextureSampler, p_t0); + SV_Target0 = textureLod(TextureSampler, p_t0, 0); } else if ((iptr.y > 0.5f - lofs.y) || (iptr.y < 0.0 + lofs.y)) { diff --git a/bin/resources/shaders/vulkan/interlace.glsl b/bin/resources/shaders/vulkan/interlace.glsl index cee958d4c4..551ac12780 100644 --- a/bin/resources/shaders/vulkan/interlace.glsl +++ b/bin/resources/shaders/vulkan/interlace.glsl @@ -35,7 +35,7 @@ void ps_main0() const int vpos = int(gl_FragCoord.y); // vertical position of destination texture if ((vpos & 1) == field) - o_col0 = texture(samp0, v_tex); + o_col0 = textureLod(samp0, v_tex, 0); else discard; } @@ -46,7 +46,7 @@ void ps_main0() #ifdef ps_main1 void ps_main1() { - o_col0 = texture(samp0, v_tex); + o_col0 = textureLod(samp0, v_tex, 0); } #endif @@ -56,9 +56,9 @@ void ps_main1() void ps_main2() { vec2 vstep = vec2(0.0f, ZrH.y); - vec4 c0 = texture(samp0, v_tex - vstep); - vec4 c1 = texture(samp0, v_tex); - vec4 c2 = texture(samp0, v_tex + vstep); + vec4 c0 = textureLod(samp0, v_tex - vstep, 0); + vec4 c1 = textureLod(samp0, v_tex, 0); + vec4 c2 = textureLod(samp0, v_tex + vstep, 0); o_col0 = (c0 + c1 * 2.0f + c2) / 4.0f; } @@ -90,7 +90,7 @@ void ps_main3() // if the index of current destination line belongs to the current fiels we update it, otherwise // we leave the old line in the destination buffer if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field)) - o_col0 = texture(samp0, iptr); + o_col0 = textureLod(samp0, iptr, 0); else discard; } @@ -150,13 +150,13 @@ void ps_main4() // calculating motion, only relevant for missing lines where the "center line" is pointed by p_t1 - vec4 hn = texture(samp0, p_t0 - lofs); // new high pixel - vec4 cn = texture(samp0, p_t1); // new center pixel - vec4 ln = texture(samp0, p_t0 + lofs); // new low pixel + vec4 hn = textureLod(samp0, p_t0 - lofs, 0); // new high pixel + vec4 cn = textureLod(samp0, p_t1, 0); // new center pixel + vec4 ln = textureLod(samp0, p_t0 + lofs, 0); // new low pixel - vec4 ho = texture(samp0, p_t2 - lofs); // old high pixel - vec4 co = texture(samp0, p_t3); // old center pixel - vec4 lo = texture(samp0, p_t2 + lofs); // old low pixel + vec4 ho = textureLod(samp0, p_t2 - lofs, 0); // old high pixel + vec4 co = textureLod(samp0, p_t3, 0); // old center pixel + vec4 lo = textureLod(samp0, p_t2 + lofs, 0); // old low pixel vec3 mh = hn.rgb - ho.rgb; // high pixel motion vec3 mc = cn.rgb - co.rgb; // center pixel motion @@ -181,7 +181,7 @@ void ps_main4() if ((vpos & 1) == field) // output coordinate present on current field { // output coordinate present on current field - o_col0 = texture(samp0, p_t0); + o_col0 = textureLod(samp0, p_t0, 0); } else if ((iptr.y > 0.5f - lofs.y) || (iptr.y < 0.0 + lofs.y)) { diff --git a/pcsx2/GS/Renderers/Metal/GSMTLShaderCommon.h b/pcsx2/GS/Renderers/Metal/GSMTLShaderCommon.h index 48fdbcdc22..f14072bebb 100644 --- a/pcsx2/GS/Renderers/Metal/GSMTLShaderCommon.h +++ b/pcsx2/GS/Renderers/Metal/GSMTLShaderCommon.h @@ -33,6 +33,10 @@ struct ConvertPSRes { return texture.sample(s, coord); } + float4 sample_level(float2 coord, float lod) + { + return texture.sample(s, coord, level(lod)); + } }; struct ConvertPSDepthRes diff --git a/pcsx2/GS/Renderers/Metal/interlace.metal b/pcsx2/GS/Renderers/Metal/interlace.metal index 7013e71c4b..812f7aca2b 100644 --- a/pcsx2/GS/Renderers/Metal/interlace.metal +++ b/pcsx2/GS/Renderers/Metal/interlace.metal @@ -27,7 +27,7 @@ fragment float4 ps_interlace0(ConvertShaderData data [[stage_in]], ConvertPSRes const int vpos = int(data.p.y); // vertical position of destination texture if ((vpos & 1) == field) - return res.sample(data.t); + return res.sample_level(data.t, 0); else discard_fragment(); @@ -38,7 +38,7 @@ fragment float4 ps_interlace0(ConvertShaderData data [[stage_in]], ConvertPSRes // Bob shader fragment float4 ps_interlace1(ConvertShaderData data [[stage_in]], ConvertPSRes res) { - return res.sample(data.t); + return res.sample_level(data.t); } @@ -47,9 +47,9 @@ fragment float4 ps_interlace2(ConvertShaderData data [[stage_in]], ConvertPSRes constant GSMTLInterlacePSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]]) { float2 vstep = float2(0.0f, uniform.ZrH.y); - float4 c0 = res.sample(data.t - vstep); - float4 c1 = res.sample(data.t); - float4 c2 = res.sample(data.t + vstep); + float4 c0 = res.sample_level(data.t - vstep, 0); + float4 c1 = res.sample_level(data.t, 0); + float4 c2 = res.sample_level(data.t + vstep, 0); return (c0 + c1 * 2.f + c2) / 4.f; } @@ -79,7 +79,7 @@ fragment float4 ps_interlace3(ConvertShaderData data [[stage_in]], ConvertPSRes // if the index of current destination line belongs to the current fiels we update it, otherwise // we leave the old line in the destination buffer if ((optr.y >= 0.0f) && (optr.y < 0.5f) && ((vpos & 1) == field)) - return res.sample(iptr); + return res.sample_level(iptr, 0); else discard_fragment(); @@ -137,13 +137,13 @@ fragment float4 ps_interlace4(ConvertShaderData data [[stage_in]], ConvertPSRes // calculating motion, only relevant for missing lines where the "center line" is pointed by p_t1 - float4 hn = res.sample(p_t0 - lofs); // new high pixel - float4 cn = res.sample(p_t1); // new center pixel - float4 ln = res.sample(p_t0 + lofs); // new low pixel + float4 hn = res.sample_level(p_t0 - lofs, 0); // new high pixel + float4 cn = res.sample_level(p_t1, 0); // new center pixel + float4 ln = res.sample_level(p_t0 + lofs, 0); // new low pixel - float4 ho = res.sample(p_t2 - lofs); // old high pixel - float4 co = res.sample(p_t3); // old center pixel - float4 lo = res.sample(p_t2 + lofs); // old low pixel + float4 ho = res.sample_level(p_t2 - lofs, 0); // old high pixel + float4 co = res.sample_level(p_t3, 0); // old center pixel + float4 lo = res.sample_level(p_t2 + lofs, 0); // old low pixel float3 mh = hn.rgb - ho.rgb; float3 mc = cn.rgb - co.rgb; @@ -168,7 +168,7 @@ fragment float4 ps_interlace4(ConvertShaderData data [[stage_in]], ConvertPSRes if ((vpos & 1) == field) { // output coordinate present on current field - return res.sample(p_t0); + return res.sample_level(p_t0, 0); } else if ((iptr.y > 0.5f - lofs.y) || (iptr.y < 0.0 + lofs.y)) {