diff --git a/bin/resources/shaders/dx11/convert.fx b/bin/resources/shaders/dx11/convert.fx index 7bd8f2f3f6..f85867964c 100644 --- a/bin/resources/shaders/dx11/convert.fx +++ b/bin/resources/shaders/dx11/convert.fx @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team // SPDX-License-Identifier: GPL-3.0+ +#if defined(VERTEX_SHADER) + struct VS_INPUT { float4 p : POSITION; @@ -15,6 +17,21 @@ struct VS_OUTPUT float4 c : COLOR; }; +VS_OUTPUT vs_main(VS_INPUT input) +{ + VS_OUTPUT output; + + output.p = input.p; + output.t = input.t; + output.c = input.c; + + return output; +} + +#endif // VERTEX_SHADER + +#if defined(PIXEL_SHADER) + cbuffer cb0 : register(b0) { float4 BGColor; @@ -33,11 +50,22 @@ static const float3x3 rgb2yuv = Texture2D Texture; SamplerState TextureSampler; +#if HAS_FLOAT32_INPUT + +float sample_c(float2 uv) +{ + return Texture.Sample(TextureSampler, uv).r; +} + +#else + float4 sample_c(float2 uv) { return Texture.Sample(TextureSampler, uv); } +#endif + struct PS_INPUT { float4 p : SV_Position; @@ -45,36 +73,117 @@ struct PS_INPUT float4 c : COLOR; }; +#if HAS_INTEGER_OUTPUT + #define OUTPUT_TYPE uint + #define OUTPUT_SV SV_Target +#elif HAS_DEPTH_OUTPUT + #define OUTPUT_TYPE float + #define OUTPUT_SV SV_Depth +#elif HAS_FLOAT32_OUTPUT + #define OUTPUT_TYPE float + #define OUTPUT_SV SV_Target +#else + #define OUTPUT_TYPE float4 + #define OUTPUT_SV SV_Target +#endif + struct PS_OUTPUT { - float4 c : SV_Target0; + OUTPUT_TYPE o : OUTPUT_SV; }; -VS_OUTPUT vs_main(VS_INPUT input) +uint rgba8_to_uint(float4 c) { - VS_OUTPUT output; - - output.p = input.p; - output.t = input.t; - output.c = input.c; - - return output; + uint4 i = uint4(c * 255.5f) & 0xFFu; + return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24); } -PS_OUTPUT ps_copy(PS_INPUT input) +uint rgb5a1_to_uint(float4 c) { - PS_OUTPUT output; - - output.c = sample_c(input.t); - - return output; + uint4 i = uint4(c * 255.5f) & uint4(0xF8u, 0xF8u, 0xF8u, 0x80u); + return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8); } -float ps_depth_copy(PS_INPUT input) : SV_Depth +uint depth_to_uint(float d) { - return sample_c(input.t).r; + return uint(d * exp2(32.0f)); } +float4 uint_to_rgba8(uint i) +{ + return float4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f; +} + +float4 uint_to_rgb5a1(uint i) +{ + return float4(uint4(i << 3, i >> 2, i >> 7, i >> 8) & uint4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f; +} + +float uint_to_depth32(uint i) +{ + return float(i) * exp2(-32.0f); +} + +float uint_to_depth24(uint i) +{ + return float(i & 0xFFFFFFu) * exp2(-32.0f); +} + +float uint_to_depth16(uint i) +{ + return float(i & 0xFFFFu) * exp2(-32.0f); +} + +float rgba8_to_depth32(float4 val) +{ + return uint_to_depth32(rgba8_to_uint(val)); +} + +float rgba8_to_depth24(float4 val) +{ + return uint_to_depth24(rgba8_to_uint(val)); +} + +float rgba8_to_depth16(float4 val) +{ + return uint_to_depth16(rgba8_to_uint(val)); +} + +float rgb5a1_to_depth16(float4 val) +{ + return uint_to_depth16(rgb5a1_to_uint(val)); +} + +float4 depth32_to_rgba8(float d) +{ + return uint_to_rgba8(depth_to_uint(d)); +} + +float4 depth16_to_rgb5a1(float d) +{ + return uint_to_rgb5a1(depth_to_uint(d)); +} + +float depth32_to_depth24(float d) +{ + return uint_to_depth24(depth_to_uint(d)); +} + +#if defined(__ps_copy__) +OUTPUT_TYPE ps_copy(PS_INPUT input) : OUTPUT_SV +{ + return sample_c(input.t); +} +#endif + +#if defined(__ps_depth_copy__) +OUTPUT_TYPE ps_depth_copy(PS_INPUT input) : OUTPUT_SV +{ + return sample_c(input.t); +} +#endif + +#if defined(__ps_downsample_copy__) PS_OUTPUT ps_downsample_copy(PS_INPUT input) { int DownsampleFactor = DOFFSET; @@ -85,179 +194,134 @@ PS_OUTPUT ps_downsample_copy(PS_INPUT input) int2 coord = max(int2(input.p.xy) * DownsampleFactor, ClampMin); PS_OUTPUT output; - output.c = (float4)0; + output.o = (float4)0; for (int yoff = 0; yoff < DownsampleFactor; yoff++) { for (int xoff = 0; xoff < DownsampleFactor; xoff++) - output.c += Texture.Load(int3(coord + int2(xoff * step_multiplier, yoff * step_multiplier), 0)); + output.o += Texture.Load(int3(coord + int2(xoff * step_multiplier, yoff * step_multiplier), 0)); } - output.c /= Weight; + output.o /= Weight; return output; } +#endif +#if defined(__ps_filter_transparency__) PS_OUTPUT ps_filter_transparency(PS_INPUT input) { PS_OUTPUT output; float4 c = sample_c(input.t); - output.c = float4(c.rgb, 1.0); + output.o = float4(c.rgb, 1.0); return output; } +#endif -// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life -uint ps_convert_rgba8_16bits(PS_INPUT input) : SV_Target0 +#if defined(__ps_convert_rgb5a1_16bits__) +OUTPUT_TYPE ps_convert_rgb5a1_16bits(PS_INPUT input) : OUTPUT_SV { - uint4 i = sample_c(input.t) * float4(255.5f, 255.5f, 255.5f, 255.5f); - - return ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8); + // Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life + return rgb5a1_to_uint(sample_c(input.t)); } +#endif +#if defined(__ps_datm1__) void ps_datm1(PS_INPUT input) { clip(sample_c(input.t).a - 127.5f / 255); // >= 0x80 pass } +#endif +#if defined(__ps_datm0__) void ps_datm0(PS_INPUT input) { clip(127.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass) } +#endif +#if defined(__ps_datm1_rta_correction__) void ps_datm1_rta_correction(PS_INPUT input) { clip(sample_c(input.t).a - 254.5f / 255); // >= 0x80 pass } +#endif +#if defined(__ps_datm0_rta_correction__) void ps_datm0_rta_correction(PS_INPUT input) { clip(254.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass) } +#endif +#if defined(__ps_rta_correction__) PS_OUTPUT ps_rta_correction(PS_INPUT input) { PS_OUTPUT output; float4 value = sample_c(input.t); - output.c = float4(value.rgb, value.a / (128.25f / 255.0f)); + output.o = float4(value.rgb, value.a / (128.25f / 255.0f)); return output; } +#endif +#if defined(__ps_rta_decorrection__) PS_OUTPUT ps_rta_decorrection(PS_INPUT input) { PS_OUTPUT output; float4 value = sample_c(input.t); - output.c = float4(value.rgb, value.a * (128.25f / 255.0f)); + output.o = float4(value.rgb, value.a * (128.25f / 255.0f)); return output; } +#endif +#if defined(__ps_colclip_init__) PS_OUTPUT ps_colclip_init(PS_INPUT input) { PS_OUTPUT output; float4 value = sample_c(input.t); - output.c = float4(round(value.rgb * 255) / 65535, value.a); + output.o = float4(round(value.rgb * 255) / 65535, value.a); return output; } +#endif +#if defined(__ps_colclip_resolve__) PS_OUTPUT ps_colclip_resolve(PS_INPUT input) { PS_OUTPUT output; float4 value = sample_c(input.t); - output.c = float4(float3(uint3(value.rgb * 65535.5) & 255) / 255, value.a); + output.o = float4(float3(uint3(value.rgb * 65535.5) & 255) / 255, value.a); return output; } +#endif -uint ps_convert_float32_32bits(PS_INPUT input) : SV_Target0 +#if defined(__ps_convert_depth32_32bits__) +OUTPUT_TYPE ps_convert_depth32_32bits(PS_INPUT input) : OUTPUT_SV { - // Convert a FLOAT32 depth texture into a 32 bits UINT texture - return uint(exp2(32.0f) * sample_c(input.t).r); + // Convert a depth texture into a 32 bits UINT texture + return depth_to_uint(sample_c(input.t)); } +#endif -PS_OUTPUT ps_convert_float32_rgba8(PS_INPUT input) +#if defined(__ps_convert_depth32_rgba8__) +OUTPUT_TYPE ps_convert_depth32_rgba8(PS_INPUT input) : OUTPUT_SV { - PS_OUTPUT output; - - // Convert a FLOAT32 depth texture into a RGBA color texture - uint d = uint(sample_c(input.t).r * exp2(32.0f)); - output.c = float4(uint4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / 255.0f; - - return output; + // Convert a depth texture into a RGBA color texture + return depth32_to_rgba8(sample_c(input.t)); } +#endif -PS_OUTPUT ps_convert_float16_rgb5a1(PS_INPUT input) +#if defined(__ps_convert_depth16_rgb5a1__) +OUTPUT_TYPE ps_convert_depth16_rgb5a1(PS_INPUT input) : OUTPUT_SV { - PS_OUTPUT output; - - // Convert a FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture - uint d = uint(sample_c(input.t).r * exp2(32.0f)); - output.c = float4(uint4(d << 3, d >> 2, d >> 7, d >> 8) & uint4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f; - return output; + // Convert depth (only 16 lsb) into a RGB5A1 color texture + return depth16_to_rgb5a1(sample_c(input.t)); } +#endif -float rgba8_to_depth32(float4 val) -{ - uint4 c = uint4(val * 255.5f); - return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f); -} - -float rgba8_to_depth24(float4 val) -{ - uint3 c = uint3(val.rgb * 255.5f); - return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f); -} - -float rgba8_to_depth16(float4 val) -{ - uint2 c = uint2(val.rg * 255.5f); - return float(c.r | (c.g << 8)) * exp2(-32.0f); -} - -float rgb5a1_to_depth16(float4 val) -{ - uint4 c = uint4(val * 255.5f); - return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f); -} - -float ps_convert_float32_depth_to_color(PS_INPUT input) : SV_Target0 -{ - return sample_c(input.t).r; -} - -float ps_convert_float32_color_to_depth(PS_INPUT input) : SV_Depth -{ - return sample_c(input.t).r; -} - -float ps_convert_float32_float24(PS_INPUT input) : SV_Depth +#if defined(__ps_convert_depth32_depth24__) +OUTPUT_TYPE ps_convert_depth32_depth24(PS_INPUT input) : OUTPUT_SV { // Truncates depth value to 24bits - uint d = uint(sample_c(input.t).r * exp2(32.0f)) & 0xFFFFFFu; - return float(d) * exp2(-32.0f); -} - -float ps_convert_rgba8_float32(PS_INPUT input) : SV_Depth -{ - // Convert an RGBA texture into a float depth texture - return rgba8_to_depth32(sample_c(input.t)); -} - -float ps_convert_rgba8_float24(PS_INPUT input) : SV_Depth -{ - // Same as above but without the alpha channel (24 bits Z) - - // Convert an RGBA texture into a float depth texture - return rgba8_to_depth24(sample_c(input.t)); -} - -float ps_convert_rgba8_float16(PS_INPUT input) : SV_Depth -{ - // Same as above but without the A/B channels (16 bits Z) - - // Convert an RGBA texture into a float depth texture - return rgba8_to_depth16(sample_c(input.t)); -} - -float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth -{ - // Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z - return rgb5a1_to_depth16(sample_c(input.t)); + return depth32_to_depth24(sample_c(input.t)); } +#endif #define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \ uint width, height; \ @@ -272,34 +336,57 @@ float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth float depthBR = CONVERT_FN(Texture.Load(int3(coords.zw, 0))); \ return lerp(lerp(depthTL, depthTR, mix_vals.x), lerp(depthBL, depthBR, mix_vals.x), mix_vals.y); -float ps_convert_rgba8_float32_biln(PS_INPUT input) : SV_Depth +#if defined(__ps_convert_rgba8_depth32__) +OUTPUT_TYPE ps_convert_rgba8_depth32(PS_INPUT input) : OUTPUT_SV { // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32); +#else + return rgba8_to_depth32(sample_c(input.t)); +#endif } +#endif -float ps_convert_rgba8_float24_biln(PS_INPUT input) : SV_Depth +#if defined(__ps_convert_rgba8_depth24__) +OUTPUT_TYPE ps_convert_rgba8_depth24(PS_INPUT input) : OUTPUT_SV { // Same as above but without the alpha channel (24 bits Z) - // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24); +#else + return rgba8_to_depth24(sample_c(input.t)); +#endif } +#endif -float ps_convert_rgba8_float16_biln(PS_INPUT input) : SV_Depth +#if defined(__ps_convert_rgba8_depth16__) +OUTPUT_TYPE ps_convert_rgba8_depth16(PS_INPUT input) : OUTPUT_SV { // Same as above but without the A/B channels (16 bits Z) - // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16); +#else + return rgba8_to_depth16(sample_c(input.t)); +#endif } +#endif -float ps_convert_rgb5a1_float16_biln(PS_INPUT input) : SV_Depth +#if defined(__ps_convert_rgb5a1_depth16__) +OUTPUT_TYPE ps_convert_rgb5a1_depth16(PS_INPUT input) : OUTPUT_SV { // Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16); +#else + return rgb5a1_to_depth16(sample_c(input.t)); +#endif } +#endif +#if defined(__ps_convert_rgb5a1_8i__) PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input) { PS_OUTPUT output; @@ -406,7 +493,7 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input) uint red = (denorm_c.r >> 3) & 0x1Fu; uint green = (denorm_c.g >> 3) & 0x1Fu; - output.c = (float4)(((float)(((green << 5) | red) & 0xFFu)) / 255.0f); + output.o = (float4)(((float)(((green << 5) | red) & 0xFFu)) / 255.0f); } else { @@ -414,11 +501,13 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input) uint blue = (denorm_c.b >> 3) & 0x1Fu; uint alpha = denorm_c.a & 0x80u; - output.c = (float4)(((float)((alpha | (blue << 2) | (green >> 3)) & 0xFFu)) / 255.0f); + output.o = (float4)(((float)((alpha | (blue << 2) | (green >> 3)) & 0xFFu)) / 255.0f); } return output; } +#endif +#if defined(__ps_convert_rgba_8i__) PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input) { PS_OUTPUT output; @@ -462,10 +551,12 @@ PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input) float4 pixel = Texture.Load(int3(int2(coord), 0)); float2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga; float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y; - output.c = (float4)(sel1); // Divide by something here? + output.o = (float4)(sel1); // Divide by something here? return output; } +#endif +#if defined(__ps_convert_clut_4__) PS_OUTPUT ps_convert_clut_4(PS_INPUT input) { // Borrowing the YUV constant buffer. @@ -478,10 +569,12 @@ PS_OUTPUT ps_convert_clut_4(PS_INPUT input) int2 final = int2(floor(float2(offset + pos) * scale)); PS_OUTPUT output; - output.c = Texture.Load(int3(final, 0), 0); + output.o = Texture.Load(int3(final, 0), 0); return output; } +#endif +#if defined(__ps_convert_clut_8__) PS_OUTPUT ps_convert_clut_8(PS_INPUT input) { float scale = BGColor.x; @@ -497,10 +590,12 @@ PS_OUTPUT ps_convert_clut_8(PS_INPUT input) int2 final = int2(floor(float2(offset + pos) * scale)); PS_OUTPUT output; - output.c = Texture.Load(int3(final, 0), 0); + output.o = Texture.Load(int3(final, 0), 0); return output; } +#endif +#if defined(__ps_yuv__) PS_OUTPUT ps_yuv(PS_INPUT input) { PS_OUTPUT output; @@ -515,41 +610,43 @@ PS_OUTPUT ps_yuv(PS_INPUT input) switch (EMODA) { case 0: - output.c.a = i.a; + output.o.a = i.a; break; case 1: - output.c.a = Y; + output.o.a = Y; break; case 2: - output.c.a = Y / 2.0f; + output.o.a = Y / 2.0f; break; case 3: default: - output.c.a = 0.0f; + output.o.a = 0.0f; break; } switch (EMODC) { case 0: - output.c.rgb = i.rgb; + output.o.rgb = i.rgb; break; case 1: - output.c.rgb = float3(Y, Y, Y); + output.o.rgb = float3(Y, Y, Y); break; case 2: - output.c.rgb = float3(Y, Cb, Cr); + output.o.rgb = float3(Y, Cb, Cr); break; case 3: default: - output.c.rgb = float3(i.a, i.a, i.a); + output.o.rgb = float3(i.a, i.a, i.a); break; } return output; } +#endif -float ps_stencil_image_init_0(PS_INPUT input) : SV_Target +#if defined(__ps_primid_image_init_0__) +float ps_primid_image_init_0(PS_INPUT input) : SV_Target { float c; if ((127.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass) @@ -558,8 +655,10 @@ float ps_stencil_image_init_0(PS_INPUT input) : SV_Target c = float(0x7FFFFFFF); return c; } +#endif -float ps_stencil_image_init_1(PS_INPUT input) : SV_Target +#if defined(__ps_primid_image_init_1__) +float ps_primid_image_init_1(PS_INPUT input) : SV_Target { float c; if (sample_c(input.t).a < (127.5f / 255.0f)) // >= 0x80 pass @@ -568,9 +667,10 @@ float ps_stencil_image_init_1(PS_INPUT input) : SV_Target c = float(0x7FFFFFFF); return c; } +#endif -float ps_stencil_image_init_2(PS_INPUT input) - : SV_Target +#if defined(__ps_primid_image_init_2__) +float ps_primid_image_init_2(PS_INPUT input) : SV_Target { float c; if ((254.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass) @@ -579,9 +679,10 @@ float ps_stencil_image_init_2(PS_INPUT input) c = float(0x7FFFFFFF); return c; } +#endif -float ps_stencil_image_init_3(PS_INPUT input) - : SV_Target +#if defined(__ps_primid_image_init_3__) +float ps_primid_image_init_3(PS_INPUT input) : SV_Target { float c; if (sample_c(input.t).a < (254.5f / 255.0f)) // >= 0x80 pass @@ -590,3 +691,6 @@ float ps_stencil_image_init_3(PS_INPUT input) c = float(0x7FFFFFFF); return c; } +#endif + +#endif // PIXEL_SHADER \ No newline at end of file diff --git a/bin/resources/shaders/dx11/tfx.fx b/bin/resources/shaders/dx11/tfx.fx index f063ff5625..667aa8acd3 100644 --- a/bin/resources/shaders/dx11/tfx.fx +++ b/bin/resources/shaders/dx11/tfx.fx @@ -707,7 +707,7 @@ float4 sample_depth(float2 st, float2 pos) } else if (PS_DEPTH_FMT == 1) { - // Based on ps_convert_float32_rgba8 of convert + // Based on ps_convert_depth32_rgba8 of convert // Convert a FLOAT32 depth texture into a RGBA color texture uint d = uint(fetch_c(uv).r * exp2(32.0f)); @@ -715,7 +715,7 @@ float4 sample_depth(float2 st, float2 pos) } else if (PS_DEPTH_FMT == 2) { - // Based on ps_convert_float16_rgb5a1 of convert + // Based on ps_convert_depth16_rgb5a1 of convert // Convert a FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture uint d = uint(fetch_c(uv).r * exp2(32.0f)); diff --git a/bin/resources/shaders/opengl/convert.glsl b/bin/resources/shaders/opengl/convert.glsl index 0c9d4b0333..d93d76cb8a 100644 --- a/bin/resources/shaders/opengl/convert.glsl +++ b/bin/resources/shaders/opengl/convert.glsl @@ -3,21 +3,12 @@ //#version 420 // Keep it for editor detection - #ifdef VERTEX_SHADER layout(location = 0) in vec2 POSITION; layout(location = 1) in vec2 TEXCOORD0; layout(location = 7) in vec4 COLOR; -// FIXME set the interpolation (don't know what dx do) -// flat means that there is no interpolation. The value given to the fragment shader is based on the provoking vertex conventions. -// -// noperspective means that there will be linear interpolation in window-space. This is usually not what you want, but it can have its uses. -// -// smooth, the default, means to do perspective-correct interpolation. -// -// The centroid qualifier only matters when multisampling. If this qualifier is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie outside of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The centroid qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area. out vec4 PSin_p; out vec2 PSin_t; out vec4 PSin_c; @@ -40,44 +31,125 @@ in vec4 PSin_c; layout(binding = 0) uniform sampler2D TextureSampler; -// Give a different name so I remember there is a special case! -#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits) -layout(location = 0) out uint SV_Target1; -#elif defined(ps_convert_float32_depth_to_color) -layout(location = 0) out float SV_Target0; -#elif !defined(ps_datm1) && \ - !defined(ps_datm0) && \ - !defined(ps_datm1_rta_correction) && \ - !defined(ps_datm0_rta_correction) && \ - !defined(ps_convert_rgba8_float32) && \ - !defined(ps_convert_rgba8_float24) && \ - !defined(ps_convert_rgba8_float16) && \ - !defined(ps_convert_rgb5a1_float16) && \ - !defined(ps_convert_rgba8_float32_biln) && \ - !defined(ps_convert_rgba8_float24_biln) && \ - !defined(ps_convert_rgba8_float16_biln) && \ - !defined(ps_convert_rgb5a1_float16_biln) && \ - !defined(ps_convert_float32_float24) && \ - !defined(ps_depth_copy) -layout(location = 0) out vec4 SV_Target0; +#if HAS_INTEGER_OUTPUT + layout(location = 0) out uint o_col0; + #define OUTPUT o_col0 +#elif HAS_DEPTH_OUTPUT + out float gl_FragDepth; + #define OUTPUT gl_FragDepth +#elif HAS_FLOAT32_OUTPUT + layout(location = 0) out float o_col0; + #define OUTPUT o_col0 +#elif HAS_STENCIL_OUTPUT +#else + layout(location = 0) out vec4 o_col0; + #define OUTPUT o_col0 #endif +#if HAS_FLOAT32_INPUT + +float sample_c() +{ + return texture(TextureSampler, PSin_t).r; +} + +#else + vec4 sample_c() { return texture(TextureSampler, PSin_t); } +#endif + +uint rgba8_to_uint(vec4 c) +{ + uvec4 i = uvec4(c * 255.5f) & 0xFFu; + return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24); +} + +uint rgb5a1_to_uint(vec4 c) +{ + uvec4 i = uvec4(c * 255.5f) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u); + return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8); +} + +uint depth_to_uint(float d) +{ + return uint(d * exp2(32.0f)); +} + +vec4 uint_to_rgba8(uint i) +{ + return vec4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f; +} + +vec4 uint_to_rgb5a1(uint i) +{ + return vec4(uvec4(i << 3, i >> 2, i >> 7, i >> 8) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f; +} + +float uint_to_depth32(uint i) +{ + return float(i) * exp2(-32.0f); +} + +float uint_to_depth24(uint i) +{ + return float(i & 0xFFFFFFu) * exp2(-32.0f); +} + +float uint_to_depth16(uint i) +{ + return float(i & 0xFFFFu) * exp2(-32.0f); +} + +float rgba8_to_depth32(vec4 val) +{ + return uint_to_depth32(rgba8_to_uint(val)); +} + +float rgba8_to_depth24(vec4 val) +{ + return uint_to_depth24(rgba8_to_uint(val)); +} + +float rgba8_to_depth16(vec4 val) +{ + return uint_to_depth16(rgba8_to_uint(val)); +} + +float rgb5a1_to_depth16(vec4 val) +{ + return uint_to_depth16(rgb5a1_to_uint(val)); +} + +vec4 depth32_to_rgba8(float d) +{ + return uint_to_rgba8(depth_to_uint(d)); +} + +vec4 depth16_to_rgb5a1(float d) +{ + return uint_to_rgb5a1(depth_to_uint(d)); +} + +float depth32_to_depth24(float d) +{ + return uint_to_depth24(depth_to_uint(d)); +} + #ifdef ps_copy void ps_copy() { - SV_Target0 = sample_c(); + OUTPUT = sample_c(); } #endif #ifdef ps_depth_copy void ps_depth_copy() { - gl_FragDepth = sample_c().r; + OUTPUT = sample_c(); } #endif @@ -96,126 +168,47 @@ void ps_downsample_copy() for (int xoff = 0; xoff < DownsampleFactor; xoff++) result += texelFetch(TextureSampler, coord + ivec2(xoff * StepMultiplier, yoff * StepMultiplier), 0); } - SV_Target0 = result / Weight; + o_col0 = result / Weight; } #endif -#ifdef ps_convert_rgba8_16bits -// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life -void ps_convert_rgba8_16bits() +#ifdef ps_convert_rgb5a1_16bits +void ps_convert_rgb5a1_16bits() { - highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f)); - - SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8); + // Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life + OUTPUT = rgb5a1_to_uint(sample_c()); } #endif -#ifdef ps_convert_float32_32bits -void ps_convert_float32_32bits() +#ifdef ps_convert_depth32_32bits +void ps_convert_depth32_32bits() { // Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture - SV_Target1 = uint(exp2(32.0f) * sample_c().r); + OUTPUT = depth_to_uint(sample_c()); } #endif -#ifdef ps_convert_float32_rgba8 -void ps_convert_float32_rgba8() +#ifdef ps_convert_depth32_rgba8 +void ps_convert_depth32_rgba8() { // Convert a GL_FLOAT32 depth texture into a RGBA color texture - uint d = uint(sample_c().r * exp2(32.0f)); - SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0); + OUTPUT = depth32_to_rgba8(sample_c()); } #endif -#ifdef ps_convert_float16_rgb5a1 -void ps_convert_float16_rgb5a1() +#ifdef ps_convert_depth16_rgb5a1 +void ps_convert_depth16_rgb5a1() { // Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture - uint d = uint(sample_c().r * exp2(32.0f)); - SV_Target0 = vec4(uvec4(d << 3, d >> 2, d >> 7, d >> 8) & uvec4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f; + OUTPUT = depth16_to_rgb5a1(sample_c()); } #endif -float rgba8_to_depth32(vec4 unorm) -{ - uvec4 c = uvec4(unorm * vec4(255.5f)); - return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f); -} - -float rgba8_to_depth24(vec4 unorm) -{ - uvec3 c = uvec3(unorm.rgb * vec3(255.5f)); - return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f); -} - -float rgba8_to_depth16(vec4 unorm) -{ - uvec2 c = uvec2(unorm.rg * vec2(255.5f)); - return float(c.r | (c.g << 8)) * exp2(-32.0f); -} - -float rgb5a1_to_depth16(vec4 unorm) -{ - uvec4 c = uvec4(unorm * vec4(255.5f)); - return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f); -} - -#ifdef ps_convert_float32_depth_to_color -void ps_convert_float32_depth_to_color() -{ - SV_Target0 = sample_c().r; -} -#endif - -#ifdef ps_convert_float32_color_to_depth -void ps_convert_float32_color_to_depth() -{ - gl_FragDepth = sample_c().r; -} -#endif - -#ifdef ps_convert_float32_float24 -void ps_convert_float32_float24() +#ifdef ps_convert_depth32_depth24 +void ps_convert_depth32_depth24() { // Truncates depth value to 24bits - uint d = uint(sample_c().r * exp2(32.0f)) & 0xFFFFFFu; - gl_FragDepth = float(d) * exp2(-32.0f); -} -#endif - -#ifdef ps_convert_rgba8_float32 -void ps_convert_rgba8_float32() -{ - // Convert an RGBA texture into a float depth texture - gl_FragDepth = rgba8_to_depth32(sample_c()); -} -#endif - -#ifdef ps_convert_rgba8_float24 -void ps_convert_rgba8_float24() -{ - // Same as above but without the alpha channel (24 bits Z) - - // Convert an RGBA texture into a float depth texture - gl_FragDepth = rgba8_to_depth24(sample_c()); -} -#endif - -#ifdef ps_convert_rgba8_float16 -void ps_convert_rgba8_float16() -{ - // Same as above but without the A/B channels (16 bits Z) - - // Convert an RGBA texture into a float depth texture - gl_FragDepth = rgba8_to_depth16(sample_c()); -} -#endif - -#ifdef ps_convert_rgb5a1_float16 -void ps_convert_rgb5a1_float16() -{ - // Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z - gl_FragDepth = rgb5a1_to_depth16(sample_c()); + OUTPUT = depth32_to_depth24(sample_c()); } #endif @@ -229,41 +222,55 @@ void ps_convert_rgb5a1_float16() float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \ float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \ float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \ - gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y); + OUTPUT = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y); -#ifdef ps_convert_rgba8_float32_biln -void ps_convert_rgba8_float32_biln() +#ifdef ps_convert_rgba8_depth32 +void ps_convert_rgba8_depth32() { // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32); +#else + OUTPUT = rgba8_to_depth32(sample_c()); +#endif } #endif -#ifdef ps_convert_rgba8_float24_biln -void ps_convert_rgba8_float24_biln() +#ifdef ps_convert_rgba8_depth24 +void ps_convert_rgba8_depth24() { // Same as above but without the alpha channel (24 bits Z) - // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24); +#else + OUTPUT = rgba8_to_depth24(sample_c()); +#endif } #endif -#ifdef ps_convert_rgba8_float16_biln -void ps_convert_rgba8_float16_biln() +#ifdef ps_convert_rgba8_depth16 +void ps_convert_rgba8_depth16() { // Same as above but without the A/B channels (16 bits Z) - // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16); +#else + OUTPUT = rgba8_to_depth16(sample_c()); +#endif } #endif -#ifdef ps_convert_rgb5a1_float16_biln -void ps_convert_rgb5a1_float16_biln() +#ifdef ps_convert_rgb5a1_depth16 +void ps_convert_rgb5a1_depth16() { // Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16); +#else + OUTPUT = rgb5a1_to_depth16(sample_c()); +#endif } #endif @@ -373,7 +380,7 @@ void ps_convert_rgb5a1_8i() uint red = (denorm_c.r >> 3) & 0x1Fu; uint green = (denorm_c.g >> 3) & 0x1Fu; - SV_Target0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f); + o_col0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f); } else { @@ -381,7 +388,7 @@ void ps_convert_rgb5a1_8i() uint blue = (denorm_c.b >> 3) & 0x1Fu; uint alpha = denorm_c.a & 0x80u; - SV_Target0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f); + o_col0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f); } } #endif @@ -430,7 +437,7 @@ void ps_convert_rgba_8i() vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0); vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga; float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y; - SV_Target0 = vec4(sel1); + o_col0 = vec4(sel1); } #endif @@ -438,7 +445,7 @@ void ps_convert_rgba_8i() void ps_filter_transparency() { vec4 c = sample_c(); - SV_Target0 = vec4(c.rgb, 1.0); + o_col0 = vec4(c.rgb, 1.0); } #endif @@ -486,7 +493,7 @@ void ps_datm0_rta_correction() void ps_rta_correction() { vec4 value = sample_c(); - SV_Target0 = vec4(value.rgb, value.a / (128.25f / 255.0f)); + o_col0 = vec4(value.rgb, value.a / (128.25f / 255.0f)); } #endif @@ -494,7 +501,7 @@ void ps_rta_correction() void ps_rta_decorrection() { vec4 value = sample_c(); - SV_Target0 = vec4(value.rgb, value.a * (128.25f / 255.0f)); + o_col0 = vec4(value.rgb, value.a * (128.25f / 255.0f)); } #endif @@ -502,7 +509,7 @@ void ps_rta_decorrection() void ps_colclip_init() { vec4 value = sample_c(); - SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a); + o_col0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a); } #endif @@ -510,7 +517,7 @@ void ps_colclip_init() void ps_colclip_resolve() { vec4 value = sample_c(); - SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a); + o_col0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a); } #endif @@ -525,7 +532,7 @@ void ps_convert_clut_4() uvec2 pos = uvec2(index % 8u, index / 8u); ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale))); - SV_Target0 = texelFetch(TextureSampler, final, 0); + o_col0 = texelFetch(TextureSampler, final, 0); } #endif @@ -545,7 +552,7 @@ void ps_convert_clut_8() pos.y = ((index / 32u) * 2u) + (subgroup % 2u); ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale))); - SV_Target0 = texelFetch(TextureSampler, final, 0); + o_col0 = texelFetch(TextureSampler, final, 0); } #endif @@ -600,31 +607,31 @@ void ps_yuv() break; } - SV_Target0 = o; + o_col0 = o; } #endif -#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3) +#if defined(ps_primid_image_init_0) || defined(ps_primid_image_init_1) || defined(ps_primid_image_init_2) || defined(ps_primid_image_init_3) void main() { - SV_Target0 = vec4(0x7FFFFFFF); + o_col0 = vec4(0x7FFFFFFF); - #ifdef ps_stencil_image_init_0 + #ifdef ps_primid_image_init_0 if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass) - SV_Target0 = vec4(-1); + o_col0 = vec4(-1); #endif - #ifdef ps_stencil_image_init_1 + #ifdef ps_primid_image_init_1 if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass - SV_Target0 = vec4(-1); + o_col0 = vec4(-1); #endif - #ifdef ps_stencil_image_init_2 + #ifdef ps_primid_image_init_2 if((254.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass) - SV_Target0 = vec4(-1); + o_col0 = vec4(-1); #endif - #ifdef ps_stencil_image_init_3 + #ifdef ps_primid_image_init_3 if(sample_c().a < (254.5f / 255.0f)) // >= 0x80 pass - SV_Target0 = vec4(-1); + o_col0 = vec4(-1); #endif } #endif diff --git a/bin/resources/shaders/opengl/tfx_fs.glsl b/bin/resources/shaders/opengl/tfx_fs.glsl index 6c565f863c..5be4258cf5 100644 --- a/bin/resources/shaders/opengl/tfx_fs.glsl +++ b/bin/resources/shaders/opengl/tfx_fs.glsl @@ -621,13 +621,13 @@ vec4 sample_depth(vec2 st) #elif PS_DEPTH_FMT == 1 - // Based on ps_convert_float32_rgba8 of convert + // Based on ps_convert_depth32_rgba8 of convert // Convert a GL_FLOAT32 depth texture into a RGBA color texture uint d = uint(fetch_c(uv).r * exp2(32.0f)); t = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))); #elif PS_DEPTH_FMT == 2 - // Based on ps_convert_float16_rgb5a1 of convert + // Based on ps_convert_depth16_rgb5a1 of convert // Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture uint d = uint(fetch_c(uv).r * exp2(32.0f)); t = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) * vec4(8.0f, 8.0f, 8.0f, 128.0f); diff --git a/bin/resources/shaders/vulkan/convert.glsl b/bin/resources/shaders/vulkan/convert.glsl index 4b6451781d..23f6b3c89b 100644 --- a/bin/resources/shaders/vulkan/convert.glsl +++ b/bin/resources/shaders/vulkan/convert.glsl @@ -20,45 +20,127 @@ void main() layout(location = 0) in vec2 v_tex; -#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits) -layout(location = 0) out uint o_col0; -#elif defined(ps_convert_float32_depth_to_color) -layout(location = 0) out float o_col0; -#elif !defined(ps_datm1) && \ - !defined(ps_datm0) && \ - !defined(ps_datm1_rta_correction) && \ - !defined(ps_datm0_rta_correction) && \ - !defined(ps_convert_rgba8_float32) && \ - !defined(ps_convert_rgba8_float24) && \ - !defined(ps_convert_rgba8_float16) && \ - !defined(ps_convert_rgb5a1_float16) && \ - !defined(ps_convert_rgba8_float32_biln) && \ - !defined(ps_convert_rgba8_float24_biln) && \ - !defined(ps_convert_rgba8_float16_biln) && \ - !defined(ps_convert_rgb5a1_float16_biln) && \ - !defined(ps_convert_float32_float24) && \ - !defined(ps_depth_copy) -layout(location = 0) out vec4 o_col0; +#if HAS_INTEGER_OUTPUT + layout(location = 0) out uint o_col0; + #define OUTPUT o_col0 +#elif HAS_DEPTH_OUTPUT + out float gl_FragDepth; + #define OUTPUT gl_FragDepth +#elif HAS_FLOAT32_OUTPUT + layout(location = 0) out float o_col0; + #define OUTPUT o_col0 +#elif HAS_STENCIL_OUTPUT +#else + layout(location = 0) out vec4 o_col0; + #define OUTPUT o_col0 #endif layout(set = 0, binding = 0) uniform sampler2D samp0; +#if HAS_FLOAT32_INPUT + +float sample_c(vec2 uv) +{ + return texture(samp0, uv).r; +} + +#else + vec4 sample_c(vec2 uv) { return texture(samp0, uv); } +#endif + +uint rgba8_to_uint(vec4 c) +{ + uvec4 i = uvec4(c * 255.5f) & 0xFFu; + return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24); +} + +uint rgb5a1_to_uint(vec4 c) +{ + uvec4 i = uvec4(c * 255.5f) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u); + return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8); +} + +uint depth_to_uint(float d) +{ + return uint(d * exp2(32.0f)); +} + +vec4 uint_to_rgba8(uint i) +{ + return vec4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f; +} + +vec4 uint_to_rgb5a1(uint i) +{ + return vec4(uvec4(i << 3, i >> 2, i >> 7, i >> 8) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f; +} + +float uint_to_depth32(uint i) +{ + return float(i) * exp2(-32.0f); +} + +float uint_to_depth24(uint i) +{ + return float(i & 0xFFFFFFu) * exp2(-32.0f); +} + +float uint_to_depth16(uint i) +{ + return float(i & 0xFFFFu) * exp2(-32.0f); +} + +float rgba8_to_depth32(vec4 val) +{ + return uint_to_depth32(rgba8_to_uint(val)); +} + +float rgba8_to_depth24(vec4 val) +{ + return uint_to_depth24(rgba8_to_uint(val)); +} + +float rgba8_to_depth16(vec4 val) +{ + return uint_to_depth16(rgba8_to_uint(val)); +} + +float rgb5a1_to_depth16(vec4 val) +{ + return uint_to_depth16(rgb5a1_to_uint(val)); +} + +vec4 depth32_to_rgba8(float d) +{ + return uint_to_rgba8(depth_to_uint(d)); +} + +vec4 depth16_to_rgb5a1(float d) +{ + return uint_to_rgb5a1(depth_to_uint(d)); +} + +float depth32_to_depth24(float d) +{ + return uint_to_depth24(depth_to_uint(d)); +} + #ifdef ps_copy void ps_copy() { - o_col0 = sample_c(v_tex); + OUTPUT = sample_c(v_tex); } #endif #ifdef ps_depth_copy void ps_depth_copy() { - gl_FragDepth = sample_c(v_tex).r; + OUTPUT = sample_c(v_tex); } #endif @@ -83,7 +165,7 @@ void ps_downsample_copy() result += texelFetch(samp0, coord + ivec2(xoff * step_multiplier, yoff * step_multiplier), 0); } } - o_col0 = result / Weight; + OUTPUT = result / Weight; } #endif @@ -91,17 +173,15 @@ void ps_downsample_copy() void ps_filter_transparency() { vec4 c = sample_c(v_tex); - o_col0 = vec4(c.rgb, 1.0); + OUTPUT = vec4(c.rgb, 1.0); } #endif -#ifdef ps_convert_rgba8_16bits -// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life -void ps_convert_rgba8_16bits() +#ifdef ps_convert_rgb5a1_16bits +void ps_convert_rgb5a1_16bits() { - uvec4 i = uvec4(sample_c(v_tex) * vec4(255.5f, 255.5f, 255.5f, 255.5f)); - - o_col0 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8); + // Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life + OUTPUT = rgb5a1_to_uint(sample_c(v_tex)); } #endif @@ -141,7 +221,7 @@ void ps_datm0_rta_correction() void ps_rta_correction() { vec4 value = sample_c(v_tex); - o_col0 = vec4(value.rgb, value.a / (128.25f / 255.0f)); + OUTPUT = vec4(value.rgb, value.a / (128.25f / 255.0f)); } #endif @@ -149,7 +229,7 @@ void ps_rta_correction() void ps_rta_decorrection() { vec4 value = sample_c(v_tex); - o_col0 = vec4(value.rgb, value.a * (128.25f / 255.0f)); + OUTPUT = vec4(value.rgb, value.a * (128.25f / 255.0f)); } #endif @@ -157,7 +237,7 @@ void ps_rta_decorrection() void ps_colclip_init() { vec4 value = sample_c(v_tex); - o_col0 = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a); + OUTPUT = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a); } #endif @@ -165,116 +245,39 @@ void ps_colclip_init() void ps_colclip_resolve() { vec4 value = sample_c(v_tex); - o_col0 = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a); + OUTPUT = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a); } #endif -#ifdef ps_convert_float32_depth_to_color -void ps_convert_float32_depth_to_color() -{ - o_col0 = sample_c(v_tex).r; -} -#endif - -#ifdef ps_convert_float32_color_to_depth -void ps_convert_float32_color_to_depth() -{ - gl_FragDepth = sample_c(v_tex).r; -} -#endif - -#ifdef ps_convert_float32_32bits -void ps_convert_float32_32bits() +#ifdef ps_convert_depth32_32bits +void ps_convert_depth32_32bits() { // Convert a vec32 depth texture into a 32 bits UINT texture - o_col0 = uint(exp2(32.0f) * sample_c(v_tex).r); + OUTPUT = depth_to_uint(sample_c(v_tex)); } #endif -#ifdef ps_convert_float32_rgba8 -void ps_convert_float32_rgba8() +#ifdef ps_convert_depth32_rgba8 +void ps_convert_depth32_rgba8() { // Convert a vec32 depth texture into a RGBA color texture - uint d = uint(sample_c(v_tex).r * exp2(32.0f)); - o_col0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0); + OUTPUT = depth32_to_rgba8(sample_c(v_tex)); } #endif -#ifdef ps_convert_float16_rgb5a1 -void ps_convert_float16_rgb5a1() +#ifdef ps_convert_depth16_rgb5a1 +void ps_convert_depth16_rgb5a1() { // Convert a vec32 (only 16 lsb) depth into a RGB5A1 color texture - uint d = uint(sample_c(v_tex).r * exp2(32.0f)); - o_col0 = vec4(uvec4(d << 3, d >> 2, d >> 7, d >> 8) & uvec4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f; + OUTPUT = depth16_to_rgb5a1(sample_c(v_tex)); } #endif -float rgba8_to_depth32(vec4 unorm) -{ - uvec4 c = uvec4(unorm * vec4(255.5f)); - return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f); -} - -float rgba8_to_depth24(vec4 unorm) -{ - uvec3 c = uvec3(unorm.rgb * vec3(255.5f)); - return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f); -} - -float rgba8_to_depth16(vec4 unorm) -{ - uvec2 c = uvec2(unorm.rg * vec2(255.5f)); - return float(c.r | (c.g << 8)) * exp2(-32.0f); -} - -float rgb5a1_to_depth16(vec4 unorm) -{ - uvec4 c = uvec4(unorm * vec4(255.5f)); - return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f); -} - -#ifdef ps_convert_float32_float24 -void ps_convert_float32_float24() +#ifdef ps_convert_depth32_depth24 +void ps_convert_depth32_depth24() { // Truncates depth value to 24bits - uint d = uint(sample_c(v_tex).r * exp2(32.0f)) & 0xFFFFFFu; - gl_FragDepth = float(d) * exp2(-32.0f); -} -#endif - -#ifdef ps_convert_rgba8_float32 -void ps_convert_rgba8_float32() -{ - // Convert an RGBA texture into a float depth texture - gl_FragDepth = rgba8_to_depth32(sample_c(v_tex)); -} -#endif - -#ifdef ps_convert_rgba8_float24 -void ps_convert_rgba8_float24() -{ - // Same as above but without the alpha channel (24 bits Z) - - // Convert an RGBA texture into a float depth texture - gl_FragDepth = rgba8_to_depth24(sample_c(v_tex)); -} -#endif - -#ifdef ps_convert_rgba8_float16 -void ps_convert_rgba8_float16() -{ - // Same as above but without the A/B channels (16 bits Z) - - // Convert an RGBA texture into a float depth texture - gl_FragDepth = rgba8_to_depth16(sample_c(v_tex)); -} -#endif - -#ifdef ps_convert_rgb5a1_float16 -void ps_convert_rgb5a1_float16() -{ - // Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z - gl_FragDepth = rgb5a1_to_depth16(sample_c(v_tex)); + OUTPUT = depth32_to_depth24(sample_c(v_tex)); } #endif @@ -288,41 +291,53 @@ void ps_convert_rgb5a1_float16() float depthTR = CONVERT_FN(texelFetch(samp0, coords.zy, 0)); \ float depthBL = CONVERT_FN(texelFetch(samp0, coords.xw, 0)); \ float depthBR = CONVERT_FN(texelFetch(samp0, coords.zw, 0)); \ - gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y); + OUTPUT = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y); -#ifdef ps_convert_rgba8_float32_biln -void ps_convert_rgba8_float32_biln() +#ifdef ps_convert_rgba8_depth32 +void ps_convert_rgba8_depth32() { // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32); +#else + OUTPUT = rgba8_to_depth32(sample_c(v_tex)); +#endif } #endif -#ifdef ps_convert_rgba8_float24_biln -void ps_convert_rgba8_float24_biln() +#ifdef ps_convert_rgba8_depth24 +void ps_convert_rgba8_depth24() { // Same as above but without the alpha channel (24 bits Z) - - // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24); +#else + OUTPUT = rgba8_to_depth24(sample_c(v_tex)); +#endif } #endif -#ifdef ps_convert_rgba8_float16_biln -void ps_convert_rgba8_float16_biln() +#ifdef ps_convert_rgba8_depth16 +void ps_convert_rgba8_depth16() { // Same as above but without the A/B channels (16 bits Z) - - // Convert an RGBA texture into a float depth texture +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16); +#else + OUTPUT = rgba8_to_depth16(sample_c(v_tex)); +#endif } #endif -#ifdef ps_convert_rgb5a1_float16_biln -void ps_convert_rgb5a1_float16_biln() +#ifdef ps_convert_rgb5a1_depth16 +void ps_convert_rgb5a1_depth16() { // Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z +#if HAS_BILN SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16); +#else + OUTPUT = rgb5a1_to_depth16(sample_c(v_tex)); +#endif } #endif @@ -609,25 +624,25 @@ void ps_yuv() } #endif -#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3) +#if defined(ps_primid_image_init_0) || defined(ps_primid_image_init_1) || defined(ps_primid_image_init_2) || defined(ps_primid_image_init_3) void main() { o_col0 = vec4(0x7FFFFFFF); - #ifdef ps_stencil_image_init_0 + #ifdef ps_primid_image_init_0 if((127.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass) o_col0 = vec4(-1); #endif - #ifdef ps_stencil_image_init_1 + #ifdef ps_primid_image_init_1 if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass o_col0 = vec4(-1); #endif - #ifdef ps_stencil_image_init_2 + #ifdef ps_primid_image_init_2 if((254.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass) o_col0 = vec4(-1); #endif - #ifdef ps_stencil_image_init_3 + #ifdef ps_primid_image_init_3 if(sample_c(v_tex).a < (254.5f / 255.0f)) // >= 0x80 pass o_col0 = vec4(-1); #endif diff --git a/bin/resources/shaders/vulkan/tfx.glsl b/bin/resources/shaders/vulkan/tfx.glsl index 37fefc1656..706ee1face 100644 --- a/bin/resources/shaders/vulkan/tfx.glsl +++ b/bin/resources/shaders/vulkan/tfx.glsl @@ -1114,7 +1114,7 @@ vec4 sample_depth(vec2 st, ivec2 pos) } #elif (PS_DEPTH_FMT == 1) { - // Based on ps_convert_float32_rgba8 of convert + // Based on ps_convert_depth32_rgba8 of convert // Convert a vec32 depth texture into a RGBA color texture uint d = uint(fetch_c(uv).r * exp2(32.0f)); @@ -1122,7 +1122,7 @@ vec4 sample_depth(vec2 st, ivec2 pos) } #elif (PS_DEPTH_FMT == 2) { - // Based on ps_convert_float16_rgb5a1 of convert + // Based on ps_convert_depth16_rgb5a1 of convert // Convert a vec32 (only 16 lsb) depth into a RGB5A1 color texture uint d = uint(fetch_c(uv).r * exp2(32.0f)); diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index 1857b4b51e..035602d700 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -22,29 +22,13 @@ #include #include -int SetDATMShader(SetDATM datm) -{ - switch (datm) - { - case SetDATM::DATM1_RTA_CORRECTION: - return static_cast(ShaderConvert::DATM_1_RTA_CORRECTION); - case SetDATM::DATM0_RTA_CORRECTION: - return static_cast(ShaderConvert::DATM_0_RTA_CORRECTION); - case SetDATM::DATM1: - return static_cast(ShaderConvert::DATM_1); - case SetDATM::DATM0: - default: - return static_cast(ShaderConvert::DATM_0); - } -} - -const char* shaderName(ShaderConvert value) +const char* ShaderEntryPoint(ShaderConvert value) { switch (value) { - // clang-format off + // clang-format off case ShaderConvert::COPY: return "ps_copy"; - case ShaderConvert::RGBA8_TO_16_BITS: return "ps_convert_rgba8_16bits"; + case ShaderConvert::RGB5A1_TO_16_BITS: return "ps_convert_rgb5a1_16bits"; case ShaderConvert::DATM_1: return "ps_datm1"; case ShaderConvert::DATM_0: return "ps_datm0"; case ShaderConvert::DATM_1_RTA_CORRECTION: return "ps_datm1_rta_correction"; @@ -54,22 +38,16 @@ const char* shaderName(ShaderConvert value) case ShaderConvert::RTA_CORRECTION: return "ps_rta_correction"; case ShaderConvert::RTA_DECORRECTION: return "ps_rta_decorrection"; case ShaderConvert::TRANSPARENCY_FILTER: return "ps_filter_transparency"; - case ShaderConvert::FLOAT32_TO_16_BITS: return "ps_convert_float32_32bits"; - case ShaderConvert::FLOAT32_TO_32_BITS: return "ps_convert_float32_32bits"; - case ShaderConvert::FLOAT32_TO_RGBA8: return "ps_convert_float32_rgba8"; - case ShaderConvert::FLOAT32_TO_RGB8: return "ps_convert_float32_rgba8"; - case ShaderConvert::FLOAT16_TO_RGB5A1: return "ps_convert_float16_rgb5a1"; - case ShaderConvert::RGBA8_TO_FLOAT32: return "ps_convert_rgba8_float32"; - case ShaderConvert::RGBA8_TO_FLOAT24: return "ps_convert_rgba8_float24"; - case ShaderConvert::RGBA8_TO_FLOAT16: return "ps_convert_rgba8_float16"; - case ShaderConvert::RGB5A1_TO_FLOAT16: return "ps_convert_rgb5a1_float16"; - case ShaderConvert::RGBA8_TO_FLOAT32_BILN: return "ps_convert_rgba8_float32_biln"; - case ShaderConvert::RGBA8_TO_FLOAT24_BILN: return "ps_convert_rgba8_float24_biln"; - case ShaderConvert::RGBA8_TO_FLOAT16_BILN: return "ps_convert_rgba8_float16_biln"; - case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: return "ps_convert_rgb5a1_float16_biln"; - case ShaderConvert::FLOAT32_DEPTH_TO_COLOR: return "ps_convert_float32_depth_to_color"; - case ShaderConvert::FLOAT32_COLOR_TO_DEPTH: return "ps_convert_float32_color_to_depth"; - case ShaderConvert::FLOAT32_TO_FLOAT24: return "ps_convert_float32_float24"; + case ShaderConvert::DEPTH32_TO_16_BITS: return "ps_convert_depth32_32bits"; + case ShaderConvert::DEPTH32_TO_32_BITS: return "ps_convert_depth32_32bits"; + case ShaderConvert::DEPTH32_TO_RGBA8: return "ps_convert_depth32_rgba8"; + case ShaderConvert::DEPTH32_TO_RGB8: return "ps_convert_depth32_rgba8"; + case ShaderConvert::DEPTH16_TO_RGB5A1: return "ps_convert_depth16_rgb5a1"; + case ShaderConvert::RGBA8_TO_DEPTH32: return "ps_convert_rgba8_depth32"; + case ShaderConvert::RGBA8_TO_DEPTH24: return "ps_convert_rgba8_depth24"; + case ShaderConvert::RGBA8_TO_DEPTH16: return "ps_convert_rgba8_depth16"; + case ShaderConvert::RGB5A1_TO_DEPTH16: return "ps_convert_rgb5a1_depth16"; + case ShaderConvert::DEPTH32_TO_DEPTH24: return "ps_convert_depth32_depth24"; case ShaderConvert::DEPTH_COPY: return "ps_depth_copy"; case ShaderConvert::DOWNSAMPLE_COPY: return "ps_downsample_copy"; case ShaderConvert::RGBA_TO_8I: return "ps_convert_rgba_8i"; @@ -77,18 +55,18 @@ const char* shaderName(ShaderConvert value) case ShaderConvert::CLUT_4: return "ps_convert_clut_4"; case ShaderConvert::CLUT_8: return "ps_convert_clut_8"; case ShaderConvert::YUV: return "ps_yuv"; - // clang-format on + // clang-format on default: pxAssert(0); return "ShaderConvertUnknownShader"; } } -const char* shaderName(PresentShader value) +const char* ShaderEntryPoint(PresentShader value) { switch (value) { - // clang-format off + // clang-format off case PresentShader::COPY: return "ps_copy"; case PresentShader::SCANLINE: return "ps_filter_scanlines"; case PresentShader::DIAGONAL_FILTER: return "ps_filter_diagonal"; @@ -97,13 +75,53 @@ const char* shaderName(PresentShader value) 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 + // clang-format on default: pxAssert(0); return "DisplayShaderUnknownShader"; } } +const char* ShaderConvertName(ShaderConvert shader) +{ + #define ENTRY(x) case ShaderConvert::x: return #x + switch (shader) + { + ENTRY(COPY); + ENTRY(DEPTH_COPY); + ENTRY(RGB5A1_TO_16_BITS); + ENTRY(DATM_1); + ENTRY(DATM_0); + ENTRY(DATM_1_RTA_CORRECTION); + ENTRY(DATM_0_RTA_CORRECTION); + ENTRY(COLCLIP_INIT); + ENTRY(COLCLIP_RESOLVE); + ENTRY(RTA_CORRECTION); + ENTRY(RTA_DECORRECTION); + ENTRY(TRANSPARENCY_FILTER); + ENTRY(DEPTH32_TO_16_BITS); + ENTRY(DEPTH32_TO_32_BITS); + ENTRY(DEPTH32_TO_RGBA8); + ENTRY(DEPTH32_TO_RGB8); + ENTRY(DEPTH16_TO_RGB5A1); + ENTRY(RGBA8_TO_DEPTH32); + ENTRY(RGBA8_TO_DEPTH24); + ENTRY(RGBA8_TO_DEPTH16); + ENTRY(RGB5A1_TO_DEPTH16); + ENTRY(DEPTH32_TO_DEPTH24); + ENTRY(DOWNSAMPLE_COPY); + ENTRY(RGBA_TO_8I); + ENTRY(RGB5A1_TO_8I); + ENTRY(CLUT_4); + ENTRY(CLUT_8); + ENTRY(YUV); + case ShaderConvert::Count: break; + } + #undef ENTRY + pxAssert(false); + return nullptr; +} + #ifdef PCSX2_DEVBUILD enum class TextureLabel @@ -741,9 +759,21 @@ GSTexture* GSDevice::CreateRenderTarget(int w, int h, GSTexture::Format format, return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, format, clear, !prefer_reuse); } -GSTexture* GSDevice::CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse) +GSTexture* GSDevice::CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse) { - return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, format, clear, !prefer_reuse); + return FetchSurface(GSTexture::Type::RenderTarget, size.x, size.y, 1, format, clear, !prefer_reuse); +} + +GSTexture* GSDevice::CreateDepthStencil(int w, int h, bool clear, bool prefer_reuse) +{ + return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, GSTexture::Format::DepthStencil, + clear, !prefer_reuse); +} + +GSTexture* GSDevice::CreateDepthStencil(const GSVector2i& size, bool clear, bool prefer_reuse) +{ + return FetchSurface(GSTexture::Type::DepthStencil, size.x, size.y, 1, GSTexture::Format::DepthStencil, + clear, !prefer_reuse); } GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */) @@ -753,60 +783,163 @@ GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::F return FetchSurface(GSTexture::Type::Texture, w, h, levels, format, false, m_features.prefer_new_textures && !prefer_reuse); } -void GSDevice::DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) +GSTexture* GSDevice::CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */) { - pxAssert((dTex && dTex->IsDepthStencil()) == HasDepthOutput(shader)); - pxAssert(linear ? SupportsBilinear(shader) : SupportsNearest(shader)); - GL_INS("StretchRect(%d) {%d,%d} %dx%d -> {%d,%d) %dx%d", shader, int(sRect.left), int(sRect.top), + return CreateTexture(size.x, size.y, mipmap_levels, format, prefer_reuse); +} + +GSTexture* GSDevice::CreateCompatible(GSTexture* tex, bool clear, bool prefer_reuse) +{ + return CreateCompatible(tex, tex->GetWidth(), tex->GetHeight(), clear, prefer_reuse); +} + +GSTexture* GSDevice::CreateCompatible(GSTexture* tex, const GSVector2i& size, bool clear, bool prefer_reuse) +{ + return CreateCompatible(tex, size.x, size.y, clear, prefer_reuse); +} + +GSTexture* GSDevice::CreateCompatible(GSTexture* tex, int w, int h, bool clear, bool prefer_reuse) +{ + return FetchSurface(tex->GetType(), w, h, 1, tex->GetFormat(), clear, !prefer_reuse); +} + +void GSDevice::DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, + const GSVector4& dRect, ShaderConvertSelector shader, bool linear) +{ + pxAssert((dTex && dTex->IsDepthLike()) == shader.Float32Output()); + pxAssert(!(linear && shader.SupportsBilinear())); // Don't allow HW bilinear if SW bilinear is required. + GL_INS("StretchRect(%s) {%d,%d} %dx%d -> {%d,%d) %dx%d", ShaderConvertName(shader.Shader()), + int(sRect.left), int(sRect.top), int(sRect.right - sRect.left), int(sRect.bottom - sRect.top), int(dRect.left), int(dRect.top), int(dRect.right - dRect.left), int(dRect.bottom - dRect.top)); - DoStretchRect(sTex, sRect, dTex, dRect, cms, shader, linear); + DoStretchRect(sTex, sRect, dTex, dRect, shader, linear); } void GSDevice::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - bool red, bool green, bool blue, bool alpha, ShaderConvert shader) + ShaderConvertSelector shader, bool linear) { - GSHWDrawConfig::ColorMaskSelector cms; - - cms.wr = red; - cms.wg = green; - cms.wb = blue; - cms.wa = alpha; - - pxAssert(HasVariableWriteMask(shader)); - GL_INS("ColorCopy Red:%d Green:%d Blue:%d Alpha:%d", cms.wr, cms.wg, cms.wb, cms.wa); - - DoStretchRectWithAssertions(sTex, sRect, dTex, dRect, cms, shader, false); + DoStretchRectWithAssertions(sTex, sRect, dTex, dRect, shader, linear); } -void GSDevice::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - ShaderConvert shader, bool linear) -{ - DoStretchRectWithAssertions(sTex, sRect, dTex, dRect, GSHWDrawConfig::ColorMaskSelector(ShaderConvertWriteMask(shader)), shader, linear); -} - -void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear) +void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader, bool linear) { StretchRect(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader, linear); } +void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader, bool linear) +{ + StretchRect(sTex, dTex, GSVector4(dTex->GetRect()), shader, linear); +} + +void GSDevice::StretchRectAuto(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, + bool linear, u32 src_bpp, u32 dst_bpp) +{ + ShaderConvertSelector shader = GetConvertShader(sTex, dTex, src_bpp, dst_bpp); + if (shader.SupportsBilinear() && linear) + { + // Bilinear is emulated in the shader. + shader.SetBiln(true); + linear = false; + } + StretchRect(sTex, sRect, dTex, dRect, shader, linear); +} + +void GSDevice::StretchRectAuto(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, bool linear, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAuto(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, linear, src_bpp, dst_bpp); + } + +void GSDevice::StretchRectAuto(GSTexture* sTex, GSTexture* dTex, bool linear, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAuto(sTex, dTex, GSVector4(dTex->GetRect()), linear, src_bpp, dst_bpp); +} + +void GSDevice::StretchRectNearest(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, + ShaderConvertSelector shader) +{ + StretchRect(sTex, sRect, dTex, dRect, shader, false); +} + +void GSDevice::StretchRectNearest(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader) +{ + StretchRectNearest(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader); +} + +void GSDevice::StretchRectNearest(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader) +{ + StretchRectNearest(sTex, dTex, GSVector4(dTex->GetRect()), shader); +} + +void GSDevice::StretchRectAutoNearest(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAuto(sTex, sRect, dTex, dRect, false, src_bpp, dst_bpp); +} + +void GSDevice::StretchRectAutoNearest(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAutoNearest(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, src_bpp, dst_bpp); +} + +void GSDevice::StretchRectAutoNearest(GSTexture* sTex, GSTexture* dTex, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAutoNearest(sTex, dTex, GSVector4(dTex->GetRect()), src_bpp, dst_bpp); +} + +void GSDevice::StretchRectBiln(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, + ShaderConvertSelector shader) +{ + StretchRect(sTex, sRect, dTex, dRect, shader, true); +} + +void GSDevice::StretchRectBiln(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader) +{ + StretchRectBiln(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader); +} + +void GSDevice::StretchRectBiln(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader) +{ + StretchRectBiln(sTex, dTex, GSVector4(dTex->GetRect()), shader); +} + +void GSDevice::StretchRectAutoBiln(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAuto(sTex, sRect, dTex, dRect, true, src_bpp, dst_bpp); +} + +void GSDevice::StretchRectAutoBiln(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAutoBiln(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, src_bpp, dst_bpp); +} + +void GSDevice::StretchRectAutoBiln(GSTexture* sTex, GSTexture* dTex, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAutoBiln(sTex, dTex, GSVector4(dTex->GetRect()), src_bpp, dst_bpp); +} + +void GSDevice::StretchRectAutoMask(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, + bool red, bool green, bool blue, bool alpha, u32 src_bpp, u32 dst_bpp) +{ + StretchRect(sTex, sRect, dTex, dRect, GetConvertShaderMask(sTex, dTex, src_bpp, dst_bpp, red, green, blue, alpha), false); +} + +void GSDevice::StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, u32 src_bpp, u32 dst_bpp) +{ + StretchRectAutoMask(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, red, green, blue, alpha, src_bpp, dst_bpp); +} + +void GSDevice::StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, bool red, bool green, bool blue, bool alpha, + u32 src_bpp, u32 dst_bpp) +{ + StretchRectAutoMask(sTex, dTex, GSVector4(dTex->GetRect()), red, green, blue, alpha, src_bpp, dst_bpp); +} + void GSDevice::DrawMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) + const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) { for (u32 i = 0; i < num_rects; i++) { const MultiStretchRect& sr = rects[i]; - pxAssert(HasVariableWriteMask(shader) || rects[0].wmask.wrgba == 0xf); - if (rects[0].wmask.wrgba != 0xf) - { - g_gs_device->StretchRect(sr.src, sr.src_rect, dTex, sr.dst_rect, rects[0].wmask.wr, - rects[0].wmask.wg, rects[0].wmask.wb, rects[0].wmask.wa, shader); - } - else - { - g_gs_device->StretchRect(sr.src, sr.src_rect, dTex, sr.dst_rect, shader, sr.linear); - } + g_gs_device->StretchRect(sr.src, sr.src_rect, dTex, sr.dst_rect, shader.SetMask(rects[0].wmask.wrgba).SetBiln(sr.linear)); } } @@ -961,7 +1094,7 @@ void GSDevice::Resize(int width, int height) { const GSVector4 sRect(0, 0, 1, 1); const GSVector4 dRect(0, 0, s.x, s.y); - StretchRect(m_current, sRect, dTex, dRect, ShaderConvert::COPY, false); + StretchRectAutoNearest(m_current, sRect, dTex, dRect); m_current = dTex; } } @@ -992,7 +1125,7 @@ bool GSDevice::ResizeRenderTarget(GSTexture** t, int w, int h, bool preserve_con { constexpr GSVector4 sRect = GSVector4::cxpr(0, 0, 1, 1); const GSVector4 dRect = GSVector4(orig_tex->GetRect()); - StretchRect(orig_tex, sRect, new_tex, dRect, ShaderConvert::COPY, true); + StretchRectBiln(orig_tex, sRect, new_tex, dRect, ShaderConvert::COPY); } if (orig_tex) @@ -1012,10 +1145,10 @@ void GSDevice::BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea) // Create a temporary RT and copy the area needed for the draw. const int w = ds->GetWidth(); const int h = ds->GetHeight(); - m_ds_as_rt = g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Float32, false, true); + m_ds_as_rt = g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::DepthColor, false, true); const GSVector4 dRect(drawarea); const GSVector4 sRect(dRect.x / w, dRect.y / h, dRect.z / w, dRect.w / h); - StretchRect(ds, sRect, m_ds_as_rt, dRect, ShaderConvert::FLOAT32_DEPTH_TO_COLOR, false); + StretchRectAutoNearest(ds, sRect, m_ds_as_rt, dRect); } void GSDevice::EndDSAsRT() @@ -1691,6 +1824,79 @@ void GSHWDrawConfig::DumpConfig(const std::string& path, const GSHWDrawConfig& c } } +static constexpr u32 NUM_REMAP_INPUTS = static_cast(ShaderConvert::Count) * 8; + +static constexpr ShaderConvertSelector GetRemappedShader(u32 idx) +{ + ShaderConvert convert = static_cast(idx >> 3); + bool depth_in = (idx >> 0) & 1; + bool depth_out = (idx >> 1) & 1; + bool biln = (idx >> 2) & 1; + return ShaderConvertSelector(convert, 0xf, depth_in, depth_out, biln); +} + +static constexpr bool RemapIndexIsValid(u32 idx) +{ + ShaderConvert convert = static_cast(idx >> 3); + bool depth_in = (idx >> 0) & 1; + bool depth_out = (idx >> 1) & 1; + bool biln = (idx >> 2) & 1; + if (HasVariableWriteMask(convert) && !depth_in && !depth_out && !biln) + return false; // Handled as variable write mask + if (depth_in && !HasFloat32Input(convert)) + return false; + if (depth_out && !HasFloat32Output(convert)) + return false; + if (biln && !SupportsBilinear(convert)) + return false; + return true; +} + +static constexpr u32 CalcNumRemappedShaders() +{ + u32 num = 0; + for (u32 i = 0; i < NUM_REMAP_INPUTS; i++) + num += RemapIndexIsValid(i); + return num; +} + +static constexpr u32 NUM_REMAPPED_SHADERS = CalcNumRemappedShaders(); +static constexpr u32 NUM_TOTAL_SHADERS = NUM_REMAPPED_SHADERS + + 16 * ShaderConvertSelector::NUM_VARIABLE_WRITE_MASK_SHADERS; +static_assert(NUM_REMAPPED_SHADERS <= 256); // We use u8 for the remap indices. + +static constexpr std::array GenRemapArray() +{ + std::array out{}; + u32 out_idx = 0; + const u32 invalid = 0xffffffff; + for (u32 i = 0; i < NUM_REMAP_INPUTS; i++) + out[i] = RemapIndexIsValid(i) ? out_idx++ : invalid; + return out; +} + +static constexpr std::array GetPackedShaders() +{ + std::array out{}; + u32 append_idx = 0; + for (u32 i = 0; i < NUM_REMAP_INPUTS; i++) + { + if (RemapIndexIsValid(i)) + out[append_idx++] = GetRemappedShader(i); + } + for (u32 i = 0; i < 16; i++) + out[append_idx++] = ShaderConvertSelector(ShaderConvert::COPY, i); + for (u32 i = 0; i < 16; i++) + out[append_idx++] = ShaderConvertSelector(ShaderConvert::RTA_CORRECTION, i); + return out; +} + +constinit const u32 ShaderConvertSelector::NUM_REMAPPED_SHADERS = ::NUM_REMAPPED_SHADERS; +constinit const u32 ShaderConvertSelector::NUM_TOTAL_SHADERS = ::NUM_TOTAL_SHADERS; +constinit const std::array ShaderConvertSelector::INDEX_REMAP = GenRemapArray(); +static constexpr auto PACKED_SHADERS = GetPackedShaders(); +const std::span ShaderConvertSelector::SHADERS = PACKED_SHADERS; + // clang-format off // Maps PS2 blend modes to our best approximation of them with PC hardware diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index bc5419cd9e..99360035b8 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -13,11 +13,13 @@ #include "GS/GSAlignedClass.h" #include "GS/GSExtra.h" #include +#include enum class ShaderConvert { COPY = 0, - RGBA8_TO_16_BITS, + DEPTH_COPY, + RGB5A1_TO_16_BITS, DATM_1, DATM_0, DATM_1_RTA_CORRECTION, @@ -27,23 +29,16 @@ enum class ShaderConvert RTA_CORRECTION, RTA_DECORRECTION, TRANSPARENCY_FILTER, - FLOAT32_TO_16_BITS, - FLOAT32_TO_32_BITS, - FLOAT32_TO_RGBA8, - FLOAT32_TO_RGB8, - FLOAT16_TO_RGB5A1, - RGBA8_TO_FLOAT32, - RGBA8_TO_FLOAT24, - RGBA8_TO_FLOAT16, - RGB5A1_TO_FLOAT16, - RGBA8_TO_FLOAT32_BILN, - RGBA8_TO_FLOAT24_BILN, - RGBA8_TO_FLOAT16_BILN, - RGB5A1_TO_FLOAT16_BILN, - FLOAT32_DEPTH_TO_COLOR, - FLOAT32_COLOR_TO_DEPTH, - FLOAT32_TO_FLOAT24, - DEPTH_COPY, + DEPTH32_TO_16_BITS, + DEPTH32_TO_32_BITS, + DEPTH32_TO_RGBA8, + DEPTH32_TO_RGB8, + DEPTH16_TO_RGB5A1, + RGBA8_TO_DEPTH32, + RGBA8_TO_DEPTH24, + RGBA8_TO_DEPTH16, + RGB5A1_TO_DEPTH16, + DEPTH32_TO_DEPTH24, DOWNSAMPLE_COPY, RGBA_TO_8I, RGB5A1_TO_8I, @@ -53,6 +48,19 @@ enum class ShaderConvert Count }; +enum class PresentShader +{ + COPY = 0, + SCANLINE, + DIAGONAL_FILTER, + TRIANGULAR_FILTER, + COMPLEX_FILTER, + LOTTES_FILTER, + SUPERSAMPLE_4xRGSS, + SUPERSAMPLE_AUTO, + Count +}; + enum class SetDATM : u8 { DATM0 = 0U, @@ -71,7 +79,7 @@ enum class ShaderInterlace Count }; -static inline bool HasVariableWriteMask(ShaderConvert shader) +static inline constexpr bool HasVariableWriteMask(ShaderConvert shader) { switch (shader) { @@ -83,37 +91,64 @@ static inline bool HasVariableWriteMask(ShaderConvert shader) } } -static inline int GetShaderIndexForMask(ShaderConvert shader, int mask) -{ - pxAssert(HasVariableWriteMask(shader)); - int index = mask; - if (shader == ShaderConvert::RTA_CORRECTION) - index |= 1 << 4; - return index; -} - -static inline bool HasDepthOutput(ShaderConvert shader) +static inline constexpr bool HasColorOutput(ShaderConvert shader) { switch (shader) { - case ShaderConvert::RGBA8_TO_FLOAT32: - case ShaderConvert::RGBA8_TO_FLOAT24: - case ShaderConvert::RGBA8_TO_FLOAT16: - case ShaderConvert::RGB5A1_TO_FLOAT16: - case ShaderConvert::RGBA8_TO_FLOAT32_BILN: - case ShaderConvert::RGBA8_TO_FLOAT24_BILN: - case ShaderConvert::RGBA8_TO_FLOAT16_BILN: - case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: - case ShaderConvert::FLOAT32_COLOR_TO_DEPTH: - case ShaderConvert::FLOAT32_TO_FLOAT24: - case ShaderConvert::DEPTH_COPY: + case ShaderConvert::COPY: + case ShaderConvert::RTA_CORRECTION: + case ShaderConvert::RTA_DECORRECTION: + case ShaderConvert::TRANSPARENCY_FILTER: + case ShaderConvert::DEPTH32_TO_RGBA8: + case ShaderConvert::DEPTH32_TO_RGB8: + case ShaderConvert::DEPTH16_TO_RGB5A1: + case ShaderConvert::DOWNSAMPLE_COPY: + case ShaderConvert::RGBA_TO_8I: + case ShaderConvert::RGB5A1_TO_8I: + case ShaderConvert::CLUT_4: + case ShaderConvert::CLUT_8: + case ShaderConvert::YUV: + case ShaderConvert::COLCLIP_RESOLVE: return true; default: return false; } } -static inline bool HasStencilOutput(ShaderConvert shader) +static inline constexpr bool HasFloat32Output(ShaderConvert shader) +{ + switch (shader) + { + case ShaderConvert::RGBA8_TO_DEPTH32: + case ShaderConvert::RGBA8_TO_DEPTH24: + case ShaderConvert::RGBA8_TO_DEPTH16: + case ShaderConvert::RGB5A1_TO_DEPTH16: + case ShaderConvert::DEPTH_COPY: + case ShaderConvert::DEPTH32_TO_DEPTH24: + return true; + default: + return false; + } +} + +static inline constexpr bool HasFloat32Input(ShaderConvert shader) +{ + switch (shader) + { + case ShaderConvert::DEPTH_COPY: + case ShaderConvert::DEPTH32_TO_16_BITS: + case ShaderConvert::DEPTH32_TO_32_BITS: + case ShaderConvert::DEPTH32_TO_RGBA8: + case ShaderConvert::DEPTH32_TO_RGB8: + case ShaderConvert::DEPTH16_TO_RGB5A1: + case ShaderConvert::DEPTH32_TO_DEPTH24: + return true; + default: + return false; + } +} + +static inline constexpr bool IsDATMConvertShader(ShaderConvert shader) { switch (shader) { @@ -127,63 +162,378 @@ static inline bool HasStencilOutput(ShaderConvert shader) } } -static inline bool SupportsNearest(ShaderConvert shader) +static inline constexpr bool HasStencilOutput(ShaderConvert shader) +{ + return IsDATMConvertShader(shader); +} + +static inline constexpr int IntegerOutputBpp(ShaderConvert shader) { switch (shader) { - case ShaderConvert::RGBA8_TO_FLOAT32_BILN: - case ShaderConvert::RGBA8_TO_FLOAT24_BILN: - case ShaderConvert::RGBA8_TO_FLOAT16_BILN: - case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: - return false; + case ShaderConvert::DEPTH32_TO_32_BITS: + return 32; + case ShaderConvert::DEPTH32_TO_16_BITS: + case ShaderConvert::RGB5A1_TO_16_BITS: + return 16; default: - return true; + return 0; } } -static inline bool SupportsBilinear(ShaderConvert shader) +static inline constexpr bool HasColorClipOutput(ShaderConvert shader) +{ + return (shader == ShaderConvert::COLCLIP_INIT); +} + +static inline constexpr bool SupportsBilinear(ShaderConvert shader) { switch (shader) { - case ShaderConvert::RGBA8_TO_FLOAT32: - case ShaderConvert::RGBA8_TO_FLOAT24: - case ShaderConvert::RGBA8_TO_FLOAT16: - case ShaderConvert::RGB5A1_TO_FLOAT16: - return false; - default: + case ShaderConvert::RGBA8_TO_DEPTH32: + case ShaderConvert::RGBA8_TO_DEPTH24: + case ShaderConvert::RGBA8_TO_DEPTH16: + case ShaderConvert::RGB5A1_TO_DEPTH16: return true; + default: + return false; } } -static inline u32 ShaderConvertWriteMask(ShaderConvert shader) +static inline constexpr u32 ShaderConvertWriteMask(ShaderConvert shader) { switch (shader) { - case ShaderConvert::FLOAT32_TO_RGB8: + case ShaderConvert::DEPTH32_TO_RGB8: return 0x7; default: return 0xf; } } -enum class PresentShader +static inline constexpr int GetShaderIndexForMask(ShaderConvert shader, int mask) { - COPY = 0, - SCANLINE, - DIAGONAL_FILTER, - TRIANGULAR_FILTER, - COMPLEX_FILTER, - LOTTES_FILTER, - SUPERSAMPLE_4xRGSS, - SUPERSAMPLE_AUTO, - Count + pxAssert(HasVariableWriteMask(shader)); + int index = mask; + if (shader == ShaderConvert::RTA_CORRECTION) + index |= 1 << 4; + return index; +} + +static inline constexpr ShaderConvert SetDATMShader(SetDATM datm) +{ + switch (datm) + { + case SetDATM::DATM1_RTA_CORRECTION: + return ShaderConvert::DATM_1_RTA_CORRECTION; + case SetDATM::DATM0_RTA_CORRECTION: + return ShaderConvert::DATM_0_RTA_CORRECTION; + case SetDATM::DATM1: + return ShaderConvert::DATM_1; + case SetDATM::DATM0: + default: + return ShaderConvert::DATM_0; + } +} + +const char* ShaderEntryPoint(ShaderConvert value); +const char* ShaderEntryPoint(PresentShader value); +const char* ShaderConvertName(ShaderConvert shader); + +class ShaderConvertSelector +{ + union + { + struct + { + u32 shader : 8; // Main shader + u32 mask : 8; // Variable color mask + u32 depth_in : 1; // Depth texture input + u32 depth_out : 1; // Depth texture output + u32 biln : 1; // Shader bilinear (HW bilinear is specified separately) + }; + + u32 key; + } fields; + + static_assert(sizeof(fields) == 4); + +public: + constexpr ShaderConvertSelector(ShaderConvert shader = ShaderConvert::COPY, u8 mask = 0xf, bool depth_in = false, + bool depth_out = false, bool biln = false) + : fields { static_cast(shader) } + { + *this = SetMask(mask).SetDepthInput(depth_in).SetDepthOutput(depth_out).SetBiln(biln); + } + + constexpr ShaderConvert Shader() const + { + return static_cast(fields.shader); + } + + constexpr u8 Mask() const + { + return fields.mask; + } + + constexpr u8 DefaultMask() const + { + return ShaderConvertWriteMask(Shader()); + } + + constexpr bool Biln() const + { + return fields.biln; + } + + constexpr bool SupportsBilinear() const + { + return ::SupportsBilinear(Shader()); + } + + constexpr bool ColorOutput() const + { + return HasColorOutput(Shader()); + } + + constexpr bool DepthOutput() const + { + return fields.depth_out; + } + + constexpr bool DepthInput() const + { + return fields.depth_in; + } + + constexpr bool StencilOutput() const + { + return HasStencilOutput(Shader()); + } + + constexpr bool DATMConvertShader() const + { + return IsDATMConvertShader(Shader()); + } + + constexpr bool Float32Output() const + { + return HasFloat32Output(Shader()); + } + + constexpr bool Float32Input() const + { + return HasFloat32Input(Shader()); + } + + constexpr int IntegerOutputBpp() const + { + return ::IntegerOutputBpp(Shader()); + } + + constexpr bool VariableWriteMask() const + { + return HasVariableWriteMask(Shader()); + } + + constexpr bool ColorClipOutput() const + { + return HasColorClipOutput(Shader()); + } + + const char* Name() const + { + return ShaderConvertName(Shader()); + } + + const char* EntryPoint() const + { + return ShaderEntryPoint(Shader()); + } + + constexpr ShaderConvertSelector SetMask(u8 mask) const + { + ShaderConvertSelector tmp = *this; + tmp.fields.mask = VariableWriteMask() ? (mask & 0xf) : DefaultMask(); + return tmp; + } + + constexpr ShaderConvertSelector SetMask(bool wr, bool wg, bool wb, bool wa) const + { + return SetMask((wr ? 1 : 0) | (wg ? 2 : 0) | (wb ? 4 : 0) | (wa ? 8 : 0)); + } + + constexpr ShaderConvertSelector SetDepthInput(bool depth_in) const + { + ShaderConvertSelector tmp = *this; + tmp.fields.depth_in = Float32Input() && depth_in; + return tmp; + } + + constexpr ShaderConvertSelector SetDepthOutput(bool depth_out) const + { + ShaderConvertSelector tmp = *this; + tmp.fields.depth_out = Float32Output() && depth_out; + return tmp; + } + + constexpr ShaderConvertSelector SetBiln(bool biln) const + { + ShaderConvertSelector tmp = *this; + tmp.fields.biln = SupportsBilinear() && biln; + return tmp; + } + + GSTexture::Format OutputFormat() const + { + if (fields.depth_out) + return GSTexture::Format::DepthStencil; + else if (int bpp = IntegerOutputBpp()) + return bpp == 16 ? GSTexture::Format::UInt16 : GSTexture::Format::UInt32; + else if (Float32Output()) + return GSTexture::Format::DepthColor; + else if (ColorOutput()) + return GSTexture::Format::Color; + else if (ColorClipOutput()) + return GSTexture::Format::ColorClip; + else + return GSTexture::Format::Invalid; + } + +private: + // Helper variables for packing valid shaders into a contiguous range. + static const std::span SHADERS; + static const std::array(ShaderConvert::Count) * 8> INDEX_REMAP; + static const u32 NUM_REMAPPED_SHADERS; + +public: + static constexpr u32 NUM_VARIABLE_WRITE_MASK_SHADERS = 2; + static const u32 NUM_TOTAL_SHADERS; + + u32 Index() const + { + if (VariableWriteMask() && !fields.depth_in && !fields.depth_out && !fields.biln) + return GetShaderIndexForMask(Shader(), fields.mask) + NUM_REMAPPED_SHADERS; + u32 remapped = INDEX_REMAP[(fields.depth_in << 0) + + (fields.depth_out << 1) + + (fields.biln << 2) + + (fields.shader << 3)]; + pxAssert(remapped < NUM_REMAPPED_SHADERS); + return remapped; + } + + // Inverse of Index() + static ShaderConvertSelector Get(u32 index) + { + return SHADERS[index]; + } }; -/// Get the name of a shader -/// (Can't put methods on an enum class) -int SetDATMShader(SetDATM datm); -const char* shaderName(ShaderConvert value); -const char* shaderName(PresentShader value); +static inline ShaderConvertSelector GetConvertShader(GSTexture::Format src, GSTexture::Format dst, + u32 src_bpp = 32, u32 dst_bpp = 32, u8 mask = 0xf) +{ + ShaderConvert shader = static_cast(-1); + switch (src) + { + case GSTexture::Format::Color: + switch (dst) + { + case GSTexture::Format::Color: + pxAssert(src_bpp == 32 && dst_bpp == 32); + shader = ShaderConvert::COPY; // bpp is handled by mask + break; + case GSTexture::Format::DepthColor: + case GSTexture::Format::DepthStencil: + switch (dst_bpp) + { + case 32: + shader = ShaderConvert::RGBA8_TO_DEPTH32; + break; + case 24: + shader = ShaderConvert::RGBA8_TO_DEPTH24; + break; + case 16: + pxAssert(src_bpp == 16 || src_bpp == 32); + shader = src_bpp == 16 ? ShaderConvert::RGB5A1_TO_DEPTH16 : + ShaderConvert::RGBA8_TO_DEPTH16; + break; + default: + pxAssert(false); + break; + } + break; + default: + pxAssert(false); + break; + } + break; + case GSTexture::Format::DepthColor: + case GSTexture::Format::DepthStencil: + switch (dst) + { + case GSTexture::Format::Color: + switch (dst_bpp) + { + case 32: + shader = ShaderConvert::DEPTH32_TO_RGBA8; + break; + case 24: + shader = ShaderConvert::DEPTH32_TO_RGB8; + break; + case 16: + pxAssert(src_bpp == 16); + shader = ShaderConvert::DEPTH16_TO_RGB5A1; + break; + default: + pxAssert(false); + break; + } + break; + case GSTexture::Format::DepthColor: + case GSTexture::Format::DepthStencil: + switch (dst_bpp) + { + case 32: + pxAssert(src_bpp == 32); + shader = ShaderConvert::DEPTH_COPY; + break; + case 24: + pxAssert(src_bpp == 32); + shader = ShaderConvert::DEPTH32_TO_DEPTH24; + break; + default: + pxAssert(false); + break; + } + break; + } + break; + default: + pxAssert(false); + break; + } + + return ShaderConvertSelector(shader, mask, src == GSTexture::Format::DepthStencil, + dst == GSTexture::Format::DepthStencil); +} + +static inline ShaderConvertSelector GetConvertShader(const GSTexture* src, const GSTexture* dst, u32 src_bpp, u32 dst_bpp, u8 mask = 0xf) +{ + return GetConvertShader(src->GetFormat(), dst->GetFormat(), src_bpp, dst_bpp, mask); +} + +static inline ShaderConvertSelector GetConvertShaderMask(GSTexture::Format src, GSTexture::Format dst, + u32 src_bpp, u32 dst_bpp, bool red = true, bool green = true, bool blue = true, bool alpha = true) +{ + const u8 mask = (red ? 1 : 0) | (green ? 2 : 0) | (blue ? 4 : 0) | (alpha ? 8 : 0); + return GetConvertShader(src, dst, src_bpp, dst_bpp, mask); +} + +static inline ShaderConvertSelector GetConvertShaderMask(const GSTexture* src, const GSTexture* dst, + u32 src_bpp, u32 dst_bpp, bool red = true, bool green = true, bool blue = true, bool alpha = true) +{ + return GetConvertShaderMask(src->GetFormat(), dst->GetFormat(), src_bpp, dst_bpp, red, green, blue, alpha); +} enum ChannelFetch { @@ -1076,9 +1426,14 @@ protected: protected: // Entry point to the renderer-specific StretchRect code. virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) = 0; - void DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear); - + ShaderConvertSelector shader, bool linear) = 0; + virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect, + PresentShader shader, bool linear) + { + pxFailRel("Not implemented"); + } + void DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, + ShaderConvertSelector shader, bool linear); public: GSDevice(); virtual ~GSDevice(); @@ -1196,23 +1551,62 @@ public: virtual void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) = 0; GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true); - GSTexture* CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true); + GSTexture* CreateDepthStencil(int w, int h, bool clear = true, bool prefer_reuse = true); GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false); + GSTexture* CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true); + GSTexture* CreateDepthStencil(const GSVector2i& size, bool clear = true, bool prefer_reuse = true); + GSTexture* CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false); + GSTexture* CreateCompatible(GSTexture* tex, bool clear = true, bool prefer_reuse = true); + GSTexture* CreateCompatible(GSTexture* tex, const GSVector2i& size, bool clear = true, bool prefer_reuse = true); + GSTexture* CreateCompatible(GSTexture* tex, int w, int h, bool clear = true, bool prefer_reuse = true); virtual std::unique_ptr CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) = 0; virtual void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) = 0; - void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, ShaderConvert shader = ShaderConvert::COPY); - void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true); - void StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true); + // StretchRect - all options + void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader = ShaderConvert::COPY, bool linear = false); + void StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader = ShaderConvert::COPY, bool linear = false); + void StretchRect(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader = ShaderConvert::COPY, bool linear = false); + + // StretchRect - infer shader based on formats + void StretchRectAuto(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool linear, + u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAuto(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, bool linear, + u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAuto(GSTexture* sTex, GSTexture* dTex, bool linear, u32 src_bpp = 32, u32 dst_bpp = 32); + + // StretchRect - nearest filter + void StretchRectNearest(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader = ShaderConvert::COPY); + void StretchRectNearest(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader = ShaderConvert::COPY); + void StretchRectNearest(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader = ShaderConvert::COPY); + + // StretchRect - nearest filter, infer shader based on formats + void StretchRectAutoNearest(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAutoNearest(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAutoNearest(GSTexture* sTex, GSTexture* dTex, u32 src_bpp = 32, u32 dst_bpp = 32); + + // StretchRect - linear filter + void StretchRectBiln(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader = ShaderConvert::COPY); + void StretchRectBiln(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader = ShaderConvert::COPY); + void StretchRectBiln(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader = ShaderConvert::COPY); + + // StretchRect - linear filter, infer shader based on formats + void StretchRectAutoBiln(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAutoBiln(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAutoBiln(GSTexture* sTex, GSTexture* dTex, u32 src_bpp = 32, u32 dst_bpp = 32); + + // StretchRect - nearest filter, infer shader based on formats, specify channel mask + void StretchRectAutoMask(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, u32 src_bpp = 32, u32 dst_bpp = 32); + void StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, bool red, bool green, bool blue, bool alpha, u32 src_bpp = 32, u32 dst_bpp = 32); /// Performs a screen blit for display. If dTex is null, it assumes you are writing to the system framebuffer/swap chain. virtual void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) = 0; /// Same as doing StretchRect for each item, except tries to batch together rectangles in as few draws as possible. /// The provided list should be sorted by texture, the implementations only check if it's the same as the last. - virtual void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader = ShaderConvert::COPY); + virtual void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader = ShaderConvert::COPY); /// Sorts a MultiStretchRect list for optimal batching. static void SortMultiStretchRects(MultiStretchRect* rects, u32 num_rects); diff --git a/pcsx2/GS/Renderers/Common/GSTexture.cpp b/pcsx2/GS/Renderers/Common/GSTexture.cpp index 6fe5f26c5f..488f4ffafc 100644 --- a/pcsx2/GS/Renderers/Common/GSTexture.cpp +++ b/pcsx2/GS/Renderers/Common/GSTexture.cpp @@ -20,7 +20,7 @@ bool GSTexture::Save(const std::string& fn) { // Depth textures need special treatment - we have a stencil component. // Just re-use the existing conversion shader instead. - if (m_format == Format::DepthStencil || m_format == Format::Float32) + if (m_format == Format::DepthStencil || m_format == Format::DepthColor) { GSTexture* temp = g_gs_device->CreateRenderTarget(GetWidth(), GetHeight(), Format::Color, false); if (!temp) @@ -29,7 +29,7 @@ bool GSTexture::Save(const std::string& fn) return false; } - g_gs_device->StretchRect(this, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), temp, GSVector4(GetRect()), ShaderConvert::FLOAT32_TO_RGBA8, false); + g_gs_device->StretchRectAutoNearest(this, temp); const bool res = temp->Save(fn); g_gs_device->Recycle(temp); return res; @@ -73,7 +73,7 @@ const char* GSTexture::GetFormatName(Format format) case Format::ColorHDR: return "ColorHDR"; case Format::ColorClip: return "ColorClip"; case Format::DepthStencil: return "DepthStencil"; - case Format::Float32: return "Float32"; + case Format::DepthColor: return "DepthColor"; case Format::UNorm8: return "UNorm8"; case Format::UInt16: return "UInt16"; case Format::UInt32: return "UInt32"; @@ -116,11 +116,11 @@ u32 GSTexture::GetCompressedBytesPerBlock(Format format) case Format::ColorHDR: return 8; // ColorHDR/RGBA16F case Format::ColorClip: return 8; // ColorClip/RGBA16 case Format::DepthStencil: return 4; // DepthStencil - case Format::Float32: return 4; // Float32/R32 + case Format::DepthColor: return 4; // DepthColor/R32 case Format::UNorm8: return 1; // UNorm8/R8 case Format::UInt16: return 2; // UInt16/R16UI case Format::UInt32: return 4; // UInt32/R32UI - case Format::PrimID: return 4; // Int32/R32I + case Format::PrimID: return 4; // PrimID/R32 case Format::BC1: return 8; // BC1 - 16 pixels in 64 bits case Format::BC2: return 16; // BC2 - 16 pixels in 128 bits case Format::BC3: return 16; // BC3 - 16 pixels in 128 bits diff --git a/pcsx2/GS/Renderers/Common/GSTexture.h b/pcsx2/GS/Renderers/Common/GSTexture.h index a0795801c1..c913dd8cb3 100644 --- a/pcsx2/GS/Renderers/Common/GSTexture.h +++ b/pcsx2/GS/Renderers/Common/GSTexture.h @@ -34,7 +34,7 @@ public: ColorHDR, ///< High dynamic range (RGBA16F) color texture ColorClip, ///< Color texture with more bits for colclip (wrap) emulation, given that blending requires 9bpc (RGBA16Unorm) DepthStencil, ///< Depth stencil texture - Float32, ///< For treating depth texture as RT + DepthColor, ///< For treating depth texture as RT UNorm8, ///< A8UNorm texture for paletted textures and the OSD font UInt16, ///< UInt16 texture for reading back 16-bit depth UInt32, ///< UInt32 texture for reading back 24 and 32-bit depth @@ -129,10 +129,18 @@ public: { return (m_type == Type::DepthStencil); } + __fi bool IsDepthColor() const + { + return (m_type == Type::RenderTarget && m_format == Format::DepthColor); + } __fi bool IsTexture() const { return (m_type == Type::Texture); } + __fi bool IsDepthLike() const + { + return IsDepthStencil() || IsDepthColor(); + } __fi State GetState() const { return m_state; } __fi void SetState(State state) { m_state = state; } @@ -143,6 +151,10 @@ public: __fi u32 GetClearColor() const { return m_clear_value.color; } __fi float GetClearDepth() const { return m_clear_value.depth; } __fi GSVector4 GetUNormClearColor() const { return GSVector4::unorm8(m_clear_value.color); } + __fi GSVector4 GetClearForFormat() const + { + return IsDepthLike() ? GSVector4(m_clear_value.depth, 0.0f, 0.0f, 0.0f) : GetUNormClearColor(); + } __fi void SetClearColor(u32 color) { diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 3c74ab9162..c9243c0c46 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -219,15 +219,36 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) const std::optional convert_hlsl = ReadShaderSource("shaders/dx11/convert.fx"); if (!convert_hlsl.has_value()) return false; + ShaderMacro sm_vs; + sm_vs.AddMacro("VERTEX_SHADER", 1); if (!m_shader_cache.GetVertexShaderAndInputLayout(m_dev.get(), m_convert.vs.put(), m_convert.il.put(), - il_convert, std::size(il_convert), *convert_hlsl, nullptr, "vs_main")) + il_convert, std::size(il_convert), *convert_hlsl, sm_vs.GetPtr(), "vs_main")) { return false; } - for (size_t i = 0; i < std::size(m_convert.ps); i++) + const auto WrapEntryPointMacro = [](const std::string& s) { return fmt::format("__{}__", s); }; + + m_convert.ps.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS); + for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++) { - m_convert.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, nullptr, shaderName(static_cast(i))); + const ShaderConvertSelector shader = ShaderConvertSelector::Get(i); + + const char* entry_point = shader.EntryPoint(); + std::string entry_point_macro = WrapEntryPointMacro(entry_point); + + ShaderMacro sm_ps; + sm_ps.AddMacro("PIXEL_SHADER", 1); + sm_ps.AddMacro("HAS_BILN", static_cast(shader.Biln())); + sm_ps.AddMacro("HAS_STENCIL_OUTPUT", static_cast(shader.StencilOutput())); + sm_ps.AddMacro("HAS_INTEGER_OUTPUT", static_cast(shader.IntegerOutputBpp() != 0)); + sm_ps.AddMacro("HAS_DEPTH_INPUT", 0); // unused + sm_ps.AddMacro("HAS_DEPTH_OUTPUT", static_cast(shader.DepthOutput())); + sm_ps.AddMacro("HAS_FLOAT32_INPUT", static_cast(shader.Float32Input())); + sm_ps.AddMacro("HAS_FLOAT32_OUTPUT", static_cast(shader.Float32Output())); + sm_ps.AddMacro(entry_point_macro.c_str(), 1); + + m_convert.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, sm_ps.GetPtr(), entry_point); if (!m_convert.ps[i]) return false; } @@ -243,7 +264,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) for (size_t i = 0; i < std::size(m_present.ps); i++) { - m_present.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, nullptr, shaderName(static_cast(i))); + m_present.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, nullptr, ShaderEntryPoint(static_cast(i))); if (!m_present.ps[i]) return false; } @@ -548,8 +569,12 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) for (size_t i = 0; i < std::size(m_date.primid_init_ps); i++) { - const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%zu", i)); - m_date.primid_init_ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, nullptr, entry_point.c_str()); + const std::string entry_point(StringUtil::StdStringFromFormat("ps_primid_image_init_%zu", i)); + const std::string entry_point_macro = WrapEntryPointMacro(entry_point); + ShaderMacro sm_ps; + sm_ps.AddMacro("PIXEL_SHADER", 1); + sm_ps.AddMacro(entry_point_macro.c_str(), 1); + m_date.primid_init_ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, sm_ps.GetPtr(), entry_point.c_str()); if (!m_date.primid_init_ps[i]) return false; } @@ -1242,7 +1267,7 @@ void GSDevice11::CommitClear(GSTexture* t) if (T->GetState() == GSTexture::State::Invalidated) m_ctx->DiscardView(static_cast(*T)); else - m_ctx->ClearRenderTargetView(*T, T->GetUNormClearColor().F32); + m_ctx->ClearRenderTargetView(*T, T->GetClearForFormat().F32); } T->SetState(GSTexture::State::Dirty); @@ -1385,9 +1410,11 @@ void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, } void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) + ShaderConvertSelector shader, bool linear) { - DoStretchRect(sTex, sRect, dTex, dRect, m_convert.ps[static_cast(shader)].get(), nullptr, m_convert.bs[cms.wrgba].get(), linear); + const u8 mask = shader.Mask(); + shader = ProcessShaderConvertSelector(shader); // Removes mask and depth output. + DoStretchRect(sTex, sRect, dTex, dRect, GetConvertShader(shader), nullptr, m_convert.bs[mask].get(), linear); } void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, bool linear) @@ -1544,7 +1571,7 @@ void GSDevice11::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u const GSVector4 dRect(0, 0, dSize, 1); const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8; - DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast(shader)].get(), m_merge.cb.get(), nullptr, false); + DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, GetConvertShader(shader), m_merge.cb.get(), nullptr, false); } void GSDevice11::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) @@ -1563,7 +1590,7 @@ void GSDevice11::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offs const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight()); const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I; - DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast(shader)].get(), m_merge.cb.get(), nullptr, false); + DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, GetConvertShader(shader), m_merge.cb.get(), nullptr, false); } void GSDevice11::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) @@ -1583,16 +1610,18 @@ void GSDevice11::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 UpdateSubresource(m_merge.cb.get(), &cb, &m_merge.cb_uniforms, sizeof(cb)); const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY; - DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast(shader)].get(), m_merge.cb.get(), nullptr, false); + DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, GetConvertShader(shader), m_merge.cb.get(), nullptr, false); } -void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) +void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) { + shader = ProcessShaderConvertSelector(shader); + IASetInputLayout(m_convert.il.get()); IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); VSSetShader(m_convert.vs.get(), nullptr); - PSSetShader(m_convert.ps[static_cast(shader)].get(), nullptr); + PSSetShader(GetConvertShader(shader), nullptr); OMSetDepthStencilState(dTex->IsRenderTarget() ? m_convert.dss.get() : m_convert.dss_write.get(), 0); OMSetRenderTargets(dTex->IsRenderTarget() ? dTex : nullptr, dTex->IsDepthStencil() ? dTex : nullptr); @@ -1706,7 +1735,7 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, // Save 2nd output if (feedback_write_2) { - DoStretchRect(dTex, full_r, sTex[2], dRect[2], m_convert.ps[static_cast(ShaderConvert::YUV)].get(), + DoStretchRect(dTex, full_r, sTex[2], dRect[2], GetConvertShader(ShaderConvert::YUV), m_merge.cb.get(), nullptr, linear); } @@ -1722,7 +1751,7 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, if (feedback_write_1) { - DoStretchRect(dTex, full_r, sTex[2], dRect[2], m_convert.ps[static_cast(ShaderConvert::YUV)].get(), + DoStretchRect(dTex, full_r, sTex[2], dRect[2], GetConvertShader(ShaderConvert::YUV), m_merge.cb.get(), nullptr, linear); } } @@ -2312,7 +2341,7 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV PSSetShaderResource(0, rt); PSSetSamplerState(m_convert.pt.get()); - PSSetShader(m_convert.ps[SetDATMShader(datm)].get(), nullptr); + PSSetShader(GetConvertShader(SetDATMShader(datm)), nullptr); // draw diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index 0c44060c46..1f8718beb4 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -182,7 +182,7 @@ private: { wil::com_ptr_nothrow il; wil::com_ptr_nothrow vs; - wil::com_ptr_nothrow ps[static_cast(ShaderConvert::Count)]; + std::vector> ps; wil::com_ptr_nothrow ln; wil::com_ptr_nothrow pt; wil::com_ptr_nothrow dss; @@ -190,6 +190,16 @@ private: std::array, 16> bs; } m_convert; + ID3D11PixelShader* GetConvertShader(ShaderConvertSelector shader) const + { + return m_convert.ps[shader.Index()].get(); + } + + ID3D11PixelShader* GetConvertShader(ShaderConvert shader) const + { + return m_convert.ps[ShaderConvertSelector(shader).Index()].get(); + } + struct { wil::com_ptr_nothrow il; @@ -269,8 +279,12 @@ private: protected: virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override; - + ShaderConvertSelector shader, bool linear) override; + ShaderConvertSelector ProcessShaderConvertSelector(ShaderConvertSelector shader) const + { + // Depth input is handled same as color input. Mask is handled separately from program. + return shader.SetDepthInput(false).SetMask(0xf); + } public: GSDevice11(); ~GSDevice11() override; @@ -328,7 +342,7 @@ public: void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override; void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override; void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override; - void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; + void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override; void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds); void SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox); diff --git a/pcsx2/GS/Renderers/DX11/GSTexture11.cpp b/pcsx2/GS/Renderers/DX11/GSTexture11.cpp index 38855dbede..95305cfd3c 100644 --- a/pcsx2/GS/Renderers/DX11/GSTexture11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSTexture11.cpp @@ -28,23 +28,24 @@ DXGI_FORMAT GSTexture11::GetDXGIFormat(Format format) // clang-format off switch (format) { - case GSTexture::Format::Color: return DXGI_FORMAT_R8G8B8A8_UNORM; - case GSTexture::Format::ColorHQ: return DXGI_FORMAT_R10G10B10A2_UNORM; - case GSTexture::Format::ColorHDR: return DXGI_FORMAT_R16G16B16A16_FLOAT; - case GSTexture::Format::ColorClip: return DXGI_FORMAT_R16G16B16A16_UNORM; - case GSTexture::Format::DepthStencil: return DXGI_FORMAT_R32G8X24_TYPELESS; - case GSTexture::Format::UNorm8: return DXGI_FORMAT_A8_UNORM; - case GSTexture::Format::UInt16: return DXGI_FORMAT_R16_UINT; - case GSTexture::Format::UInt32: return DXGI_FORMAT_R32_UINT; - case GSTexture::Format::PrimID: return DXGI_FORMAT_R32_FLOAT; - case GSTexture::Format::BC1: return DXGI_FORMAT_BC1_UNORM; - case GSTexture::Format::BC2: return DXGI_FORMAT_BC2_UNORM; - case GSTexture::Format::BC3: return DXGI_FORMAT_BC3_UNORM; - case GSTexture::Format::BC7: return DXGI_FORMAT_BC7_UNORM; - case GSTexture::Format::Invalid: - default: - pxAssert(0); - return DXGI_FORMAT_UNKNOWN; + case GSTexture::Format::Color: return DXGI_FORMAT_R8G8B8A8_UNORM; + case GSTexture::Format::ColorHQ: return DXGI_FORMAT_R10G10B10A2_UNORM; + case GSTexture::Format::ColorHDR: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case GSTexture::Format::ColorClip: return DXGI_FORMAT_R16G16B16A16_UNORM; + case GSTexture::Format::DepthStencil: return DXGI_FORMAT_R32G8X24_TYPELESS; + case GSTexture::Format::DepthColor: return DXGI_FORMAT_R32_FLOAT; + case GSTexture::Format::UNorm8: return DXGI_FORMAT_A8_UNORM; + case GSTexture::Format::UInt16: return DXGI_FORMAT_R16_UINT; + case GSTexture::Format::UInt32: return DXGI_FORMAT_R32_UINT; + case GSTexture::Format::PrimID: return DXGI_FORMAT_R32_FLOAT; + case GSTexture::Format::BC1: return DXGI_FORMAT_BC1_UNORM; + case GSTexture::Format::BC2: return DXGI_FORMAT_BC2_UNORM; + case GSTexture::Format::BC3: return DXGI_FORMAT_BC3_UNORM; + case GSTexture::Format::BC7: return DXGI_FORMAT_BC7_UNORM; + case GSTexture::Format::Invalid: + default: + pxAssert(0); + return DXGI_FORMAT_UNKNOWN; } // clang-format on } diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index bc2d1957d8..9a08e9f92a 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -34,10 +34,6 @@ static u32 s_debug_scope_depth = 0; #endif -static bool IsDATMConvertShader(ShaderConvert i) -{ - return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1 || i == ShaderConvert::DATM_0_RTA_CORRECTION || i == ShaderConvert::DATM_1_RTA_CORRECTION); -} static bool IsDATEModePrimIDInit(u32 flag) { return flag == 1 || flag == 2; @@ -1524,7 +1520,7 @@ void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_f DXGI_FORMAT_UNKNOWN}, // ColorClip {DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT}, // DepthStencil - {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN}, // Float32 + {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN}, // DepthColor {DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN}, // UNorm8 {DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN}, // UInt16 {DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN}, // UInt32 @@ -1613,7 +1609,7 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, { dTex12->TransitionToState(GSTexture12::ResourceState::RenderTarget); GetCommandList().list4->ClearRenderTargetView( - dTex12->GetWriteDescriptor(), sTex12->GetUNormClearColor().v, 0, nullptr); + dTex12->GetWriteDescriptor(), sTex12->GetClearForFormat().v, 0, nullptr); } else { @@ -1673,16 +1669,20 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, } void GSDevice12::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) + ShaderConvertSelector shader, bool linear) { - const bool allow_discard = (cms.wrgba == 0xf); - const ID3D12PipelineState* state; - if (HasVariableWriteMask(shader)) - state = m_color_copy[GetShaderIndexForMask(shader, cms.wrgba)].get(); - else - state = dTex ? m_convert[static_cast(shader)].get() : m_present[static_cast(shader)].get(); + pxAssert(dTex); + shader = ProcessShaderConvertSelector(shader); // Removes depth input + const bool allow_discard = (shader.Mask() == 0xf); DoStretchRect(static_cast(sTex), sRect, static_cast(dTex), dRect, - state, linear, allow_discard); + GetConvertPipeline(shader), linear, allow_discard); +} + +void GSDevice12::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect, + PresentShader shader, bool linear) +{ + DoStretchRect(static_cast(sTex), sRect, nullptr, dRect, + m_present[static_cast(shader)].get(), linear, true); } void GSDevice12::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, @@ -1717,7 +1717,7 @@ void GSDevice12::UpdateCLUTTexture( const GSVector4 dRect(0, 0, dSize, 1); const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8; DoStretchRect(static_cast(sTex), GSVector4::zero(), static_cast(dTex), dRect, - m_convert[static_cast(shader)].get(), false, true); + GetConvertPipeline(shader), false, true); } void GSDevice12::ConvertToIndexedTexture( @@ -1739,7 +1739,7 @@ void GSDevice12::ConvertToIndexedTexture( const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight()); const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I; DoStretchRect(static_cast(sTex), GSVector4::zero(), static_cast(dTex), dRect, - m_convert[static_cast(shader)].get(), false, true); + GetConvertPipeline(shader), false, true); } void GSDevice12::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) @@ -1762,12 +1762,14 @@ void GSDevice12::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 //const GSVector4 dRect = GSVector4(dTex->GetRect()); const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY; DoStretchRect(static_cast(sTex), GSVector4::zero(), static_cast(dTex), dRect, - m_convert[static_cast(shader)].get(), false, true); + GetConvertPipeline(shader), false, true); } void GSDevice12::DrawMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) + const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) { + shader = ProcessShaderConvertSelector(shader); // Removes depth input + GSTexture* last_tex = rects[0].src; bool last_linear = rects[0].linear; u8 last_wmask = rects[0].wmask.wrgba; @@ -1808,7 +1810,7 @@ void GSDevice12::DrawMultiStretchRects( } void GSDevice12::DoMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvert shader) + const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvertSelector shader) { g_perfmon.Put(GSPerfMon::TextureCopies, 1); @@ -1879,10 +1881,7 @@ void GSDevice12::DoMultiStretchRects( SetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); SetUtilityTexture(rects[0].src, rects[0].linear ? m_linear_sampler_cpu : m_point_sampler_cpu); - pxAssert(HasVariableWriteMask(shader) || rects[0].wmask.wrgba == 0xf); - SetPipeline((rects[0].wmask.wrgba != 0xf) ? - m_color_copy[GetShaderIndexForMask(shader, rects[0].wmask.wrgba)].get() : - m_convert[static_cast(shader)].get()); + SetPipeline(GetConvertPipeline(shader.SetMask(rects[0].wmask.wrgba))); if (ApplyUtilityState()) DrawIndexedPrimitive(); @@ -1901,7 +1900,7 @@ void GSDevice12::BeginRenderPassForStretchRect( BeginRenderPass(load_op, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, - dTex->GetUNormClearColor()); + dTex->GetClearForFormat()); } else { @@ -2032,7 +2031,7 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, GSVector4::unorm8(c)); SetUtilityRootSignature(); - SetPipeline(m_convert[static_cast(ShaderConvert::COPY)].get()); + SetPipeline(GetConvertPipeline(ShaderConvert::COPY)); DrawStretchRect(sRect[1], PMODE.SLBG ? dRect[2] : dRect[1], dsize); dTex->SetState(GSTexture::State::Dirty); dcleared = true; @@ -2053,7 +2052,7 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, if (dcleared) { SetUtilityRootSignature(); - SetPipeline(m_convert[static_cast(ShaderConvert::YUV)].get()); + SetPipeline(GetConvertPipeline(ShaderConvert::YUV)); DrawStretchRect(full_r, dRect[2], fbsize); } EndRenderPass(); @@ -2096,7 +2095,7 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, { EndRenderPass(); SetUtilityRootSignature(); - SetPipeline(m_convert[static_cast(ShaderConvert::YUV)].get()); + SetPipeline(GetConvertPipeline(ShaderConvert::YUV)); SetUtilityTexture(dTex, sampler); OMSetRenderTargets(sTex[2], nullptr, nullptr, fbarea); BeginRenderPass( @@ -2598,6 +2597,7 @@ static void AddUtilityVertexAttributes(D3D12::GraphicsPipelineBuilder& gpb) GSDevice12::ComPtr GSDevice12::GetUtilityVertexShader(const std::string& source, const char* entry_point) { ShaderMacro sm_model; + sm_model.AddMacro("VERTEX_SHADER", "1"); return m_shader_cache.GetVertexShader(source, sm_model.GetPtr(), entry_point); } @@ -2703,14 +2703,14 @@ bool GSDevice12::CreateRootSignatures() bool GSDevice12::CompileConvertPipelines() { - std::optional shader = ReadShaderSource("shaders/dx11/convert.fx"); - if (!shader) + std::optional source = ReadShaderSource("shaders/dx11/convert.fx"); + if (!source) { Host::ReportErrorAsync("GS", "Failed to read shaders/dx11/convert.fx."); return false; } - m_convert_vs = GetUtilityVertexShader(*shader, "vs_main"); + m_convert_vs = GetUtilityVertexShader(*source, "vs_main"); if (!m_convert_vs) return false; @@ -2721,50 +2721,29 @@ bool GSDevice12::CompileConvertPipelines() gpb.SetNoBlendingState(); gpb.SetVertexShader(m_convert_vs.get()); - for (ShaderConvert i = ShaderConvert::COPY; i < ShaderConvert::Count; i = static_cast(static_cast(i) + 1)) - { - const bool depth = HasDepthOutput(i); - const int index = static_cast(i); + const auto WrapEntryPointMacro = [](const std::string& s) { return fmt::format("__{}__", s); }; - switch (i) + m_convert.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS); + for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++) + { + const ShaderConvertSelector shader = ShaderConvertSelector::Get(i); + + GSTexture::Format format = shader.OutputFormat(); + DXGI_FORMAT dxgi_format; + LookupNativeFormat(format, nullptr, nullptr, &dxgi_format, nullptr); + + if (shader.DATMConvertShader() || shader.DepthOutput()) { - case ShaderConvert::RGBA8_TO_16_BITS: - case ShaderConvert::FLOAT32_TO_16_BITS: - { - gpb.SetRenderTarget(0, DXGI_FORMAT_R16_UINT); - gpb.SetDepthStencilFormat(DXGI_FORMAT_UNKNOWN); - } - break; - case ShaderConvert::FLOAT32_TO_32_BITS: - { - gpb.SetRenderTarget(0, DXGI_FORMAT_R32_UINT); - gpb.SetDepthStencilFormat(DXGI_FORMAT_UNKNOWN); - } - break; - case ShaderConvert::DATM_0: - case ShaderConvert::DATM_1: - case ShaderConvert::DATM_0_RTA_CORRECTION: - case ShaderConvert::DATM_1_RTA_CORRECTION: - { - gpb.ClearRenderTargets(); - gpb.SetDepthStencilFormat(DXGI_FORMAT_D32_FLOAT_S8X24_UINT); - } - break; - case ShaderConvert::FLOAT32_DEPTH_TO_COLOR: - { - gpb.SetRenderTarget(0, DXGI_FORMAT_R32_FLOAT); - gpb.SetDepthStencilFormat(DXGI_FORMAT_UNKNOWN); - } - break; - default: - { - depth ? gpb.ClearRenderTargets() : gpb.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM); - gpb.SetDepthStencilFormat(depth ? DXGI_FORMAT_D32_FLOAT_S8X24_UINT : DXGI_FORMAT_UNKNOWN); - } - break; + gpb.ClearRenderTargets(); + gpb.SetDepthStencilFormat(DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + } + else + { + gpb.SetRenderTarget(0, dxgi_format); + gpb.SetDepthStencilFormat(DXGI_FORMAT_UNKNOWN); } - if (IsDATMConvertShader(i)) + if (shader.DATMConvertShader()) { const D3D12_DEPTH_STENCILOP_DESC sos = { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_REPLACE, D3D12_COMPARISON_FUNC_ALWAYS}; @@ -2773,63 +2752,47 @@ bool GSDevice12::CompileConvertPipelines() } else { - gpb.SetDepthState(depth, depth, D3D12_COMPARISON_FUNC_ALWAYS); + gpb.SetDepthState(shader.DepthOutput(), shader.DepthOutput(), D3D12_COMPARISON_FUNC_ALWAYS); gpb.SetNoStencilState(); } - gpb.SetColorWriteMask(0, ShaderConvertWriteMask(i)); + gpb.SetColorWriteMask(0, shader.Mask()); - ComPtr ps(GetUtilityPixelShader(*shader, shaderName(i))); + const char* entry_point = shader.EntryPoint(); + std::string entry_point_macro = WrapEntryPointMacro(entry_point); + + ShaderMacro sm; + sm.AddMacro("PIXEL_SHADER", 1); + sm.AddMacro("HAS_BILN", static_cast(shader.Biln())); + sm.AddMacro("HAS_STENCIL_OUTPUT", static_cast(shader.StencilOutput())); + sm.AddMacro("HAS_INTEGER_OUTPUT", static_cast(shader.IntegerOutputBpp() != 0)); + sm.AddMacro("HAS_DEPTH_INPUT", 0); // unused + sm.AddMacro("HAS_DEPTH_OUTPUT", static_cast(shader.DepthOutput())); + sm.AddMacro("HAS_FLOAT32_INPUT", static_cast(shader.Float32Input())); + sm.AddMacro("HAS_FLOAT32_OUTPUT", static_cast(shader.Float32Output())); + sm.AddMacro(entry_point_macro.c_str(), 1); + + ComPtr ps(m_shader_cache.GetPixelShader(*source, sm.GetPtr(), shader.EntryPoint())); if (!ps) return false; gpb.SetPixelShader(ps.get()); - m_convert[index] = gpb.Create(m_device.get(), m_shader_cache, false); - if (!m_convert[index]) + ComPtr pipe = gpb.Create(m_device.get(), m_shader_cache, false); + + if (!pipe) return false; - D3D12::SetObjectName(m_convert[index].get(), TinyString::from_format("Convert pipeline {}", static_cast(i))); + D3D12::SetObjectName(pipe.get(), + TinyString::from_format("Convert pipeline ({}, mask={:x}, depth={}, biln={})", + shader.Name(), shader.Mask(), static_cast(shader.DepthOutput()), + static_cast(shader.Biln()))); - if (i == ShaderConvert::COPY) - { - // compile color copy pipelines - gpb.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM); - gpb.SetDepthStencilFormat(DXGI_FORMAT_UNKNOWN); - for (u32 j = 0; j < 16; j++) - { - pxAssert(!m_color_copy[j]); - gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, - D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, static_cast(j)); - m_color_copy[j] = gpb.Create(m_device.get(), m_shader_cache, false); - if (!m_color_copy[j]) - return false; + m_convert[i] = pipe; - D3D12::SetObjectName(m_color_copy[j].get(), TinyString::from_format("Color copy pipeline (r={}, g={}, b={}, a={})", - j & 1u, (j >> 1) & 1u, (j >> 2) & 1u, (j >> 3) & 1u)); - } - } - else if (i == ShaderConvert::RTA_CORRECTION) + if (shader.Shader() == ShaderConvert::COLCLIP_INIT || shader.Shader() == ShaderConvert::COLCLIP_RESOLVE) { - // compile color copy pipelines - gpb.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM); - gpb.SetDepthStencilFormat(DXGI_FORMAT_UNKNOWN); - for (u32 j = 16; j < 32; j++) - { - pxAssert(!m_color_copy[j]); - gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, - D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, static_cast(j - 16)); - m_color_copy[j] = gpb.Create(m_device.get(), m_shader_cache, false); - if (!m_color_copy[j]) - return false; - - D3D12::SetObjectName(m_color_copy[j].get(), TinyString::from_format("Color copy pipeline (r={}, g={}, b={}, a={})", - j & 1u, (j >> 1) & 1u, (j >> 2) & 1u, (j >> 3) & 1u)); - } - } - else if (i == ShaderConvert::COLCLIP_INIT || i == ShaderConvert::COLCLIP_RESOLVE) - { - const bool is_setup = i == ShaderConvert::COLCLIP_INIT; + const bool is_setup = shader.Shader() == ShaderConvert::COLCLIP_INIT; std::array, 2>& arr = is_setup ? m_colclip_setup_pipelines : m_colclip_finish_pipelines; for (u32 ds = 0; ds < 2; ds++) { @@ -2848,8 +2811,15 @@ bool GSDevice12::CompileConvertPipelines() for (u32 datm = 0; datm < 4; datm++) { - const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%d", datm)); - ComPtr ps(GetUtilityPixelShader(*shader, entry_point.c_str())); + const std::string entry_point(StringUtil::StdStringFromFormat("ps_primid_image_init_%d", datm)); + + const std::string entry_point_macro = WrapEntryPointMacro(entry_point); + + ShaderMacro sm; + sm.AddMacro("PIXEL_SHADER", "1"); + sm.AddMacro(entry_point_macro.c_str(), "1"); + + ComPtr ps(m_shader_cache.GetPixelShader(*source, sm.GetPtr(), entry_point.c_str())); if (!ps) return false; @@ -2864,11 +2834,11 @@ bool GSDevice12::CompileConvertPipelines() for (u32 ds = 0; ds < 2; ds++) { gpb.SetDepthStencilFormat(ds ? DXGI_FORMAT_D32_FLOAT_S8X24_UINT : DXGI_FORMAT_UNKNOWN); - m_date_image_setup_pipelines[ds][datm] = gpb.Create(m_device.get(), m_shader_cache, false); - if (!m_date_image_setup_pipelines[ds][datm]) + m_primid_image_setup_pipelines[ds][datm] = gpb.Create(m_device.get(), m_shader_cache, false); + if (!m_primid_image_setup_pipelines[ds][datm]) return false; - D3D12::SetObjectName(m_date_image_setup_pipelines[ds][datm].get(), + D3D12::SetObjectName(m_primid_image_setup_pipelines[ds][datm].get(), TinyString::from_format("DATE image clear pipeline (ds={}, datm={})", ds, (datm == 1 || datm == 3))); } } @@ -2903,7 +2873,7 @@ bool GSDevice12::CompilePresentPipelines() { const int index = static_cast(i); - ComPtr ps(GetUtilityPixelShader(*shader, shaderName(i))); + ComPtr ps(GetUtilityPixelShader(*shader, ShaderEntryPoint(i))); if (!ps) return false; @@ -3063,12 +3033,11 @@ void GSDevice12::DestroyResources() m_tfx_vertex_shaders.clear(); m_interlace = {}; m_merge = {}; - m_color_copy = {}; m_present = {}; - m_convert = {}; + m_convert.clear(); m_colclip_setup_pipelines = {}; m_colclip_finish_pipelines = {}; - m_date_image_setup_pipelines = {}; + m_primid_image_setup_pipelines = {}; m_fxaa_pipeline.reset(); m_shadeboost_pipeline.reset(); m_imgui_pipeline.reset(); @@ -3698,7 +3667,7 @@ void GSDevice12::RenderTextureMipmap( cmdlist.list4->RSSetScissorRects(1, &scissor); SetUtilityRootSignature(); - SetPipeline(m_convert[static_cast(ShaderConvert::COPY)].get()); + SetPipeline(GetConvertPipeline(ShaderConvert::COPY)); DrawStretchRect(GSVector4(0.0f, 0.0f, 1.0f, 1.0f), GSVector4(0.0f, 0.0f, static_cast(dst_width), static_cast(dst_height)), GSVector2i(dst_width, dst_height)); @@ -4077,7 +4046,7 @@ void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV OMSetRenderTargets(nullptr, nullptr, ds, bbox); IASetVertexBuffer(vertices, sizeof(vertices[0]), 4); SetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - SetPipeline(m_convert[SetDATMShader(datm)].get()); + SetPipeline(GetConvertPipeline(SetDATMShader(datm))); // Reference stencil value set on Create() BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, @@ -4132,7 +4101,7 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe }; SetUtilityRootSignature(); SetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - SetPipeline(m_date_image_setup_pipelines[pipe.ds][static_cast(config.datm)].get()); + SetPipeline(m_primid_image_setup_pipelines[pipe.ds][static_cast(config.datm)].get()); IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices)); if (ApplyUtilityState()) DrawPrimitive(); @@ -4225,7 +4194,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) GetLoadOpForTexture(draw_ds), draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, - draw_rt->GetUNormClearColor(), 0.0f, 0); + draw_rt->GetClearForFormat(), 0.0f, 0); const GSVector4 sRect(GSVector4(config.colclip_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy()); SetPipeline(m_colclip_finish_pipelines[pipe.ds].get()); @@ -4430,7 +4399,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) // Begin render pass if new target or out of the area. if (!InRenderPass()) { - GSVector4 clear_color = draw_rt ? draw_rt->GetUNormClearColor() : GSVector4::zero(); + GSVector4 clear_color = draw_rt ? draw_rt->GetClearForFormat() : GSVector4::zero(); if (pipe.ps.colclip_hw) { // Denormalize clear color for hw colclip. @@ -4536,7 +4505,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) GetLoadOpForTexture(draw_ds), draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, - draw_rt->GetUNormClearColor(), 0.0f, 0); + draw_rt->GetClearForFormat(), 0.0f, 0); const GSVector4 sRect(GSVector4(config.colclip_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy()); SetPipeline(m_colclip_finish_pipelines[pipe.ds].get()); diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.h b/pcsx2/GS/Renderers/DX12/GSDevice12.h index ed34b8f160..654b7f0af0 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.h +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.h @@ -346,18 +346,27 @@ private: std::unordered_map m_samplers; - std::array, static_cast(ShaderConvert::Count)> m_convert{}; + std::vector> m_convert; std::array, static_cast(PresentShader::Count)> m_present{}; - std::array, 32> m_color_copy{}; std::array, 2> m_merge{}; std::array, NUM_INTERLACE_SHADERS> m_interlace{}; std::array, 2> m_colclip_setup_pipelines{}; // [depth] std::array, 2> m_colclip_finish_pipelines{}; // [depth] - std::array, 4>, 2> m_date_image_setup_pipelines{}; // [depth][datm] + std::array, 4>, 2> m_primid_image_setup_pipelines{}; // [depth][datm] ComPtr m_fxaa_pipeline; ComPtr m_shadeboost_pipeline; ComPtr m_imgui_pipeline; + ID3D12PipelineState* GetConvertPipeline(ShaderConvertSelector shader) const + { + return m_convert[shader.Index()].get(); + } + + ID3D12PipelineState* GetConvertPipeline(ShaderConvert shader) const + { + return m_convert[ShaderConvertSelector(shader).Index()].get(); + } + std::unordered_map> m_tfx_vertex_shaders; std::unordered_map, GSHWDrawConfig::PSSelectorHash> m_tfx_pixel_shaders; @@ -431,8 +440,14 @@ private: protected: virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override; - + ShaderConvertSelector shader, bool linear) override; + virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect, + PresentShader shader, bool linear) override; + ShaderConvertSelector ProcessShaderConvertSelector(ShaderConvertSelector shader) const + { + // Depth input handled same as color input. + return shader.SetDepthInput(false); + } public: GSDevice12(); ~GSDevice12() override; @@ -486,8 +501,8 @@ public: void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override; void DrawMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; - void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvert shader); + const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override; + void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvertSelector shader); void BeginRenderPassForStretchRect( GSTexture12* dTex, const GSVector4i& dtex_rc, const GSVector4i& dst_rc, bool allow_discard = true); diff --git a/pcsx2/GS/Renderers/DX12/GSTexture12.cpp b/pcsx2/GS/Renderers/DX12/GSTexture12.cpp index a83918660d..82573684a5 100644 --- a/pcsx2/GS/Renderers/DX12/GSTexture12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSTexture12.cpp @@ -1159,7 +1159,7 @@ void GSTexture12::CommitClear(const D3D12CommandList& cmdlist) else { TransitionToState(cmdlist, ResourceState::RenderTarget); - cmdlist.list4->ClearRenderTargetView(GetWriteDescriptor(), GSVector4::unorm8(m_clear_value.color).v, 0, nullptr); + cmdlist.list4->ClearRenderTargetView(GetWriteDescriptor(), GetClearForFormat().v, 0, nullptr); } SetState(GSTexture::State::Dirty); diff --git a/pcsx2/GS/Renderers/HW/GSHwHack.cpp b/pcsx2/GS/Renderers/HW/GSHwHack.cpp index 73b25c8950..fa9582ad9c 100644 --- a/pcsx2/GS/Renderers/HW/GSHwHack.cpp +++ b/pcsx2/GS/Renderers/HW/GSHwHack.cpp @@ -1135,14 +1135,14 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds, rt_again->m_valid.y /= 2; rt_again->m_valid.w /= 2; rt_again->m_TEX0.PSM = PSMCT32; - GSTexture* tex = g_gs_device->CreateRenderTarget(rt_again->m_unscaled_size.x * rt_again->m_scale, rt_again->m_unscaled_size.y * rt_again->m_scale, GSTexture::Format::Color, false); + GSTexture* tex = g_gs_device->CreateRenderTarget( + rt_again->m_unscaled_size.x * rt_again->m_scale, rt_again->m_unscaled_size.y * rt_again->m_scale, + GSTexture::Format::Color, false); if (!tex) return false; - - g_gs_device->StretchRect(rt_again->m_texture, source_rect, tex, dRect, ShaderConvert::COPY, false); - + g_gs_device->StretchRectAutoNearest(rt_again->m_texture, source_rect, tex, dRect); g_gs_device->Recycle(rt_again->m_texture); rt_again->m_texture = tex; @@ -1172,7 +1172,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds, // This is kind of a bodge because the game confuses everything since the source is really 16bit and it assumes it's really drawing 16bit on the copy back, resizing the target. const GSVector4 dRect(0, 0, copy_size.x, copy_size.y); - g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false); + g_gs_device->StretchRectAutoMask(src->m_texture, sRect, rt, dRect, true, true, true, false); return false; } @@ -1358,8 +1358,9 @@ bool GSHwHack::MV_Growlanser(GSRendererHW& r) GL_INS("MV_Growlanser: %x -> %x %dx%d", RSBP, RDBP, src->GetUnscaledWidth(), src->GetUnscaledHeight()); - g_gs_device->StretchRect(src->GetTexture(), GSVector4(rc) / GSVector4(src->GetUnscaledSize()).xyxy(), - dst->GetTexture(), GSVector4(rc) * GSVector4(dst->GetScale()), ShaderConvert::RGBA8_TO_FLOAT32, false); + g_gs_device->StretchRectAutoNearest( + src->GetTexture(), GSVector4(rc) / GSVector4(src->GetUnscaledSize()).xyxy(), + dst->GetTexture(), GSVector4(rc) * GSVector4(dst->GetScale())); s_last_hacked_move_n = r.s_n; return true; diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 30088ef96a..e725ea7a28 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -3016,8 +3016,11 @@ void GSRendererHW::Draw() { GL_CACHE("HW: Pre-draw resolve of colclip! Address: %x", FRAME.TBP0); GSTexture* colclip_texture = g_gs_device->GetColorClipTexture(); - g_gs_device->StretchRect(colclip_texture, GSVector4(m_conf.colclip_update_area) / GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()), old_rt->m_texture, GSVector4(m_conf.colclip_update_area), - ShaderConvert::COLCLIP_RESOLVE, false); + const GSVector4 colclip_texture_dims = GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()); + g_gs_device->StretchRectNearest( + colclip_texture, GSVector4(m_conf.colclip_update_area) / colclip_texture_dims, + old_rt->m_texture, GSVector4(m_conf.colclip_update_area), + ShaderConvert::COLCLIP_RESOLVE); g_gs_device->Recycle(colclip_texture); @@ -4218,7 +4221,7 @@ void GSRendererHW::Draw() static_cast((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast(g_texture_cache->GetTemporaryZ()->GetHeight())); GL_CACHE("HW: RT in RT Z copy back draw %lld z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset); - g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect)); } g_texture_cache->InvalidateTemporaryZ(); @@ -4234,7 +4237,7 @@ void GSRendererHW::Draw() sRect = sRect.min(GSVector4(1.0f)); dRect = dRect.min_u32(GSVector4i(ds->m_unscaled_size.x * ds->m_scale, ds->m_unscaled_size.y * ds->m_scale).xyxy()); - g_gs_device->StretchRect(ds->m_texture, sRect, g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(ds->m_texture, sRect, g_texture_cache->GetTemporaryZ(), GSVector4(dRect)); z_address_info.rect_since = GSVector4i::zero(); g_texture_cache->SetTemporaryZInfo(z_address_info); } @@ -4260,7 +4263,7 @@ void GSRendererHW::Draw() const int new_height = std::min(2048, std::max(t_size.y, static_cast(vertical_size))) * ds->m_scale; const int new_width = std::min(2048, std::max(t_size.x, static_cast(horizontal_size))) * ds->m_scale; - if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_width, new_height, GSTexture::Format::DepthStencil, true)) + if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_width, new_height, true)) { GSVector4 sRect = GSVector4(static_cast(z_horizontal_offset) / static_cast(ds->m_unscaled_size.x), static_cast(z_vertical_offset) / static_cast(ds->m_unscaled_size.y), 1.0f , 1.0f); @@ -4281,7 +4284,7 @@ void GSRendererHW::Draw() if (m_cached_ctx.TEST.ZTST > ZTST_ALWAYS || !dRect.rintersect(GSVector4i(GSVector4(m_r) * ds->m_scale)).eq(dRect)) { - g_gs_device->StretchRect(ds->m_texture, sRect, tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(ds->m_texture, sRect, tex, GSVector4(dRect)); } g_texture_cache->SetTemporaryZ(tex); g_texture_cache->SetTemporaryZInfo(ds->m_TEX0.TBP0, page_offset, rt_page_offset); @@ -4869,10 +4872,9 @@ void GSRendererHW::Draw() if (z_width != new_w || z_height != new_h) { - if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_w * ds->m_scale, new_h * ds->m_scale, GSTexture::Format::DepthStencil, true)) + if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_w * ds->m_scale, new_h * ds->m_scale, true)) { - const GSVector4i dRect = GSVector4i(0, 0, g_texture_cache->GetTemporaryZ()->GetWidth(), g_texture_cache->GetTemporaryZ()->GetHeight()); - g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), GSVector4(0.0f, 0.0f, 1.0f, 1.0f), tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(g_texture_cache->GetTemporaryZ(), tex); g_texture_cache->InvalidateTemporaryZ(); g_texture_cache->SetTemporaryZ(tex); } @@ -5178,7 +5180,7 @@ void GSRendererHW::Draw() static_cast((real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast(g_texture_cache->GetTemporaryZ()->GetHeight())); GL_CACHE("HW: RT in RT Z copy back draw %lld z_vert_offset %d rt_vert_offset %d z_horz_offset %d rt_horz_offset %d", s_n, z_vertical_offset, vertical_offset, z_horizontal_offset, horizontal_offset); - g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect)); } else if (m_temp_z_full_copy) { @@ -5190,7 +5192,7 @@ void GSRendererHW::Draw() static_cast((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast(g_texture_cache->GetTemporaryZ()->GetHeight())); GL_CACHE("HW: RT in RT Z copy back draw %lld z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset); - g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect)); } m_temp_z_full_copy = false; @@ -5219,8 +5221,11 @@ void GSRendererHW::Draw() if (writeback_colclip_texture) { GSTexture* colclip_texture = g_gs_device->GetColorClipTexture(); - g_gs_device->StretchRect(colclip_texture, GSVector4(m_conf.colclip_update_area) / GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.colclip_update_area), - ShaderConvert::COLCLIP_RESOLVE, false); + const GSVector4 colclip_texture_dims = GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()); + g_gs_device->StretchRectNearest( + colclip_texture, GSVector4(m_conf.colclip_update_area) / colclip_texture_dims, + rt->m_texture, GSVector4(m_conf.colclip_update_area), + ShaderConvert::COLCLIP_RESOLVE); } const u64 frame = g_perfmon.GetFrame(); @@ -6032,8 +6037,7 @@ void GSRendererHW::EmulateDATEGetConfig(DATEOptions& date_options, bool scale_rt if (date_stencil_needs_ds) { const bool need_barrier = m_conf.require_one_barrier || (m_conf.require_full_barrier && features.feedback_loops()); - if ((temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(), - GSTexture::Format::DepthStencil, false)), temp_ds)) + if ((temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(), false)), temp_ds)) { m_conf.ds = temp_ds.get(); } @@ -6425,7 +6429,7 @@ bool GSRendererHW::TestChannelShuffle(GSTextureCache::Target* src) __ri u32 GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt) { - if (src && (src->m_texture->GetType() == GSTexture::Type::DepthStencil) && !src->m_32_bits_fmt) + if (src && src->m_texture->IsDepthLike() && !src->m_32_bits_fmt) { // So far 2 games hit this code path. Urban Chaos and Tales of Abyss // UC: will copy depth to green channel @@ -6999,8 +7003,11 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio if (colclip_texture->GetSize() != rt->m_texture->GetSize()) { GL_CACHE("HW: Pre-Blend resolve of colclip due to size change! Address: %x", rt->m_TEX0.TBP0); - g_gs_device->StretchRect(colclip_texture, GSVector4(m_conf.colclip_update_area) / GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.colclip_update_area), - ShaderConvert::COLCLIP_RESOLVE, false); + const GSVector4 colclip_texture_dims = GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()); + g_gs_device->StretchRectNearest( + colclip_texture, GSVector4(m_conf.colclip_update_area) / colclip_texture_dims, + rt->m_texture, GSVector4(m_conf.colclip_update_area), + ShaderConvert::COLCLIP_RESOLVE); g_gs_device->Recycle(colclip_texture); @@ -7586,7 +7593,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, // Depth + bilinear filtering isn't done yet. But if the game has just set a Z24 swizzle on a colour texture, we can // just pretend it's not a depth format, since in the texture cache, it's not. // Other games worth testing: Area 51, Burnout - if (psm.depth && m_vt.IsLinear() && tex->GetTexture()->IsDepthStencil()) + if (psm.depth && m_vt.IsLinear() && tex->GetTexture()->IsDepthLike()) GL_INS("HW: WARNING: Depth + bilinear filtering not supported"); // Performance note: @@ -7605,7 +7612,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, // Require a float conversion if the texure is a depth otherwise uses Integral scaling if (psm.depth) { - m_conf.ps.depth_fmt = (tex->m_texture->GetType() != GSTexture::Type::DepthStencil) ? 3 : tex->m_32_bits_fmt ? 1 : 2; + m_conf.ps.depth_fmt = !tex->m_texture->IsDepthLike() ? 3 : tex->m_32_bits_fmt ? 1 : 2; } // Shuffle is a 16 bits format, so aem is always required @@ -7685,7 +7692,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, } // Depth format - if (tex->m_texture->IsDepthStencil()) + if (tex->m_texture->IsDepthLike()) { // Require a float conversion if the texure is a depth format m_conf.ps.depth_fmt = (psm.bpp == 16) ? 2 : 1; @@ -8044,7 +8051,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c // Shuffles take the whole target. This should've already been halved. // We can't partially copy depth targets in DirectX, and GL/Vulkan should use the direct read above. // Restricting it also breaks Tom and Jerry... - if (m_downscale_source || m_channel_shuffle || tex->m_texture->GetType() == GSTexture::Type::DepthStencil) + if (m_downscale_source || m_channel_shuffle || tex->m_texture->IsDepthLike()) { if (m_channel_shuffle) { @@ -8192,10 +8199,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c const GSVector2i scaled_copy_size = GSVector2i(static_cast(std::ceil(static_cast(copy_size.x) * scale)), static_cast(std::ceil(static_cast(copy_size.y) * scale))); - - src_copy.reset(src_target->m_texture->IsDepthStencil() ? - g_gs_device->CreateDepthStencil(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) : - g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, true)); + const bool clear = src_target->m_texture->IsRenderTarget(); + src_copy.reset(g_gs_device->CreateCompatible(src_target->m_texture, scaled_copy_size, clear)); if (!src_copy) [[unlikely]] { Console.Error("HW: Failed to allocate %dx%d texture for hazard copy", scaled_copy_size.x, scaled_copy_size.y); @@ -8211,8 +8216,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c { GSVector4 src_rect = GSVector4(tmm.coverage) / GSVector4(GSVector4i::loadh(src_unscaled_size).zwzw()); const GSVector4 dst_rect = GSVector4(tmm.coverage); - g_gs_device->StretchRect(src_target->m_texture, src_rect, src_copy.get(), dst_rect, - src_target->m_texture->IsDepthStencil() ? ShaderConvert::DEPTH_COPY : ShaderConvert::COPY, false); + g_gs_device->StretchRectAutoNearest(src_target->m_texture, src_rect, src_copy.get(), dst_rect); } else { @@ -8244,8 +8248,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c const GSVector4 src_rect = GSVector4(copy_range) / GSVector4(src_unscaled_size).xyxy(); const GSVector4 dst_rect = (GSVector4(copy_range) - GSVector4(offset).xyxy()) * scale; - g_gs_device->StretchRect(src_target->m_texture, src_rect, src_copy.get(), dst_rect, - src_target->m_texture->IsDepthStencil() ? ShaderConvert::DEPTH_COPY : ShaderConvert::COPY, false); + g_gs_device->StretchRectAutoNearest(src_target->m_texture, src_rect, src_copy.get(), dst_rect); } m_conf.tex = src_copy.get(); } @@ -10116,7 +10119,7 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc th = new_height; const GSVector4 sRect(m_vt.m_min.t.x / tw, m_vt.m_min.t.y / th, m_vt.m_max.t.x / tw, m_vt.m_max.t.y / th); const GSVector4i r_full_new(0, 0, tw, th); - g_gs_device->StretchRect(tex->m_texture, sRect, rt, dRect, ShaderConvert::COPY, m_vt.IsRealLinear()); + g_gs_device->StretchRectAuto(tex->m_texture, sRect, rt, dRect, m_vt.IsRealLinear()); g_gs_device->CopyRect(rt, tex->m_texture, r_full_new, 0, 0); g_gs_device->Recycle(rt); } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index ab7bbdbc0f..3983d03b57 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -2369,14 +2369,14 @@ void GSTextureCache::CombineAlignedInsideTargets(Target* target, GSTextureCache: if (target->m_type == RenderTarget) { - g_gs_device->StretchRect(t->m_texture, source_rect, target->m_texture, - target_drect, valid_color, valid_color, valid_color, valid_alpha, ShaderConvert::COPY); + g_gs_device->StretchRectAutoMask(t->m_texture, source_rect, target->m_texture, + target_drect, valid_color, valid_color, valid_color, valid_alpha); } else { if (!valid_color || (!valid_alpha && (GSUtil::GetChannelMask(t->m_TEX0.PSM) & 0x8))) GL_CACHE("Warning: CombineAlignedInsideTargets: Depth copy with invalid lower 24 bits or invalid upper 8 bits."); - g_gs_device->StretchRect(t->m_texture, source_rect, target->m_texture, target_drect, ShaderConvert::DEPTH_COPY); + g_gs_device->StretchRectAutoNearest(t->m_texture, source_rect, target->m_texture, target_drect); } target->m_valid_rgb |= t->m_valid_rgb; @@ -2865,27 +2865,29 @@ GSTextureCache::Target* GSTextureCache::LookupDrawTarget(GIFRegTEX0 TEX0, const dst->UpdateValidity(dst->m_valid); } - ShaderConvert shader; // m_32_bits_fmt gets set on a shuffle or if the format isn't 16bit. // In this case it needs to make sure it isn't part of a shuffle, where it needs to be interpreted as 32bits. const bool fmt_16_bits = (psm_s.bpp == 16 && GSLocalMemory::m_psm[dst_match->m_TEX0.PSM].bpp == 16 && !dst->m_32_bits_fmt); + + u32 src_bpp = fmt_16_bits ? 16 : 32; + + u32 dst_bpp; + if (type == DepthStencil) { GL_CACHE("TC: Lookup Target(Depth) %dx%d, hit Color (0x%x, TBW %d, %s was %s)", rescaler.m_new_size.x, rescaler.m_new_size.y, bp, TEX0.TBW, GSUtil::GetPSMName(TEX0.PSM), GSUtil::GetPSMName(dst_match->m_TEX0.PSM)); - shader = (fmt_16_bits) ? ShaderConvert::RGB5A1_TO_FLOAT16 : - (ShaderConvert)(static_cast(ShaderConvert::RGBA8_TO_FLOAT32) + psm_s.fmt); + dst_bpp = fmt_16_bits ? 16 : psm_s.trbpp; } else { GL_CACHE("TC: Lookup Target(Color) %dx%d, hit Depth (0x%x, TBW %d, FBMSK %0x, %s was %s)", rescaler.m_new_size.x, rescaler.m_new_size.y, bp, TEX0.TBW, fbmask, GSUtil::GetPSMName(TEX0.PSM), GSUtil::GetPSMName(dst_match->m_TEX0.PSM)); - shader = (fmt_16_bits) ? ShaderConvert::FLOAT16_TO_RGB5A1 : ShaderConvert::FLOAT32_TO_RGBA8; + dst_bpp = fmt_16_bits ? 16 : 32; } - if (!preserve_target) { GL_INS("TC: Not converting existing %s[%x] because it's fully overwritten.", to_string(!type), dst->m_TEX0.TBP0); @@ -2912,14 +2914,14 @@ GSTextureCache::Target* GSTextureCache::LookupDrawTarget(GIFRegTEX0 TEX0, const if (type == DepthStencil) { const u32 cc = dst_match->m_texture->GetClearColor(); - const float cd = ConvertColorToDepth(cc, shader); + const float cd = ConvertColorToDepth(cc, src_bpp, dst_bpp); GL_INS("TC: Convert clear color[%08X] to depth[%f]", cc, cd); g_gs_device->ClearDepth(dst->m_texture, cd); } else { const float cd = dst_match->m_texture->GetClearDepth(); - const u32 cc = ConvertDepthToColor(cd, shader); + const u32 cc = ConvertDepthToColor(cd, dst_bpp); GL_INS("TC: Convert clear depth[%f] to color[%08X]", cd, cc); g_gs_device->ClearRenderTarget(dst->m_texture, cc); } @@ -2927,7 +2929,8 @@ GSTextureCache::Target* GSTextureCache::LookupDrawTarget(GIFRegTEX0 TEX0, const else if (dst_match->m_texture->GetState() == GSTexture::State::Dirty) { dst_match->UnscaleRTAlpha(); - g_gs_device->StretchRect(dst_match->m_texture, FullSrcRect, dst->m_texture, rescaler.m_dRect, shader, false); + g_gs_device->StretchRectAutoNearest(dst_match->m_texture, FullSrcRect, dst->m_texture, + rescaler.m_dRect, src_bpp, dst_bpp); } } @@ -2973,9 +2976,7 @@ GSTextureCache::Target* GSTextureCache::ProcessTargetAfterLookup(RescaleHelper& if (dst->m_scale != rescaler.m_scale && (!preserve_scale || (type == RenderTarget && (is_shuffle || !dst->m_downscaled || TEX0.TBW != dst->m_TEX0.TBW)))) { rescaler.CalcRescale(dst); - GSTexture* tex = type == RenderTarget ? - g_gs_device->CreateRenderTarget(rescaler.m_new_scaled_size.x, rescaler.m_new_scaled_size.y, GSTexture::Format::Color, rescaler.m_clear) : - g_gs_device->CreateDepthStencil(rescaler.m_new_scaled_size.x, rescaler.m_new_scaled_size.y, GSTexture::Format::DepthStencil, rescaler.m_clear); + GSTexture* tex = g_gs_device->CreateCompatible(dst->m_texture, rescaler.m_new_scaled_size, rescaler.m_clear); if (!tex) return nullptr; @@ -2993,8 +2994,10 @@ GSTextureCache::Target* GSTextureCache::ProcessTargetAfterLookup(RescaleHelper& g_gs_device->FilteredDownsampleTexture(dst->m_texture, tex, downsample_factor, clamp_min, dRect); } else - g_gs_device->StretchRect(dst->m_texture, FullSrcRect, tex, rescaler.m_dRect, - (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, type == RenderTarget && !preserve_scale); + { + g_gs_device->StretchRectAuto(dst->m_texture, FullSrcRect, tex, rescaler.m_dRect, + type == RenderTarget && !preserve_scale); + } m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage(); @@ -3023,10 +3026,10 @@ GSTextureCache::Target* GSTextureCache::ProcessTargetAfterLookup(RescaleHelper& if (type == DepthStencil && dst->m_type == DepthStencil && GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32 && GSLocalMemory::m_psm[TEX0.PSM].trbpp == 24 && dst->m_alpha_max > 0) { rescaler.CalcRescale(dst); - GSTexture* tex = g_gs_device->CreateDepthStencil(rescaler.m_new_scaled_size.x, rescaler.m_new_scaled_size.y, GSTexture::Format::DepthStencil, false); + GSTexture* tex = g_gs_device->CreateCompatible(dst->m_texture, rescaler.m_new_scaled_size, false); if (!tex) return nullptr; - g_gs_device->StretchRect(dst->m_texture, FullSrcRect, tex, rescaler.m_dRect, ShaderConvert::FLOAT32_TO_FLOAT24, false); + g_gs_device->StretchRectAutoNearest(dst->m_texture, FullSrcRect, tex, rescaler.m_dRect, 32, 24); g_gs_device->Recycle(dst->m_texture); dst->m_texture = tex; @@ -3091,13 +3094,11 @@ GSTextureCache::Target* GSTextureCache::ProcessTargetAfterLookup(RescaleHelper& dst->ResizeTexture(rescaler.m_new_size.x, rescaler.m_new_size.y, true, true, GSVector4i(rescaler.m_dRect), true); else { - GSTexture* tex = type == RenderTarget ? - g_gs_device->CreateRenderTarget(rescaler.m_new_scaled_size.x, rescaler.m_new_scaled_size.y, GSTexture::Format::Color, rescaler.m_clear) : - g_gs_device->CreateDepthStencil(rescaler.m_new_scaled_size.x, rescaler.m_new_scaled_size.y, GSTexture::Format::DepthStencil, rescaler.m_clear); + GSTexture* tex = g_gs_device->CreateCompatible(dst->m_texture, rescaler.m_new_scaled_size, rescaler.m_clear); if (!tex) return nullptr; - g_gs_device->StretchRect(dst->m_texture, source_rect, tex, rescaler.m_dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(dst->m_texture, source_rect, tex, rescaler.m_dRect); m_target_memory_usage = m_target_memory_usage + tex->GetMemUsage(); @@ -3112,16 +3113,11 @@ GSTextureCache::Target* GSTextureCache::ProcessTargetAfterLookup(RescaleHelper& dst->ResizeTexture(rescaler.m_new_size.x, rescaler.m_new_size.y, true, true, GSVector4i(rescaler.m_dRect)); else { - GSTexture* tex = type == RenderTarget ? - g_gs_device->CreateRenderTarget(rescaler.m_new_scaled_size.x, rescaler.m_new_scaled_size.y, GSTexture::Format::Color, rescaler.m_clear) : - g_gs_device->CreateDepthStencil(rescaler.m_new_scaled_size.x, rescaler.m_new_scaled_size.y, GSTexture::Format::DepthStencil, rescaler.m_clear); + GSTexture* tex = g_gs_device->CreateCompatible(dst->m_texture, rescaler.m_new_scaled_size, rescaler.m_clear); if (!tex) return nullptr; - if (scale_down) - g_gs_device->StretchRect(dst->m_texture, source_rect, tex, rescaler.m_dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false); - else - g_gs_device->StretchRect(dst->m_texture, source_rect, tex, rescaler.m_dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(dst->m_texture, source_rect, tex, rescaler.m_dRect); m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage(); @@ -3199,12 +3195,9 @@ GSTextureCache::Target* GSTextureCache::ProcessTargetAfterLookup(RescaleHelper& return nullptr; } - const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 : - (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 : - ShaderConvert::RGBA8_TO_FLOAT24; - - g_gs_device->StretchRect(dst_match->m_texture, GSVector4(0, 0, 1, 1), - dst->m_texture, GSVector4(dst->GetUnscaledRect()) * GSVector4(dst->GetScale()), shader, false); + g_gs_device->StretchRectAutoNearest(dst_match->m_texture, GSVector4(0, 0, 1, 1), + dst->m_texture, GSVector4(dst->GetUnscaledRect()) * GSVector4(dst->GetScale()), + 32, GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp); dst_match->m_valid_rgb = !used; dst_match->m_was_dst_matched = true; @@ -3222,16 +3215,14 @@ GSTextureCache::Target* GSTextureCache::ProcessTargetAfterLookup(RescaleHelper& // We couldn't get RGB from any depth targets. So clear and preload. // Unfortunately, we still have an alpha channel to preserve, and we can't clear RGB... // So, create a new target, clear/preload it, and copy RGB in. - GSTexture* tex = (type == RenderTarget) ? - g_gs_device->CreateRenderTarget(dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), GSTexture::Format::Color, true) : - g_gs_device->CreateDepthStencil(dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true); + GSTexture* tex = g_gs_device->CreateCompatible(dst->m_texture, true); if (!tex) return nullptr; std::swap(dst->m_texture, tex); PreloadTarget(TEX0, size, GSVector2i(dst->m_valid.z, dst->m_valid.w), is_frame, preload, preserve_target, draw_rect, dst, src); - g_gs_device->StretchRect(tex, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), dst->m_texture, + g_gs_device->StretchRectAutoMask(tex, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), dst->m_texture, GSVector4(dst->m_texture->GetRect()), false, false, false, true); g_gs_device->Recycle(tex); dst->m_valid_rgb = true; @@ -3398,7 +3389,6 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe return dst; } -// For preload data from GS memory and/or other targets when creating a new target. bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame, bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src) { @@ -3754,7 +3744,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons { const GSVector4 src_rect = GSVector4(0, 0, copy_width, copy_height) / (GSVector4(old_dst->m_texture->GetSize()).xyxy()); const GSVector4 dst_rect = GSVector4(dst_offset_scaled_width, dst_offset_scaled_height, dst_offset_scaled_width + copy_width, dst_offset_scaled_height + copy_height); - g_gs_device->StretchRect(old_dst->m_texture, src_rect, dst->m_texture, dst_rect, old_dst->m_valid_rgb, old_dst->m_valid_rgb, old_dst->m_valid_rgb, old_dst->m_valid_alpha_high || old_dst->m_valid_alpha_low); + g_gs_device->StretchRectAutoMask(old_dst->m_texture, src_rect, dst->m_texture, dst_rect, old_dst->m_valid_rgb, old_dst->m_valid_rgb, old_dst->m_valid_rgb, old_dst->m_valid_alpha_high || old_dst->m_valid_alpha_low); } else { @@ -3817,12 +3807,10 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons dst->ResizeTexture(old_dst->m_unscaled_size.x, old_dst->m_unscaled_size.y); - const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 : - (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 : - ShaderConvert::RGBA8_TO_FLOAT24; - - g_gs_device->StretchRect(old_dst->m_texture, GSVector4(0, 0, 1, 1), - dst->m_texture, GSVector4(old_dst->GetUnscaledRect()) * GSVector4(dst->GetScale()), shader, false); + const u32 dst_bpp = GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp; + const u32 src_bpp = (dst_bpp == 16) ? 16 : 32; + g_gs_device->StretchRectAutoNearest(old_dst->m_texture, GSVector4(0, 0, 1, 1), + dst->m_texture, GSVector4(old_dst->GetUnscaledRect()) * GSVector4(dst->GetScale()), src_bpp, dst_bpp); break; } @@ -3857,10 +3845,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons if (!old_dst->m_valid.rempty()) { delete_target = false; - GSTexture* tex = (old_dst->m_type == RenderTarget) ? - g_gs_device->CreateRenderTarget(old_dst->m_texture->GetWidth(), old_dst->m_texture->GetHeight(), GSTexture::Format::Color, true) : - g_gs_device->CreateDepthStencil(old_dst->m_texture->GetWidth(), old_dst->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true); - if (tex) + if (GSTexture* tex = g_gs_device->CreateCompatible(old_dst->m_texture, true)) { g_gs_device->CopyRect(old_dst->m_texture, tex, GSVector4i(0, height_adjust * old_dst->m_scale, old_dst->m_texture->GetWidth(), old_dst->m_texture->GetHeight()), 0, 0); if (src && src->m_target && src->m_from_target == old_dst) @@ -4160,12 +4145,12 @@ void GSTextureCache::Target::ScaleRTAlpha() const GSVector4i valid_rect = GSVector4i(GSVector4(m_valid) * GSVector4(m_scale)); GL_PUSH("TC: ScaleRTAlpha(valid=(%dx%d %d,%d=>%d,%d))", m_valid.width(), m_valid.height(), m_valid.x, m_valid.y, m_valid.z, m_valid.w); - if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::Color, !GSVector4i::loadh(rtsize).eq(valid_rect))) + if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize, GSTexture::Format::Color, !GSVector4i::loadh(rtsize).eq(valid_rect))) { // Only copy up the valid area, since there's no point in "correcting" nothing. const GSVector4 dRect(m_texture->GetRect().rintersect(valid_rect)); const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy(); - g_gs_device->StretchRect(m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_CORRECTION, false); + g_gs_device->StretchRectNearest(m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_CORRECTION); g_gs_device->Recycle(m_texture); m_texture = temp_rt; } @@ -4185,12 +4170,12 @@ void GSTextureCache::Target::UnscaleRTAlpha() const GSVector4i valid_rect = GSVector4i(GSVector4(m_valid) * GSVector4(m_scale)); GL_PUSH("TC: UnscaleRTAlpha(valid=(%dx%d %d,%d=>%d,%d))", valid_rect.width(), valid_rect.height(), valid_rect.x, valid_rect.y, valid_rect.z, valid_rect.w); - if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::Color, !GSVector4i::loadh(rtsize).eq(valid_rect))) + if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize, GSTexture::Format::Color, !GSVector4i::loadh(rtsize).eq(valid_rect))) { // Only copy up the valid area, since there's no point in "correcting" nothing. const GSVector4 dRect(m_texture->GetRect().rintersect(valid_rect)); const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy(); - g_gs_device->StretchRect(m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_DECORRECTION, false); + g_gs_device->StretchRectNearest(m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_DECORRECTION); g_gs_device->Recycle(m_texture); m_texture = temp_rt; } @@ -4249,7 +4234,7 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, t->m_unscaled_size.y, t->m_TEX0.TBP0, real_h, dispfb.TBP0, y_offset, needed_height); // Fill the new texture with the old data, and discard the old texture. - g_gs_device->StretchRect(old_texture, new_texture, GSVector4(old_texture->GetSize()).zwxy(), ShaderConvert::COPY, false); + g_gs_device->StretchRectAutoNearest(old_texture, new_texture, GSVector4(old_texture->GetSize()).zwxy()); m_target_memory_usage = (m_target_memory_usage - old_texture->GetMemUsage()) + new_texture->GetMemUsage(); g_gs_device->Recycle(old_texture); t->m_texture = new_texture; @@ -4284,47 +4269,52 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, GetTargetSize(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, new_width, static_cast(needed_height)); } -float GSTextureCache::ConvertColorToDepth(u32 c, ShaderConvert convert) +float GSTextureCache::ConvertColorToDepth(u32 c, u32 src_bpp, u32 dst_bpp) { const float mult = std::exp2(-32.0f); - switch (convert) + switch (dst_bpp) { - case ShaderConvert::RGB5A1_TO_FLOAT16: - return static_cast(((c & 0xF8u) >> 3) | (((c >> 8) & 0xF8u) << 2) | (((c >> 16) & 0xF8u) << 7) | - (((c >> 24) & 0x80u) << 8)) * - mult; + case 32: + default: + pxAssert(src_bpp == 32); + return static_cast(c) * mult; - case ShaderConvert::RGBA8_TO_FLOAT16: - return static_cast(c & 0x0000FFFF) * mult; - - case ShaderConvert::RGBA8_TO_FLOAT24: + case 24: + pxAssert(src_bpp == 32); return static_cast(c & 0x00FFFFFF) * mult; - case ShaderConvert::RGBA8_TO_FLOAT32: - default: - return static_cast(c) * mult; + case 16: + pxAssert(src_bpp == 16 || src_bpp == 32); + if (src_bpp == 16) + { + const u32 r = (c >> 3) & 0x001Fu; + const u32 g = (c >> 6) & 0x03E0u; + const u32 b = (c >> 9) & 0x7C00u; + const u32 a = (c >> 16) & 0x8000u; + return static_cast(r | g | b | a) * mult; + } + else + { + return static_cast(c & 0x0000ffff) * mult; + } } } -u32 GSTextureCache::ConvertDepthToColor(float d, ShaderConvert convert) +u32 GSTextureCache::ConvertDepthToColor(float d, u32 dst_bpp) { - const float mult = std::exp2(32.0f); - switch (convert) + pxAssert(dst_bpp == 32 || dst_bpp == 16); + const u32 cc = static_cast(d * 0x1p32); + if (dst_bpp == 16) { - case ShaderConvert::FLOAT16_TO_RGB5A1: - { - const u32 cc = static_cast(d * mult); - - // Truely awful. - const GSVector4i vcc = GSVector4i( - GSVector4(GSVector4i(cc & 0x1Fu, (cc >> 5) & 0x1Fu, (cc >> 10) & 0x1Fu, (cc >> 15) & 0x01u)) * - GSVector4::cxpr(255.0f / 31.0f)); - return (vcc.r | (vcc.g << 8) | (vcc.b << 16) | (vcc.a << 24)); - } - - case ShaderConvert::FLOAT32_TO_RGBA8: - default: - return static_cast(d * mult); + const u32 r = (cc << 3) & 0x000000FF; + const u32 g = (cc << 6) & 0x0000F800; + const u32 b = (cc << 9) & 0x00F80000; + const u32 a = (cc << 16) & 0x80000000; + return r | g | b | a; + } + else + { + return cc; } } @@ -4342,7 +4332,7 @@ bool GSTextureCache::CopyRGBFromDepthToColor(Target* dst, Target* depth_src) GSTexture* tex = dst->m_texture; if (needs_new_tex) { - tex = g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, + tex = g_gs_device->CreateRenderTarget(new_scaled_size, GSTexture::Format::Color, new_size != dst->m_unscaled_size || new_size != depth_src->m_unscaled_size); if (!tex) return false; @@ -4373,16 +4363,17 @@ bool GSTextureCache::CopyRGBFromDepthToColor(Target* dst, Target* depth_src) // Depth source should be up to date. depth_src->Update(); - constexpr ShaderConvert shader = ShaderConvert::FLOAT32_TO_RGB8; if (depth_src->m_texture->GetState() == GSTexture::State::Cleared) { - g_gs_device->ClearRenderTarget(tex, ConvertDepthToColor(depth_src->m_texture->GetClearDepth(), shader)); + g_gs_device->ClearRenderTarget(tex, ConvertDepthToColor(depth_src->m_texture->GetClearDepth(), 32)); } else if (depth_src->m_texture->GetState() != GSTexture::State::Invalidated) { const GSVector4 convert_rect = GSVector4(depth_src->GetUnscaledRect().rintersect(GSVector4i::loadh(new_size))); - g_gs_device->StretchRect(depth_src->m_texture, convert_rect / GSVector4(depth_src->GetUnscaledSize()).xyxy(), - tex, convert_rect * GSVector4(dst->GetScale()), shader, false); + // Update RGB bits only. + g_gs_device->StretchRectAutoNearest( + depth_src->m_texture, convert_rect / GSVector4(depth_src->GetUnscaledSize()).xyxy(), + tex, convert_rect * GSVector4(dst->GetScale()), 32, 24); } // Copy in alpha if we're a new texture. @@ -4391,8 +4382,9 @@ bool GSTextureCache::CopyRGBFromDepthToColor(Target* dst, Target* depth_src) if (dst->m_valid_alpha_low || dst->m_valid_alpha_high) { const GSVector4 copy_rect = GSVector4(tex->GetRect().rintersect(dst->m_texture->GetRect())); - g_gs_device->StretchRect(dst->m_texture, copy_rect / GSVector4(GSVector4i(dst->m_texture->GetSize()).xyxy()), tex, - copy_rect, false, false, false, true); + const GSVector4 dst_dims = GSVector4(GSVector4i(dst->m_texture->GetSize()).xyxy()); + g_gs_device->StretchRectAutoMask(dst->m_texture, copy_rect / dst_dims, + tex, copy_rect, false, false, false, true); } g_gs_device->Recycle(dst->m_texture); @@ -5416,22 +5408,20 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u const bool renderer_is_directx = (renderer == GSRendererType::DX11 || renderer == GSRendererType::DX12); if (SBP == DBP && (!(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h))).rempty() || renderer_is_directx)) { - GSTexture* tmp_texture = src->m_texture->IsDepthStencil() ? - g_gs_device->CreateDepthStencil(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false) : - g_gs_device->CreateRenderTarget(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false); + GSTexture* tmp_texture = g_gs_device->CreateCompatible(src->m_texture, false); if (!tmp_texture) { Console.Error("(HW Move) Failed to allocate temporary %dx%d texture on HW move", w, h); return false; } - if (tmp_texture->IsDepthStencil()) + if (tmp_texture->IsDepthLike()) { const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h); const GSVector4 tmp_rect = src_rect / (GSVector4(tmp_texture->GetSize()).xyxy()); const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h)); - g_gs_device->StretchRect(src->m_texture, tmp_rect, tmp_texture, src_rect, ShaderConvert::DEPTH_COPY, false); - g_gs_device->StretchRect(tmp_texture, tmp_rect, dst->m_texture, dst_rect, ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(src->m_texture, tmp_rect, tmp_texture, src_rect); + g_gs_device->StretchRectAutoNearest(tmp_texture, tmp_rect, dst->m_texture, dst_rect); } else { @@ -5440,20 +5430,15 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h); const GSVector4 tmp_rect = src_rect / (GSVector4(tmp_texture->GetSize()).xyxy()); const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h)); - g_gs_device->StretchRect(src->m_texture, tmp_rect, tmp_texture, src_rect, false, false, false, true); - g_gs_device->StretchRect(tmp_texture, tmp_rect, dst->m_texture, dst_rect, false, false, false, true); + g_gs_device->StretchRectAutoMask(src->m_texture, tmp_rect, tmp_texture, src_rect, false, false, false, true); + g_gs_device->StretchRectAutoMask(tmp_texture, tmp_rect, dst->m_texture, dst_rect, false, false, false, true); } else { const GSVector4i src_rect = GSVector4i(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h); // Fast memcpy()-like path for color targets. - g_gs_device->CopyRect(src->m_texture, tmp_texture, - src_rect, - scaled_sx, scaled_sy); - - g_gs_device->CopyRect(tmp_texture, dst->m_texture, - src_rect, - scaled_dx, scaled_dy); + g_gs_device->CopyRect(src->m_texture, tmp_texture, src_rect, scaled_sx, scaled_sy); + g_gs_device->CopyRect(tmp_texture, dst->m_texture, src_rect, scaled_dx, scaled_dy); } } @@ -5465,31 +5450,18 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u const GSVector4 src_rect = scaled_src_rect / (GSVector4(src->m_texture->GetSize()).xyxy()); if (SPSM == PSMT8H && SPSM == DPSM) { - const ShaderConvert shader = ShaderConvert::COPY; const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h)); - g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, dst_rect, false, false, false, true, shader); + g_gs_device->StretchRectAutoMask(src->m_texture, src_rect, dst->m_texture, dst_rect, false, false, false, true); } else if (src->m_type != dst->m_type) { - ShaderConvert shader = dst->m_type ? ShaderConvert::RGBA8_TO_FLOAT32 : ShaderConvert::FLOAT32_TO_RGBA8; - - switch (dpsm_s.trbpp) - { - case 24: - shader = dst->m_type ? ShaderConvert::RGBA8_TO_FLOAT24 : ShaderConvert::FLOAT32_TO_RGB8; - break; - case 16: - shader = dst->m_type ? ShaderConvert::RGB5A1_TO_FLOAT16 : ShaderConvert::FLOAT16_TO_RGB5A1; - break; - default: - break; - } - g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, scaled_src_rect, shader, false); + g_gs_device->StretchRectAutoNearest(src->m_texture, src_rect, dst->m_texture, scaled_src_rect, + dpsm_s.trbpp == 16 ? 16 : 32, dpsm_s.trbpp); } - else if (src->m_texture->IsDepthStencil()) + else if (src->m_texture->IsDepthLike()) { const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h)); - g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, dst_rect, ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(src->m_texture, src_rect, dst->m_texture, dst_rect); } else { @@ -6100,8 +6072,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con const bool outside_target = ((x + w) > dst->m_texture->GetWidth() || (y + h) > dst->m_texture->GetHeight()); GSTexture* sTex = dst->m_texture; GSTexture* dTex = outside_target ? - g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) : - g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture()); + g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) : + g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture()); if (!dTex) [[unlikely]] { Console.Error("Failed to allocate %dx%d texture for offset source", w, h); @@ -6118,8 +6090,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con if (dst->m_rt_alpha_scale) { const GSVector4 sRectF = GSVector4(area) / GSVector4(1, 1, sTex->GetWidth(), sTex->GetHeight()); - g_gs_device->StretchRect( - sTex, sRectF, dTex, GSVector4(area), ShaderConvert::RTA_DECORRECTION, false); + g_gs_device->StretchRectNearest(sTex, sRectF, dTex, GSVector4(area), ShaderConvert::RTA_DECORRECTION); } else g_gs_device->CopyRect(sTex, dTex, area, 0, 0); @@ -6213,7 +6184,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con { // TODO: clean up this mess - ShaderConvert shader = dst->m_type != RenderTarget ? ShaderConvert::FLOAT32_TO_RGBA8 : ShaderConvert::COPY; + ShaderConvertSelector shader = GetConvertShader(dst->m_texture->GetFormat(), GSTexture::Format::Color); channel_shuffle = GSRendererHW::GetInstance()->TestChannelShuffle(dst); const bool is_8bits = TEX0.PSM == PSMT8 && !channel_shuffle; @@ -6369,7 +6340,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con // Create a cleared RT if we somehow end up with an empty source rect (because the RT isn't large enough). const bool source_rect_empty = sRect.rempty(); - const bool use_texture = (shader == ShaderConvert::COPY && !source_rect_empty); + const bool use_texture = (shader.Shader() == ShaderConvert::COPY && !source_rect_empty); GSVector4i region_rect = GSVector4i(0, 0, tw, th); // Assuming everything matches up, instead of copying the target, we can just sample it directly. @@ -6412,8 +6383,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con // 'src' is the new texture cache entry (hence the output) GSTexture* sTex = dst->m_texture; GSTexture* dTex = use_texture ? - g_gs_device->CreateTexture(new_size.x, new_size.y, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) : - g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color, source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture()); + g_gs_device->CreateTexture(new_size, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) : + g_gs_device->CreateRenderTarget(new_size, GSTexture::Format::Color, source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture()); if (!dTex) [[unlikely]] { Console.Error("Failed to allocate %dx%d texture for target copy to source", new_size.x, new_size.y); @@ -6431,8 +6402,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con if (dst->m_rt_alpha_scale) { const GSVector4 sRectF = GSVector4(sRect) / GSVector4(1, 1, sTex->GetWidth(), sTex->GetHeight()); - g_gs_device->StretchRect( - sTex, sRectF, dTex, GSVector4(destX, destY, sRect.width(), sRect.height()), ShaderConvert::RTA_DECORRECTION, false); + g_gs_device->StretchRectNearest( + sTex, sRectF, dTex, GSVector4(destX, destY, sRect.width(), sRect.height()), ShaderConvert::RTA_DECORRECTION); } else g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY); @@ -6459,8 +6430,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con if (dst->GetScale() > 1.0f) { GSTexture* tmpTex = use_texture ? - g_gs_device->CreateTexture(dst->m_unscaled_size.x, dst->m_unscaled_size.y, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) : - g_gs_device->CreateRenderTarget(dst->m_unscaled_size.x, dst->m_unscaled_size.y, GSTexture::Format::Color, false, PreferReusedLabelledTexture()); + g_gs_device->CreateTexture(dst->m_unscaled_size, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) : + g_gs_device->CreateRenderTarget(dst->m_unscaled_size, GSTexture::Format::Color, false, PreferReusedLabelledTexture()); const GSVector4 dRect = GSVector4(GSVector4i::loadh(dst->m_unscaled_size)); @@ -6471,7 +6442,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con g_gs_device->FilteredDownsampleTexture(dst->m_texture, tmpTex, downsample_factor, GSVector2i(0, 0), dRect); } else - g_gs_device->StretchRect(sTex, tmpTex, dRect, ShaderConvert::COPY, false); + g_gs_device->StretchRectAutoNearest(sTex, tmpTex, dRect); g_gs_device->ConvertToIndexedTexture(tmpTex, 1, x_offset, y_offset, std::max(dst->m_TEX0.TBW, 1u) * 64, dst->m_TEX0.PSM, dTex, @@ -6497,12 +6468,11 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con } else { - if (dst->m_rt_alpha_scale && shader == ShaderConvert::COPY) + if (dst->m_rt_alpha_scale && shader.Shader() == ShaderConvert::COPY) shader = ShaderConvert::RTA_DECORRECTION; const GSVector4 sRectF = GSVector4(sRect) / GSVector4(1, 1, sTex->GetWidth(), sTex->GetHeight()); - g_gs_device->StretchRect( - sTex, sRectF, dTex, GSVector4(destX, destY, new_size.x, new_size.y), shader, false); + g_gs_device->StretchRectNearest(sTex, sRectF, dTex, GSVector4(destX, destY, new_size.x, new_size.y), shader); } #ifdef PCSX2_DEVBUILD @@ -6953,7 +6923,7 @@ GSTextureCache::Source* GSTextureCache::CreateMergedSource(GIFRegTEX0 TEX0, GIFR // Sort rect list by the texture, we want to batch as many as possible together. g_gs_device->SortMultiStretchRects(copy_queue, copy_count); - g_gs_device->DrawMultiStretchRects(copy_queue, copy_count, dtex, ShaderConvert::COPY); + g_gs_device->DrawMultiStretchRects(copy_queue, copy_count, dtex); if (lmtex) g_gs_device->Recycle(lmtex); @@ -7201,8 +7171,8 @@ GSTextureCache::Target* GSTextureCache::Target::Create(GIFRegTEX0 TEX0, int w, i const int scaled_w = static_cast(std::ceil(static_cast(w) * scale)); const int scaled_h = static_cast(std::ceil(static_cast(h) * scale)); GSTexture* texture = (type == RenderTarget) ? - g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) : - g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear, PreferReusedLabelledTexture()); + g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) : + g_gs_device->CreateDepthStencil(scaled_w, scaled_h, clear, PreferReusedLabelledTexture()); if (!texture) return nullptr; @@ -7238,12 +7208,11 @@ GSTexture* GSTextureCache::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVec // If we're using native scaling we can take this opertunity to downscale the target, it should maintain this. if (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && t->m_scale > 1.0f) { - GSTexture* tex = t->m_type == RenderTarget ? g_gs_device->CreateRenderTarget(t->m_unscaled_size.x, t->m_unscaled_size.y, GSTexture::Format::Color, false) : - g_gs_device->CreateDepthStencil(t->m_unscaled_size.x, t->m_unscaled_size.y, GSTexture::Format::DepthStencil, false); + GSTexture* tex = g_gs_device->CreateCompatible(t->m_texture, t->GetUnscaledSize(), false); if (!tex) return nullptr; - g_gs_device->StretchRect(t->m_texture, GSVector4(0, 0, 1, 1), tex, GSVector4(GSVector4i::loadh(t->m_unscaled_size)), (t->m_type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false); + g_gs_device->StretchRectAutoNearest(t->m_texture, tex); m_target_memory_usage = (m_target_memory_usage - t->m_texture->GetMemUsage()) + tex->GetMemUsage(); g_gs_device->Recycle(t->m_texture); @@ -7334,7 +7303,7 @@ void GSTextureCache::Read(Target* t, const GSVector4i& r) if (is_depth) { fmt = GSTexture::Format::UInt32; - ps_shader = ShaderConvert::FLOAT32_TO_32_BITS; + ps_shader = ShaderConvert::DEPTH32_TO_32_BITS; dltex = &m_uint32_download_texture; } else @@ -7356,7 +7325,7 @@ void GSTextureCache::Read(Target* t, const GSVector4i& r) case PSMZ16S: { fmt = GSTexture::Format::UInt16; - ps_shader = is_depth ? ShaderConvert::FLOAT32_TO_16_BITS : ShaderConvert::RGBA8_TO_16_BITS; + ps_shader = is_depth ? ShaderConvert::DEPTH32_TO_16_BITS : ShaderConvert::RGB5A1_TO_16_BITS; dltex = &m_uint16_download_texture; } break; @@ -7392,7 +7361,7 @@ void GSTextureCache::Read(Target* t, const GSVector4i& r) GSTexture* tmp = g_gs_device->CreateRenderTarget(drc.z, drc.w, fmt, false); if (tmp) { - g_gs_device->StretchRect(t->m_texture, src, tmp, GSVector4(drc), ps_shader, false); + g_gs_device->StretchRectNearest(t->m_texture, src, tmp, GSVector4(drc), ps_shader); dltex->get()->CopyFromTexture(drc, tmp, drc, 0, true); g_gs_device->Recycle(tmp); } @@ -8021,25 +7990,11 @@ void GSTextureCache::Target::Update(bool cannot_scale) } const bool linear = upscaled && GSConfig.UserHacks_BilinearHack != GSBilinearDirtyMode::ForceNearest; - ShaderConvert depth_shader = linear ? ShaderConvert::RGBA8_TO_FLOAT32_BILN : ShaderConvert::RGBA8_TO_FLOAT32; - if (m_type == DepthStencil && GSLocalMemory::m_psm[m_TEX0.PSM].trbpp != 32) - { - switch (GSLocalMemory::m_psm[m_TEX0.PSM].trbpp) - { - case 24: - depth_shader = linear ? ShaderConvert::RGBA8_TO_FLOAT24_BILN : ShaderConvert::RGBA8_TO_FLOAT24; - break; - case 16: - depth_shader = linear ? ShaderConvert::RGB5A1_TO_FLOAT16_BILN : ShaderConvert::RGB5A1_TO_FLOAT16; - break; - default: - break; - } - } - const ShaderConvert rt_shader = m_rt_alpha_scale ? ShaderConvert::RTA_CORRECTION : ShaderConvert::COPY; // No need to sort here, it's all the one texture. - const ShaderConvert shader = (m_type == RenderTarget) ? rt_shader : depth_shader; + const ShaderConvertSelector shader = (m_type == RenderTarget) ? + (m_rt_alpha_scale ? ShaderConvert::RTA_CORRECTION : ShaderConvert::COPY) : + GetConvertShader(GSTexture::Format::Color, m_texture->GetFormat(), bpp, bpp, linear); g_gs_device->DrawMultiStretchRects(drects, ndrects, m_texture, shader); } @@ -8069,8 +8024,17 @@ void GSTextureCache::Target::Update(bool cannot_scale) if (m_TEX0.TBP0 == z_address_info.ZBP) { //GL_CACHE("TC: RT in RT Updating Z copy on draw %lld z_offset %d", s_n, z_address_info.offset); - const GSVector4i dRect = GSVector4i(total_rect.x * m_scale, (z_address_info.offset + total_rect.y) * m_scale, (total_rect.z + (1.0f / m_scale)) * m_scale, (z_address_info.offset + total_rect.w + (1.0f / m_scale)) * m_scale); - g_gs_device->StretchRect(m_texture, GSVector4(total_rect.x / static_cast(m_unscaled_size.x), total_rect.y / static_cast(m_unscaled_size.y), (total_rect.z + (1.0f / m_scale)) / static_cast(m_unscaled_size.x), (total_rect.w + (1.0f / m_scale)) / static_cast(m_unscaled_size.y)), g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false); + const GSVector4i dRect = GSVector4i( + total_rect.x * m_scale, + (z_address_info.offset + total_rect.y) * m_scale, + (total_rect.z + (1.0f / m_scale)) * m_scale, + (z_address_info.offset + total_rect.w + (1.0f / m_scale)) * m_scale); + g_gs_device->StretchRectAutoNearest(m_texture, + GSVector4(total_rect.x / static_cast(m_unscaled_size.x), + total_rect.y / static_cast(m_unscaled_size.y), + (total_rect.z + (1.0f / m_scale)) / static_cast(m_unscaled_size.x), + (total_rect.w + (1.0f / m_scale)) / static_cast(m_unscaled_size.y)), + g_texture_cache->GetTemporaryZ(), GSVector4(dRect)); } } } @@ -8203,9 +8167,7 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca const bool clear = (new_size.x > size.x || new_size.y > size.y); - GSTexture* tex = m_texture->IsDepthStencil() ? - g_gs_device->CreateDepthStencil(new_size.x, new_size.y, m_texture->GetFormat(), clear, PreferReusedLabelledTexture()) : - g_gs_device->CreateRenderTarget(new_size.x, new_size.y, m_texture->GetFormat(), clear, PreferReusedLabelledTexture()); + GSTexture* tex = g_gs_device->CreateCompatible(m_texture, new_size, clear, PreferReusedLabelledTexture()); if (!tex) { Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", size.x, size.y, new_size.x, new_size.y); @@ -8216,17 +8178,18 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca if (m_texture->GetState() == GSTexture::State::Dirty) { const GSVector4i rc = require_new_rect ? new_rect : GSVector4i::loadh(size.min(new_size)); - if (tex->IsDepthStencil()) + if (tex->IsDepthLike()) { // Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other // APIs either. So use a fullscreen quad setting depth instead. - g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, true); + // Use bilinear to avoid artifacts with upscaling. At native this is equivalent to nearest. + g_gs_device->StretchRectAutoBiln(m_texture, tex, GSVector4(rc)); } else { if (require_new_rect) { - g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::COPY, false); + g_gs_device->StretchRectAutoNearest(m_texture, tex, GSVector4(rc)); } else { @@ -8238,10 +8201,10 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca else if (m_texture->GetState() == GSTexture::State::Cleared) { // Otherwise just pass the clear through. - if (tex->GetType() != GSTexture::Type::DepthStencil) - g_gs_device->ClearRenderTarget(tex, m_texture->GetClearColor()); - else + if (tex->IsDepthLike()) g_gs_device->ClearDepth(tex, m_texture->GetClearDepth()); + else + g_gs_device->ClearRenderTarget(tex, m_texture->GetClearColor()); } else { diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index f4bf8a5531..605fe1d5c7 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -575,10 +575,10 @@ public: HashCacheEntry* hc_entry, bool new_texture_is_shared); /// Converts single color value to depth using the specified shader expression. - static float ConvertColorToDepth(u32 c, ShaderConvert convert); + static float ConvertColorToDepth(u32 c, u32 src_bpp, u32 dst_bpp); /// Converts single depth value to colour using the specified shader expression. - static u32 ConvertDepthToColor(float d, ShaderConvert convert); + static u32 ConvertDepthToColor(float d, u32 dst_bpp); /// Copies RGB channels from depth target to a color target. bool CopyRGBFromDepthToColor(Target* dst, Target* depth_src); diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h index bd163a641d..e46f64d79b 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h @@ -249,9 +249,8 @@ public: // Functions and Pipeline States MRCOwned> m_cas_pipeline[2]; - MRCOwned> m_convert_pipeline[static_cast(ShaderConvert::Count)]; + std::vector>> m_convert_pipeline; MRCOwned> m_present_pipeline[static_cast(PresentShader::Count)]; - MRCOwned> m_convert_pipeline_copy_mask[1 << 5]; MRCOwned> m_merge_pipeline[4]; MRCOwned> m_interlace_pipeline[NUM_INTERLACE_SHADERS]; MRCOwned> m_datm_pipeline[4]; @@ -265,6 +264,16 @@ public: MRCOwned> m_shadeboost_pipeline; MRCOwned> m_imgui_pipeline; + id GetConvertPipeline(ShaderConvertSelector shader) const + { + return m_convert_pipeline[shader.Index()]; + } + + id GetConvertPipeline(ShaderConvert shader) const + { + return m_convert_pipeline[ShaderConvertSelector(shader).Index()]; + } + MRCOwned> m_hw_vs[6 << 3]; std::unordered_map>> m_hw_ps; std::unordered_map>> m_hw_pipeline; @@ -416,7 +425,7 @@ public: /// Copy from a position in sTex to the same position in the currently active render encoder using the given fs pipeline and rect void RenderCopy(GSTexture* sTex, id pipeline, const GSVector4i& rect); void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) override; - void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; + void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override; void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override; void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override; void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override; @@ -463,7 +472,7 @@ public: protected: virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override; + ShaderConvertSelector shader, bool linear) override; }; static constexpr bool IsCommandBufferCompleted(MTLCommandBufferStatus status) diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index d3883fa109..e125a9432d 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -402,7 +402,25 @@ void GSDeviceMTL::EndRenderPass() } } -void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load, GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil, MTLLoadAction stencil_load, bool rt1) +static GSVector4 GetRTLoadInfo(GSTextureMTL* tex, MTLLoadAction* load_action) +{ + if (tex) + { + if (tex->GetState() == GSTexture::State::Invalidated) + { + *load_action = MTLLoadActionDontCare; + } + else if (tex->GetState() == GSTexture::State::Cleared && *load_action != MTLLoadActionDontCare) + { + *load_action = MTLLoadActionClear; + return tex->GetClearForFormat(); + } + } + return {}; +}; + +void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load, + GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil, MTLLoadAction stencil_load, bool rt1) { GSTextureMTL* mc = static_cast(color); GSTextureMTL* md = static_cast(depth); @@ -411,31 +429,16 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio || depth != m_current_render.depth_target || stencil != m_current_render.stencil_target || rt1 != m_current_render.has.rt1_depth; - GSVector4 color_clear; - float depth_clear; - // Depth and stencil might be the same, so do all invalidation checks before resetting invalidation -#define CHECK_CLEAR(tex, load_action, clear, ClearGetter) \ - if (tex) \ - { \ - if (tex->GetState() == GSTexture::State::Invalidated) \ - { \ - load_action = MTLLoadActionDontCare; \ - } \ - else if (tex->GetState() == GSTexture::State::Cleared && load_action != MTLLoadActionDontCare) \ - { \ - clear = tex->ClearGetter(); \ - load_action = MTLLoadActionClear; \ - } \ - } - CHECK_CLEAR(mc, color_load, color_clear, GetUNormClearColor) - CHECK_CLEAR(md, depth_load, depth_clear, GetClearDepth) -#undef CHECK_CLEAR + // Depth and stencil might be the same, so do all invalidation checks before resetting invalidation + GSVector4 color_clear = GetRTLoadInfo(mc, &color_load); + GSVector4 depth_clear = GetRTLoadInfo(md, &depth_load); + // Stencil and depth are one texture, stencil clears aren't supported if (ms && ms->GetState() == GSTexture::State::Invalidated) stencil_load = MTLLoadActionDontCare; - needs_new |= mc && color_load == MTLLoadActionClear; - needs_new |= md && depth_load == MTLLoadActionClear; + needs_new |= mc && color_load == MTLLoadActionClear; + needs_new |= md && depth_load == MTLLoadActionClear; // Reset texture state if (mc) mc->SetState(GSTexture::State::Dirty); @@ -480,7 +483,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio md->m_last_write = m_current_draw; desc.depthAttachment.texture = md->GetTexture(); if (depth_load == MTLLoadActionClear) - desc.depthAttachment.clearDepth = depth_clear; + desc.depthAttachment.clearDepth = depth_clear.x; desc.depthAttachment.loadAction = depth_load; } if (ms) @@ -496,7 +499,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio MTLRenderPassColorAttachmentDescriptor* color1 = desc.colorAttachments[1]; color1.texture = GetRT1DepthTexture(md); if (m_features.framebuffer_fetch) - color1.clearColor = MTLClearColorMake(depth_load == MTLLoadActionClear ? depth_clear : -1, 0, 0, 0); + color1.clearColor = MTLClearColorMake(depth_load == MTLLoadActionClear ? depth_clear.x : -1, 0, 0, 0); } EndRenderPass(); @@ -524,7 +527,7 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format) { switch (format) { - case GSTexture::Format::Float32: return MTLPixelFormatR32Float; + case GSTexture::Format::DepthColor: return MTLPixelFormatR32Float; case GSTexture::Format::PrimID: return MTLPixelFormatR32Float; case GSTexture::Format::UInt32: return MTLPixelFormatR32Uint; case GSTexture::Format::UInt16: return MTLPixelFormatR16Uint; @@ -625,7 +628,7 @@ void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, // Save 2nd output if (feedback_write_2) // FIXME I'm not sure dRect[1] is always correct - DoStretchRect(dTex, full_r, sTex[2], dRect[1], m_convert_pipeline[static_cast(ShaderConvert::YUV)], linear, LoadAction::DontCareIfFull, &cb_yuv, sizeof(cb_yuv)); + DoStretchRect(dTex, full_r, sTex[2], dRect[1], GetConvertPipeline(ShaderConvert::YUV), linear, LoadAction::DontCareIfFull, &cb_yuv, sizeof(cb_yuv)); if (feedback_write_2_but_blend_bg) ClearRenderTarget(dTex, c); @@ -890,6 +893,25 @@ static bool getDepthFeedback(const GSMTLDevice& dev, bool fbfetch) } } +// Some shaders are only used by methods on MTLDevice, which currently use separately-compiled shaders +static bool ConvertShaderNotNeeded(ShaderConvert shader) +{ + switch (shader) + { + case ShaderConvert::DATM_0: + case ShaderConvert::DATM_1: + case ShaderConvert::DATM_0_RTA_CORRECTION: + case ShaderConvert::DATM_1_RTA_CORRECTION: + case ShaderConvert::CLUT_4: + case ShaderConvert::CLUT_8: + case ShaderConvert::COLCLIP_INIT: + case ShaderConvert::COLCLIP_RESOLVE: + return true; + default: + return false; + } +} + bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) { @autoreleasepool { if (!GSDevice::Create(vsync_mode, allow_present_throttle)) @@ -1164,97 +1186,57 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) NSString* name = [NSString stringWithFormat:@"ps_interlace%zu", i]; m_interlace_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name); } - for (size_t i = 0; i < std::size(m_convert_pipeline); i++) + + m_convert_pipeline.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS); + for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++) { - ShaderConvert conv = static_cast(i); - NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding]; - switch (conv) + const ShaderConvertSelector shader = ShaderConvertSelector::Get(i); + if (ConvertShaderNotNeeded(shader.Shader())) + continue; + NSString* shader_name = [NSString stringWithCString:shader.EntryPoint() encoding:NSUTF8StringEncoding]; + if (shader.DepthOutput()) { - case ShaderConvert::Count: - case ShaderConvert::DATM_0: - case ShaderConvert::DATM_1: - case ShaderConvert::DATM_0_RTA_CORRECTION: - case ShaderConvert::DATM_1_RTA_CORRECTION: - case ShaderConvert::CLUT_4: - case ShaderConvert::CLUT_8: - case ShaderConvert::COLCLIP_INIT: - case ShaderConvert::COLCLIP_RESOLVE: - continue; - case ShaderConvert::FLOAT32_TO_32_BITS: - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt32); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - break; - case ShaderConvert::FLOAT32_TO_16_BITS: - case ShaderConvert::RGBA8_TO_16_BITS: - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt16); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - break; - case ShaderConvert::DEPTH_COPY: - case ShaderConvert::FLOAT32_TO_FLOAT24: - case ShaderConvert::FLOAT32_COLOR_TO_DEPTH: - case ShaderConvert::RGBA8_TO_FLOAT32: - case ShaderConvert::RGBA8_TO_FLOAT24: - case ShaderConvert::RGBA8_TO_FLOAT16: - case ShaderConvert::RGB5A1_TO_FLOAT16: - case ShaderConvert::RGBA8_TO_FLOAT32_BILN: - case ShaderConvert::RGBA8_TO_FLOAT24_BILN: - case ShaderConvert::RGBA8_TO_FLOAT16_BILN: - case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: - pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid; - pdesc.depthAttachmentPixelFormat = ConvertPixelFormat(GSTexture::Format::DepthStencil); - break; - case ShaderConvert::COPY: - case ShaderConvert::DOWNSAMPLE_COPY: - case ShaderConvert::RGBA_TO_8I: // Yes really - case ShaderConvert::RGB5A1_TO_8I: - case ShaderConvert::RTA_CORRECTION: - case ShaderConvert::RTA_DECORRECTION: - case ShaderConvert::TRANSPARENCY_FILTER: - case ShaderConvert::FLOAT32_TO_RGBA8: - case ShaderConvert::FLOAT32_TO_RGB8: - case ShaderConvert::FLOAT16_TO_RGB5A1: - case ShaderConvert::YUV: - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - break; - case ShaderConvert::FLOAT32_DEPTH_TO_COLOR: - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Float32); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - break; + pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid; + pdesc.depthAttachmentPixelFormat = ConvertPixelFormat(GSTexture::Format::DepthStencil); } - const u32 scmask = ShaderConvertWriteMask(conv); + else + { + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(shader.OutputFormat()); + pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; + } + NSString* name = shader_name; + if (shader.VariableWriteMask()) + name = [name stringByAppendingString:[NSString stringWithFormat:@" Mask=%x", shader.Mask()]]; + if (shader.Biln()) + name = [name stringByAppendingString:@" Biln"]; + if (shader.Float32Input()) + name = [name stringByAppendingString:shader.DepthInput() ? @" Depth" : @" Float"]; + if (shader.Float32Output()) + name = [name stringByAppendingString:shader.DepthOutput() ? @" → Depth" : @" → Float"]; + + const u32 scmask = shader.Mask(); MTLColorWriteMask mask = MTLColorWriteMaskNone; if (scmask & 1) mask |= MTLColorWriteMaskRed; if (scmask & 2) mask |= MTLColorWriteMaskGreen; if (scmask & 4) mask |= MTLColorWriteMaskBlue; if (scmask & 8) mask |= MTLColorWriteMaskAlpha; pdesc.colorAttachments[0].writeMask = mask; - m_convert_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name); + setFnConstantB(m_fn_constants, shader.Biln(), GSMTLConstantIndex_BILN); + setFnConstantB(m_fn_constants, shader.DepthInput(), GSMTLConstantIndex_DEPTH_IN); + setFnConstantB(m_fn_constants, shader.DepthOutput(), GSMTLConstantIndex_DEPTH_OUT); + m_convert_pipeline[shader.Index()] = MakePipeline(pdesc, vs_convert, LoadShader(shader_name), name); } pdesc.colorAttachments[0].writeMask = MTLColorWriteMaskAll; pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; for (size_t i = 0; i < std::size(m_present_pipeline); i++) { PresentShader conv = static_cast(i); - NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding]; + NSString* name = [NSString stringWithCString:ShaderEntryPoint(conv) encoding:NSUTF8StringEncoding]; pdesc.colorAttachments[0].pixelFormat = layer_px_fmt; - m_present_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), [NSString stringWithFormat:@"present_%s", shaderName(conv) + 3]); + m_present_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), [NSString stringWithFormat:@"present_%s", ShaderEntryPoint(conv) + 3]); } pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); - for (size_t i = 0; i < std::size(m_convert_pipeline_copy_mask); i++) - { - MTLColorWriteMask mask = MTLColorWriteMaskNone; - if (i & 1) mask |= MTLColorWriteMaskRed; - if (i & 2) mask |= MTLColorWriteMaskGreen; - if (i & 4) mask |= MTLColorWriteMaskBlue; - if (i & 8) mask |= MTLColorWriteMaskAlpha; - NSString* name = [NSString stringWithFormat:@"copy_%s%s%s%s%s", - i & 1 ? "r" : "", i & 2 ? "g" : "", i & 4 ? "b" : "", i & 8 ? "a" : "", i & 16 ? "_rta" : ""]; - pdesc.colorAttachments[0].writeMask = mask; - m_convert_pipeline_copy_mask[i] = MakePipeline(pdesc, vs_convert, i & 16 ? ps_copy_rta_correct : ps_copy, name); - } - pdesc.colorAttachments[0].blendingEnabled = YES; pdesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; pdesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; @@ -1667,16 +1649,12 @@ void GSDeviceMTL::RenderCopy(GSTexture* sTex, id pipelin } void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) + ShaderConvertSelector shader, bool linear) { @autoreleasepool { - const LoadAction load_action = (cms.wrgba == 0xf) ? LoadAction::DontCareIfFull : LoadAction::Load; - id pipeline; - if (HasVariableWriteMask(shader)) - pipeline = m_convert_pipeline_copy_mask[GetShaderIndexForMask(shader, cms.wrgba)]; - else - pipeline = m_convert_pipeline[static_cast(shader)]; - pxAssertRel(pipeline, fmt::format("No pipeline for {}", shaderName(shader)).c_str()); + const LoadAction load_action = (shader.Mask() == 0xf) ? LoadAction::DontCareIfFull : LoadAction::Load; + id pipeline = GetConvertPipeline(shader); + pxAssertRel(pipeline, fmt::format("No pipeline for {}", ShaderEntryPoint(shader.Shader())).c_str()); DoStretchRect(sTex, sRect, dTex, dRect, pipeline, linear, load_action, nullptr, 0); }} @@ -1715,7 +1693,7 @@ void GSDeviceMTL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture } }} -void GSDeviceMTL::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) +void GSDeviceMTL::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) { @autoreleasepool { BeginStretchRect(@"MultiStretchRect", dTex, MTLLoadActionLoad); @@ -1737,13 +1715,11 @@ void GSDeviceMTL::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_r const u32 end = i * 4; const u32 vertex_count = end - start; const u32 index_count = vertex_count + (vertex_count >> 1); // 6 indices per 4 vertices - pxAssert(HasVariableWriteMask(shader) || wmask == 0xf); - id new_pipeline = wmask == 0xf ? m_convert_pipeline[static_cast(shader)] - : m_convert_pipeline_copy_mask[GetShaderIndexForMask(shader, wmask)]; + id new_pipeline = GetConvertPipeline(shader.SetMask(wmask)); if (new_pipeline != pipeline) { pipeline = new_pipeline; - pxAssertRel(pipeline, fmt::format("No pipeline for {}", shaderName(shader)).c_str()); + pxAssertRel(pipeline, fmt::format("No pipeline for {}", ShaderEntryPoint(shader.Shader())).c_str()); MRESetPipeline(pipeline); } MRESetSampler(linear ? SamplerSelector::Linear() : SamplerSelector::Point()); @@ -1790,7 +1766,7 @@ void GSDeviceMTL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, void GSDeviceMTL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) { @autoreleasepool { const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I; - id pipeline = m_convert_pipeline[static_cast(shader)]; + id pipeline = GetConvertPipeline(shader); if (!pipeline) [NSException raise:@"StretchRect Missing Pipeline" format:@"No pipeline for %d", static_cast(shader)]; @@ -1803,7 +1779,7 @@ void GSDeviceMTL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 off void GSDeviceMTL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) { @autoreleasepool { const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY; - id pipeline = m_convert_pipeline[static_cast(shader)]; + id pipeline = GetConvertPipeline(shader); if (!pipeline) [NSException raise:@"StretchRect Missing Pipeline" format:@"No pipeline for %d", static_cast(shader)]; @@ -1847,7 +1823,7 @@ void GSDeviceMTL::BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea) return; if (m_ds_as_rt_gstexture) Recycle(m_ds_as_rt_gstexture); - m_ds_as_rt_gstexture = CreateRenderTarget(needed_width, needed_height, GSTexture::Format::Float32, false, true); + m_ds_as_rt_gstexture = CreateRenderTarget(needed_width, needed_height, GSTexture::Format::DepthColor, false, true); m_ds_as_rt_texture = static_cast(m_ds_as_rt_gstexture)->GetTexture(); @autoreleasepool { diff --git a/pcsx2/GS/Renderers/Metal/GSMTLSharedHeader.h b/pcsx2/GS/Renderers/Metal/GSMTLSharedHeader.h index 5b23952513..2dd72545d4 100644 --- a/pcsx2/GS/Renderers/Metal/GSMTLSharedHeader.h +++ b/pcsx2/GS/Renderers/Metal/GSMTLSharedHeader.h @@ -155,6 +155,9 @@ enum GSMTLAttributes enum GSMTLFnConstants { + GSMTLConstantIndex_BILN, + GSMTLConstantIndex_DEPTH_IN, + GSMTLConstantIndex_DEPTH_OUT, GSMTLConstantIndex_CAS_SHARPEN_ONLY, GSMTLConstantIndex_FRAMEBUFFER_FETCH, GSMTLConstantIndex_DEPTH_FEEDBACK, diff --git a/pcsx2/GS/Renderers/Metal/convert.metal b/pcsx2/GS/Renderers/Metal/convert.metal index e95937e268..c39a46be28 100644 --- a/pcsx2/GS/Renderers/Metal/convert.metal +++ b/pcsx2/GS/Renderers/Metal/convert.metal @@ -5,6 +5,12 @@ using namespace metal; +constant bool BILN [[function_constant(GSMTLConstantIndex_BILN)]]; +constant bool DEPTH_IN [[function_constant(GSMTLConstantIndex_DEPTH_IN)]]; +constant bool DEPTH_OUT [[function_constant(GSMTLConstantIndex_DEPTH_OUT)]]; +constant bool COLOR_IN = !DEPTH_IN; +constant bool COLOR_OUT = !DEPTH_OUT; + struct ConvertVSIn { vector_float2 position [[attribute(0)]]; @@ -65,7 +71,7 @@ fragment float4 ps_copy(ConvertShaderData data [[stage_in]], ConvertPSRes res) return res.sample(data.t); } -fragment ushort ps_convert_rgba8_16bits(ConvertShaderData data [[stage_in]], ConvertPSRes res) +fragment ushort ps_convert_rgb5a1_16bits(ConvertShaderData data [[stage_in]], ConvertPSRes res) { float4 c = res.sample(data.t); uint4 cu = uint4(c * 255.f + 0.5f); @@ -156,17 +162,17 @@ fragment float4 ps_filter_transparency(ConvertShaderData data [[stage_in]], Conv return float4(c.rgb, 1.0); } -fragment uint ps_convert_float32_32bits(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) +fragment uint ps_convert_depth32_32bits(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) { return uint(0x1p32 * res.sample(data.t)); } -fragment float4 ps_convert_float32_rgba8(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) +fragment float4 ps_convert_depth32_rgba8(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) { return convert_depth32_rgba8(res.sample(data.t)) / 255.f; } -fragment float4 ps_convert_float16_rgb5a1(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) +fragment float4 ps_convert_depth16_rgb5a1(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) { return convert_depth16_rgba8(res.sample(data.t)) / 255.f; } @@ -176,17 +182,6 @@ fragment float ps_convert_float32_depth_to_color(ConvertShaderData data [[stage_ return res.sample(data.t); } -struct DepthOut -{ - float depth [[depth(any)]]; - DepthOut(float depth): depth(depth) {} -}; - -fragment DepthOut ps_depth_copy(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) -{ - return res.sample(data.t); -} - fragment float4 ps_downsample_copy(ConvertShaderData data [[stage_in]], texture2d texture [[texture(GSMTLTextureIndexNonHW)]], constant GSMTLDownsamplePSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]]) @@ -225,6 +220,24 @@ static float rgb5a1_to_depth16(half4 unorm) return float(out) * 0x1p-32f; } +struct DepthOrColorOut +{ + float color [[color(0), function_constant(COLOR_OUT)]]; + float depth [[depth(any), function_constant(DEPTH_OUT)]]; + DepthOrColorOut(float value): color(value), depth(value) {} +}; + +struct ConvertPSDepthOrColorRes +{ + texture2d color [[texture(GSMTLTextureIndexNonHW), function_constant(COLOR_IN)]]; + depth2d depth [[texture(GSMTLTextureIndexNonHW), function_constant(DEPTH_IN)]]; + sampler s [[sampler(0)]]; + float sample(float2 coord) + { + return COLOR_IN ? color.sample(s, coord).x : depth.sample(s, coord); + } +}; + struct ConvertToDepthRes { texture2d texture [[texture(GSMTLTextureIndexNonHW)]]; @@ -252,59 +265,51 @@ struct ConvertToDepthRes float depthBR = convert(texture.read(coords.zw)); return mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y); } + + template + float sample_maybe_biln(float2 coord) + { + if (BILN) + return sample_biln(coord); + else + return convert(sample(coord)); + } }; -fragment DepthOut ps_convert_float32_float24(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res) +fragment DepthOrColorOut ps_depth_copy(ConvertShaderData data [[stage_in]], ConvertPSDepthOrColorRes res) +{ + return res.sample(data.t); +} + +static float depth32_to_depth24(float d) +{ + return float(uint(d * exp2(32.0f)) & 0xffffff) * exp2(-32.0f); +} + +fragment DepthOrColorOut ps_convert_depth32_depth24(ConvertShaderData data [[stage_in]], ConvertPSDepthOrColorRes res) { // Truncates depth value to 24bits - uint val = uint(res.sample(data.t) * 0x1p32) & 0xFFFFFF; - return float(val) * 0x1p-32f; + return depth32_to_depth24(res.sample(data.t)); } -fragment DepthOut ps_convert_float32_color_to_depth(ConvertShaderData data [[stage_in]], ConvertPSRes res) +fragment DepthOrColorOut ps_convert_rgba8_depth32(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) { - return res.sample(data.t).x; + return res.sample_maybe_biln(data.t); } - -fragment DepthOut ps_convert_rgba8_float32(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) +fragment DepthOrColorOut ps_convert_rgba8_depth24(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) { - return rgba8_to_depth32(res.sample(data.t)); + return res.sample_maybe_biln(data.t); } -fragment DepthOut ps_convert_rgba8_float24(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) +fragment DepthOrColorOut ps_convert_rgba8_depth16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) { - return rgba8_to_depth24(res.sample(data.t)); + return res.sample_maybe_biln(data.t); } -fragment DepthOut ps_convert_rgba8_float16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) +fragment DepthOrColorOut ps_convert_rgb5a1_depth16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) { - return rgba8_to_depth16(res.sample(data.t)); -} - -fragment DepthOut ps_convert_rgb5a1_float16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) -{ - return rgb5a1_to_depth16(res.sample(data.t)); -} - -fragment DepthOut ps_convert_rgba8_float32_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) -{ - return res.sample_biln(data.t); -} - -fragment DepthOut ps_convert_rgba8_float24_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) -{ - return res.sample_biln(data.t); -} - -fragment DepthOut ps_convert_rgba8_float16_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) -{ - return res.sample_biln(data.t); -} - -fragment DepthOut ps_convert_rgb5a1_float16_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res) -{ - return res.sample_biln(data.t); + return res.sample_maybe_biln(data.t); } fragment float4 ps_convert_rgb5a1_8i(ConvertShaderData data [[stage_in]], DirectReadTextureIn res, diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index c1fd689523..a68b1992cd 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -414,40 +414,57 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) { GL_PUSH("GSDeviceOGL::Convert"); - - m_convert.vs = GetShaderSource("vs_main", GL_VERTEX_SHADER, *convert_glsl); - for (size_t i = 0; i < std::size(m_convert.ps); i++) + m_convert.ps.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS); + for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++) { - const char* name = shaderName(static_cast(i)); - const std::string ps(GetShaderSource(name, GL_FRAGMENT_SHADER, *convert_glsl)); - if (!m_shader_cache.GetProgram(&m_convert.ps[i], m_convert.vs, ps)) - return false; - m_convert.ps[i].SetFormattedName("Convert pipe %s", name); + const ShaderConvertSelector shader = ShaderConvertSelector::Get(i); - if (static_cast(i) == ShaderConvert::RGBA_TO_8I || static_cast(i) == ShaderConvert::RGB5A1_TO_8I) + const char* name = shader.EntryPoint(); + + std::string macro; + macro += fmt::format("#define HAS_BILN {}\n", static_cast(shader.Biln())); + macro += fmt::format("#define HAS_STENCIL_OUTPUT {}\n", static_cast(shader.StencilOutput())); + macro += fmt::format("#define HAS_INTEGER_OUTPUT {}\n", static_cast(shader.IntegerOutputBpp() != 0)); + macro += fmt::format("#define HAS_DEPTH_INPUT {}\n", 0); // unused + macro += fmt::format("#define HAS_DEPTH_OUTPUT {}\n", static_cast(shader.DepthOutput())); + macro += fmt::format("#define HAS_FLOAT32_INPUT {}\n", static_cast(shader.Float32Input())); + macro += fmt::format("#define HAS_FLOAT32_OUTPUT {}\n", static_cast(shader.Float32Output())); + + const std::string ps(GetShaderSource(name, GL_FRAGMENT_SHADER, *convert_glsl, macro)); + + GLProgram& prog = m_convert.ps[i]; + + if (!m_shader_cache.GetProgram(&prog, m_convert.vs, ps)) + return false; + + prog.SetFormattedName("Convert pipeline (%s, mask=%x, depth=%d, biln=%d)", + shader.Name(), shader.Mask(), static_cast(shader.DepthOutput()), + static_cast(shader.Biln())); + + if (shader.Shader() == ShaderConvert::RGBA_TO_8I || shader.Shader() == ShaderConvert::RGB5A1_TO_8I) { - m_convert.ps[i].RegisterUniform("SBW"); - m_convert.ps[i].RegisterUniform("DBW"); - m_convert.ps[i].RegisterUniform("PSM"); - m_convert.ps[i].RegisterUniform("ScaleFactor"); + prog.RegisterUniform("SBW"); + prog.RegisterUniform("DBW"); + prog.RegisterUniform("PSM"); + prog.RegisterUniform("ScaleFactor"); } - else if (static_cast(i) == ShaderConvert::YUV) + else if (shader.Shader() == ShaderConvert::YUV) { - m_convert.ps[i].RegisterUniform("EMOD"); + prog.RegisterUniform("EMOD"); } - else if (static_cast(i) == ShaderConvert::CLUT_4 || static_cast(i) == ShaderConvert::CLUT_8) + else if (shader.Shader() == ShaderConvert::CLUT_4 || shader.Shader() == ShaderConvert::CLUT_8) { - m_convert.ps[i].RegisterUniform("offset"); - m_convert.ps[i].RegisterUniform("scale"); + prog.RegisterUniform("offset"); + prog.RegisterUniform("scale"); } - else if (static_cast(i) == ShaderConvert::DOWNSAMPLE_COPY) + else if (shader.Shader() == ShaderConvert::DOWNSAMPLE_COPY) { - m_convert.ps[i].RegisterUniform("ClampMin"); - m_convert.ps[i].RegisterUniform("DownsampleFactor"); - m_convert.ps[i].RegisterUniform("Weight"); - m_convert.ps[i].RegisterUniform("StepMultiplier"); + prog.RegisterUniform("ClampMin"); + prog.RegisterUniform("DownsampleFactor"); + prog.RegisterUniform("Weight"); + prog.RegisterUniform("StepMultiplier"); } } @@ -482,7 +499,7 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) for (size_t i = 0; i < std::size(m_present); i++) { - const char* name = shaderName(static_cast(i)); + const char* name = ShaderEntryPoint(static_cast(i)); const std::string ps(GetShaderSource(name, GL_FRAGMENT_SHADER, *shader)); if (!m_shader_cache.GetProgram(&m_present[i], present_vs, ps)) return false; @@ -586,7 +603,7 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle) for (size_t i = 0; i < std::size(m_date.primid_ps); i++) { const std::string ps(GetShaderSource( - fmt::format("ps_stencil_image_init_{}", i), + fmt::format("ps_primid_image_init_{}", i), GL_FRAGMENT_SHADER, *convert_glsl)); m_shader_cache.GetProgram(&m_date.primid_ps[i], m_convert.vs, ps); m_date.primid_ps[i].SetFormattedName("PrimID Destination Alpha Init %d", i); @@ -942,8 +959,9 @@ void GSDeviceOGL::DestroyResources() for (GLProgram& prog : m_present) prog.Destroy(); - for (GLProgram& prog : m_convert.ps) + for (auto& prog : m_convert.ps) prog.Destroy(); + delete m_convert.dss; delete m_convert.dss_write; @@ -1271,7 +1289,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo) { glDisable(GL_SCISSOR_TEST); - if (T->GetType() == GSTexture::Type::DepthStencil) + if (T->IsDepthStencil()) { const float d = T->GetClearDepth(); if (GLState::depth_mask) @@ -1290,7 +1308,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo) const u32 old_color_mask = GLState::wrgba; OMSetColorMaskState(); - const GSVector4 c_unorm = T->GetUNormClearColor(); + const GSVector4 c_unorm = T->GetClearForFormat(); if (T->IsIntegerFormat()) { @@ -1598,7 +1616,7 @@ void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2 const GSVector4 float_r(r); - m_convert.ps[static_cast(ShaderConvert::COPY)].Bind(); + GetConvertProgram(ShaderConvert::COPY).Bind(); OMSetDepthStencilState(m_convert.dss); OMSetBlendState(); OMSetColorMaskState(); @@ -1656,9 +1674,11 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r } void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - OMColorMaskSelector cms, ShaderConvert shader, bool linear) + ShaderConvertSelector shader, bool linear) { - DoStretchRect(sTex, sRect, dTex, dRect, m_convert.ps[static_cast(shader)], false, cms, linear); + const u8 mask = shader.Mask(); + shader = ProcessShaderConvertSelector(shader); // Removes mask and depth input. + DoStretchRect(sTex, sRect, dTex, dRect, GetConvertProgram(shader), false, OMColorMaskSelector(mask), linear); } void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, @@ -1754,7 +1774,7 @@ void GSDeviceOGL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, CommitClear(sTex, false); const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8; - GLProgram& prog = m_convert.ps[static_cast(shader)]; + GLProgram& prog = GetConvertProgram(shader); prog.Bind(); prog.Uniform3ui(0, offsetX, offsetY, dOffset); prog.Uniform1f(1, sScale); @@ -1776,7 +1796,7 @@ void GSDeviceOGL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 off CommitClear(sTex, false); const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I; - GLProgram& prog = m_convert.ps[static_cast(shader)]; + GLProgram& prog = GetConvertProgram(shader); prog.Bind(); prog.Uniform1ui(0, SBW); prog.Uniform1ui(1, DBW); @@ -1800,7 +1820,7 @@ void GSDeviceOGL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u3 CommitClear(sTex, false); constexpr ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY; - GLProgram& prog = m_convert.ps[static_cast(shader)]; + GLProgram& prog = GetConvertProgram(shader); prog.Bind(); prog.Uniform2iv(0, clamp_min.v); prog.Uniform1i(1, downsample_factor); @@ -1846,18 +1866,20 @@ void GSDeviceOGL::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect } void GSDeviceOGL::DrawMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) + const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) { + shader = ProcessShaderConvertSelector(shader); + IASetVAO(m_vao); IASetPrimitiveTopology(GL_TRIANGLE_STRIP); - OMSetDepthStencilState(HasDepthOutput(shader) ? m_convert.dss_write : m_convert.dss); + OMSetDepthStencilState(shader.DepthOutput() ? m_convert.dss_write : m_convert.dss); OMSetBlendState(false); OMSetColorMaskState(); if (!dTex->IsDepthStencil()) OMSetRenderTargets(dTex, nullptr, nullptr); else OMSetRenderTargets(nullptr, nullptr, dTex); - m_convert.ps[static_cast(shader)].Bind(); + GetConvertProgram(shader).Bind(); const GSVector2 ds(static_cast(dTex->GetWidth()), static_cast(dTex->GetHeight())); GSTexture* last_tex = rects[0].src; @@ -1968,8 +1990,8 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, if (feedback_write_2 || feedback_write_1) { // Write result to feedback loop - m_convert.ps[static_cast(ShaderConvert::YUV)].Bind(); - m_convert.ps[static_cast(ShaderConvert::YUV)].Uniform2i(0, EXTBUF.EMODA, EXTBUF.EMODC); + GetConvertProgram(ShaderConvert::YUV).Bind(); + GetConvertProgram(ShaderConvert::YUV).Uniform2i(0, EXTBUF.EMODA, EXTBUF.EMODC); } // Save 2nd output @@ -2100,7 +2122,7 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GS constexpr GLint clear_color = 0; glClearBufferiv(GL_STENCIL, 0, &clear_color); } - m_convert.ps[SetDATMShader(datm)].Bind(); + GetConvertProgram(SetDATMShader(datm)).Bind(); // om diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h index 0633c49288..e8100bef5c 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h @@ -182,13 +182,23 @@ private: struct { std::string vs; - GLProgram ps[static_cast(ShaderConvert::Count)]; // program object + std::vector ps; // program object GLuint ln = 0; // sampler object GLuint pt = 0; // sampler object GSDepthStencilOGL* dss = nullptr; GSDepthStencilOGL* dss_write = nullptr; } m_convert; + GLProgram& GetConvertProgram(ShaderConvertSelector shader) + { + return m_convert.ps[shader.Index()]; + } + + GLProgram& GetConvertProgram(ShaderConvert shader) + { + return m_convert.ps[ShaderConvertSelector(shader).Index()]; + } + GLProgram m_present[static_cast(PresentShader::Count)]; struct @@ -280,8 +290,12 @@ private: protected: virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override; - + ShaderConvertSelector shader, bool linear) override; + virtual ShaderConvertSelector ProcessShaderConvertSelector(ShaderConvertSelector shader) const + { + // Depth input is handled same as color. Color mask is handled separately. + return shader.SetDepthInput(false).SetMask(0xf); + } public: GSDeviceOGL(); virtual ~GSDeviceOGL(); @@ -348,7 +362,7 @@ public: void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override; void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override; - void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; + void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override; void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds); void RenderHW(GSHWDrawConfig& config) override; diff --git a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp index e83a57d5f1..4b83c1df6f 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp @@ -64,7 +64,7 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format break; // 1 channel float - case Format::Float32: + case Format::DepthColor: gl_fmt = GL_R32F; m_int_format = GL_RED; m_int_type = GL_FLOAT; diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index f0a5a8cd51..df34f8d8de 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -52,10 +52,6 @@ enum : u32 static u32 s_debug_scope_depth = 0; #endif -static bool IsDATMConvertShader(ShaderConvert i) -{ - return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1 || i == ShaderConvert::DATM_0_RTA_CORRECTION || i == ShaderConvert::DATM_1_RTA_CORRECTION); -} static bool IsDATEModePrimIDInit(u32 flag) { return flag == 1 || flag == 2; @@ -2813,11 +2809,11 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const VK_FORMAT_R16G16B16A16_SFLOAT, // ColorHDR VK_FORMAT_R16G16B16A16_UNORM, // ColorClip VK_FORMAT_D32_SFLOAT_S8_UINT, // DepthStencil - VK_FORMAT_R32_SFLOAT, // Float32 + VK_FORMAT_R32_SFLOAT, // DepthColor VK_FORMAT_R8_UNORM, // UNorm8 VK_FORMAT_R16_UINT, // UInt16 VK_FORMAT_R32_UINT, // UInt32 - VK_FORMAT_R32_SFLOAT, // Int32 + VK_FORMAT_R32_SFLOAT, // PrimID VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1 VK_FORMAT_BC2_UNORM_BLOCK, // BC2 VK_FORMAT_BC3_UNORM_BLOCK, // BC3 @@ -2825,8 +2821,8 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const }}; return (format != GSTexture::Format::DepthStencil || m_features.stencil_buffer) ? - s_format_mapping[static_cast(format)] : - VK_FORMAT_D32_SFLOAT; + s_format_mapping[static_cast(format)] : + VK_FORMAT_D32_SFLOAT; } GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) @@ -2879,7 +2875,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, // so use an attachment clear VkClearAttachment ca; ca.aspectMask = depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - GSVector4::store(ca.clearValue.color.float32, sTexVK->GetUNormClearColor()); + GSVector4::store(ca.clearValue.color.float32, sTexVK->GetClearForFormat()); ca.clearValue.depthStencil.depth = sTexVK->GetClearDepth(); ca.clearValue.depthStencil.stencil = 0; ca.colorAttachment = 0; @@ -2926,15 +2922,20 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, } void GSDeviceVK::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) + ShaderConvertSelector shader, bool linear) { - const bool allow_discard = (cms.wrgba == 0xf); - VkPipeline state; - if (HasVariableWriteMask(shader)) - state = m_color_copy[GetShaderIndexForMask(shader, cms.wrgba)]; - else - state = dTex ? m_convert[static_cast(shader)] : m_present[static_cast(shader)]; - DoStretchRect(static_cast(sTex), sRect, static_cast(dTex), dRect, state, linear, allow_discard); + pxAssert(dTex); + shader = ProcessShaderConvertSelector(shader); // Removes depth input + const bool allow_discard = (shader.Mask() == 0xf); + DoStretchRect(static_cast(sTex), sRect, static_cast(dTex), dRect, + GetConvertPipeline(shader), linear, allow_discard); +} + +void GSDeviceVK::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect, + PresentShader shader, bool linear) +{ + DoStretchRect(static_cast(sTex), sRect, nullptr, dRect, + m_present.at(static_cast(shader)), linear, true); } void GSDeviceVK::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, @@ -2951,8 +2952,10 @@ void GSDeviceVK::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* } void GSDeviceVK::DrawMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) + const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) { + shader = ProcessShaderConvertSelector(shader); // Removes depth input + GSTexture* last_tex = rects[0].src; bool last_linear = rects[0].linear; u8 last_wmask = rects[0].wmask.wrgba; @@ -2993,7 +2996,7 @@ void GSDeviceVK::DrawMultiStretchRects( } void GSDeviceVK::DoMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvert shader) + const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvertSelector shader) { g_perfmon.Put(GSPerfMon::TextureCopies, 1); @@ -3062,10 +3065,7 @@ void GSDeviceVK::DoMultiStretchRects( BeginRenderPassForStretchRect(dTex, rc, rc, false); SetUtilityTexture(rects[0].src, rects[0].linear ? m_linear_sampler : m_point_sampler); - pxAssert(HasVariableWriteMask(shader) || rects[0].wmask.wrgba == 0xf); - SetPipeline((rects[0].wmask.wrgba != 0xf) ? - m_color_copy[GetShaderIndexForMask(shader, rects[0].wmask.wrgba)] : - m_convert[static_cast(shader)]); + SetPipeline(GetConvertPipeline(shader.SetMask(rects[0].wmask.wrgba))); if (ApplyUtilityState()) DrawIndexedPrimitive(); @@ -3221,7 +3221,7 @@ void GSDeviceVK::UpdateCLUTTexture( const GSVector4 dRect(0, 0, dSize, 1); const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8; DoStretchRect(static_cast(sTex), GSVector4::zero(), static_cast(dTex), dRect, - m_convert[static_cast(shader)], false, true); + GetConvertPipeline(shader), false, true); } void GSDeviceVK::ConvertToIndexedTexture( @@ -3243,7 +3243,7 @@ void GSDeviceVK::ConvertToIndexedTexture( const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I; const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight()); DoStretchRect(static_cast(sTex), GSVector4::zero(), static_cast(dTex), dRect, - m_convert[static_cast(shader)], false, true); + GetConvertPipeline(shader), false, true); } void GSDeviceVK::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) @@ -3265,7 +3265,7 @@ void GSDeviceVK::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY; //const GSVector4 dRect = GSVector4(dTex->GetRect()); DoStretchRect(static_cast(sTex), GSVector4::zero(), static_cast(dTex), dRect, - m_convert[static_cast(shader)], false, true); + GetConvertPipeline(shader), false, true); } void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, @@ -3315,7 +3315,7 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, OMSetRenderTargets(dTex, nullptr, darea); SetUtilityTexture(sTex[1], sampler); BeginClearRenderPass(m_utility_color_render_pass_clear, darea, c); - SetPipeline(m_convert[static_cast(ShaderConvert::COPY)]); + SetPipeline(GetConvertPipeline(ShaderConvert::COPY)); DrawStretchRect(sRect[1], PMODE.SLBG ? dRect[2] : dRect[1], dsize); dTex->SetState(GSTexture::State::Dirty); dcleared = true; @@ -3335,7 +3335,7 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, BeginRenderPassForStretchRect(static_cast(sTex[2]), fbarea, GSVector4i(dRect[2])); if (dcleared) { - SetPipeline(m_convert[static_cast(ShaderConvert::YUV)]); + SetPipeline(GetConvertPipeline(ShaderConvert::YUV)); SetUtilityPushConstants(yuv_constants, sizeof(yuv_constants)); DrawStretchRect(full_r, dRect[2], fbsize); } @@ -3374,7 +3374,7 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, if (feedback_write_1) { EndRenderPass(); - SetPipeline(m_convert[static_cast(ShaderConvert::YUV)]); + SetPipeline(GetConvertPipeline(ShaderConvert::YUV)); SetUtilityTexture(dTex, sampler); SetUtilityPushConstants(yuv_constants, sizeof(yuv_constants)); OMSetRenderTargets(sTex[2], nullptr, fbarea); @@ -3565,7 +3565,7 @@ void GSDeviceVK::OMSetRenderTargets( VkClearAttachment& ca = cas[num_ca++]; ca.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; ca.colorAttachment = 0; - GSVector4::store(ca.clearValue.color.float32, vkRt->GetUNormClearColor()); + GSVector4::store(ca.clearValue.color.float32, vkRt->GetClearForFormat()); } vkRt->SetState(GSTexture::State::Dirty); @@ -4005,14 +4005,14 @@ bool GSDeviceVK::CreateRenderPasses() bool GSDeviceVK::CompileConvertPipelines() { - const std::optional shader = ReadShaderSource("shaders/vulkan/convert.glsl"); - if (!shader) + const std::optional source = ReadShaderSource("shaders/vulkan/convert.glsl"); + if (!source) { Host::ReportErrorAsync("GS", "Failed to read shaders/vulkan/convert.glsl."); return false; } - VkShaderModule vs = GetUtilityVertexShader(*shader); + VkShaderModule vs = GetUtilityVertexShader(*source); if (vs == VK_NULL_HANDLE) return false; ScopedGuard vs_guard([this, &vs]() { vkDestroyShaderModule(m_device, vs, nullptr); }); @@ -4028,55 +4028,37 @@ bool GSDeviceVK::CompileConvertPipelines() gpb.SetNoBlendingState(); gpb.SetVertexShader(vs); - for (ShaderConvert i = ShaderConvert::COPY; i < ShaderConvert::Count; i = static_cast(static_cast(i) + 1)) + m_convert.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS); + for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++) { - const bool depth = HasDepthOutput(i); - const int index = static_cast(i); + const ShaderConvertSelector shader = ShaderConvertSelector::Get(i); VkRenderPass rp; - switch (i) + if (shader.DATMConvertShader()) { - case ShaderConvert::RGBA8_TO_16_BITS: - case ShaderConvert::FLOAT32_TO_16_BITS: - { - rp = GetRenderPass(LookupNativeFormat(GSTexture::Format::UInt16), VK_FORMAT_UNDEFINED, - VK_ATTACHMENT_LOAD_OP_DONT_CARE); - } - break; - case ShaderConvert::FLOAT32_TO_32_BITS: - { - rp = GetRenderPass(LookupNativeFormat(GSTexture::Format::UInt32), VK_FORMAT_UNDEFINED, - VK_ATTACHMENT_LOAD_OP_DONT_CARE); - } - break; - case ShaderConvert::DATM_0: - case ShaderConvert::DATM_1: - case ShaderConvert::DATM_0_RTA_CORRECTION: - case ShaderConvert::DATM_1_RTA_CORRECTION: - { - rp = m_date_setup_render_pass; - } - break; - case ShaderConvert::FLOAT32_DEPTH_TO_COLOR: - { - rp = GetRenderPass(LookupNativeFormat(GSTexture::Format::Float32), VK_FORMAT_UNDEFINED, - VK_ATTACHMENT_LOAD_OP_DONT_CARE); - } - break; - default: - { - rp = GetRenderPass(LookupNativeFormat(depth ? GSTexture::Format::Invalid : GSTexture::Format::Color), - LookupNativeFormat(depth ? GSTexture::Format::DepthStencil : GSTexture::Format::Invalid), - VK_ATTACHMENT_LOAD_OP_DONT_CARE); - } - break; + rp = m_date_setup_render_pass; } + else if (shader.DepthOutput()) + { + rp = GetRenderPass( + LookupNativeFormat(GSTexture::Format::Invalid), + LookupNativeFormat(GSTexture::Format::DepthStencil), + VK_ATTACHMENT_LOAD_OP_DONT_CARE); + } + else + { + rp = GetRenderPass( + LookupNativeFormat(shader.OutputFormat()), + LookupNativeFormat(GSTexture::Format::Invalid), + VK_ATTACHMENT_LOAD_OP_DONT_CARE); + } + if (!rp) return false; gpb.SetRenderPass(rp, 0); - if (IsDATMConvertShader(i)) + if (shader.DATMConvertShader()) { const VkStencilOpState sos = { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 1u, 1u, 1u}; @@ -4085,64 +4067,44 @@ bool GSDeviceVK::CompileConvertPipelines() } else { - gpb.SetDepthState(depth, depth, VK_COMPARE_OP_ALWAYS); + gpb.SetDepthState(shader.DepthOutput(), shader.DepthOutput(), VK_COMPARE_OP_ALWAYS); gpb.SetNoStencilState(); } - gpb.SetColorWriteMask(0, ShaderConvertWriteMask(i)); + gpb.SetColorWriteMask(0, shader.Mask()); - VkShaderModule ps = GetUtilityFragmentShader(*shader, shaderName(i)); + std::string macro; + macro += fmt::format("#define HAS_BILN {}\n", static_cast(shader.Biln())); + macro += fmt::format("#define HAS_STENCIL_OUTPUT {}\n", static_cast(shader.StencilOutput())); + macro += fmt::format("#define HAS_INTEGER_OUTPUT {}\n", static_cast(shader.IntegerOutputBpp() != 0)); + macro += fmt::format("#define HAS_DEPTH_INPUT {}\n", 0); // unused + macro += fmt::format("#define HAS_DEPTH_OUTPUT {}\n", static_cast(shader.DepthOutput())); + macro += fmt::format("#define HAS_FLOAT32_INPUT {}\n", static_cast(shader.Float32Input())); + macro += fmt::format("#define HAS_FLOAT32_OUTPUT {}\n", static_cast(shader.Float32Output())); + + std::string shader_with_header = macro + *source; + + VkShaderModule ps = GetUtilityFragmentShader(shader_with_header, shader.EntryPoint()); if (ps == VK_NULL_HANDLE) return false; ScopedGuard ps_guard([this, &ps]() { vkDestroyShaderModule(m_device, ps, nullptr); }); gpb.SetFragmentShader(ps); - m_convert[index] = gpb.Create(m_device, g_vulkan_shader_cache->GetPipelineCache(true), false); - if (!m_convert[index]) + VkPipeline pipe = gpb.Create(m_device, g_vulkan_shader_cache->GetPipelineCache(true), false); + + if (!pipe) return false; - Vulkan::SetObjectName(m_device, m_convert[index], "Convert pipeline %d", i); + m_convert[i] = pipe; - if (i == ShaderConvert::COPY) + Vulkan::SetObjectName(m_device, pipe, "Convert pipeline (%s, mask=%x, depth=%d, biln=%d)", + shader.Name(), shader.Mask(), static_cast(shader.DepthOutput()), + static_cast(shader.Biln())); + + if (shader.Shader() == ShaderConvert::COLCLIP_INIT || shader.Shader() == ShaderConvert::COLCLIP_RESOLVE) { - // compile color copy pipelines - gpb.SetRenderPass(m_utility_color_render_pass_discard, 0); - for (u32 j = 0; j < 16; j++) - { - pxAssert(!m_color_copy[j]); - gpb.ClearBlendAttachments(); - gpb.SetBlendAttachment(0, false, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, static_cast(j)); - m_color_copy[j] = gpb.Create(m_device, g_vulkan_shader_cache->GetPipelineCache(true), false); - if (!m_color_copy[j]) - return false; - - Vulkan::SetObjectName(m_device, m_color_copy[j], "Color copy pipeline (r=%u, g=%u, b=%u, a=%u)", j & 1u, - (j >> 1) & 1u, (j >> 2) & 1u, (j >> 3) & 1u); - } - } - else if (i == ShaderConvert::RTA_CORRECTION) - { - gpb.SetRenderPass(m_utility_color_render_pass_discard, 0); - for (u32 j = 16; j < 32; j++) - { - pxAssert(!m_color_copy[j]); - gpb.ClearBlendAttachments(); - - gpb.SetBlendAttachment(0, false, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, static_cast(j - 16)); - m_color_copy[j] = gpb.Create(m_device, g_vulkan_shader_cache->GetPipelineCache(true), false); - if (!m_color_copy[j]) - return false; - - Vulkan::SetObjectName(m_device, m_color_copy[j], "Color copy pipeline (r=%u, g=%u, b=%u, a=%u)", j & 1u, - (j >> 1) & 1u, (j >> 2) & 1u, (j >> 3) & 1u); - } - } - else if (i == ShaderConvert::COLCLIP_INIT || i == ShaderConvert::COLCLIP_RESOLVE) - { - const bool is_setup = i == ShaderConvert::COLCLIP_INIT; + const bool is_setup = shader.Shader() == ShaderConvert::COLCLIP_INIT; VkPipeline(&arr)[2][2] = *(is_setup ? &m_colclip_setup_pipelines : &m_colclip_finish_pipelines); for (u32 ds = 0; ds < 2; ds++) { @@ -4151,7 +4113,7 @@ bool GSDeviceVK::CompileConvertPipelines() pxAssert(!arr[ds][fbl]); gpb.SetRenderPass(GetTFXRenderPass(true, ds != 0, is_setup, false, fbl != 0, false, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE), + VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE), 0); arr[ds][fbl] = gpb.Create(m_device, g_vulkan_shader_cache->GetPipelineCache(true), false); if (!arr[ds][fbl]) @@ -4169,7 +4131,7 @@ bool GSDeviceVK::CompileConvertPipelines() { for (u32 clear = 0; clear < 2; clear++) { - m_date_image_setup_render_passes[ds][clear] = GetRenderPass(LookupNativeFormat(GSTexture::Format::PrimID), + m_primid_image_setup_render_passes[ds][clear] = GetRenderPass(LookupNativeFormat(GSTexture::Format::PrimID), ds ? LookupNativeFormat(GSTexture::Format::DepthStencil) : VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, ds ? (clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD) : @@ -4180,9 +4142,9 @@ bool GSDeviceVK::CompileConvertPipelines() for (u32 datm = 0; datm < 4; datm++) { - const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%d", datm)); + const std::string entry_point(StringUtil::StdStringFromFormat("ps_primid_image_init_%d", datm)); VkShaderModule ps = - GetUtilityFragmentShader(*shader, entry_point.c_str()); + GetUtilityFragmentShader(*source, entry_point.c_str()); if (ps == VK_NULL_HANDLE) return false; @@ -4197,13 +4159,13 @@ bool GSDeviceVK::CompileConvertPipelines() for (u32 ds = 0; ds < 2; ds++) { - gpb.SetRenderPass(m_date_image_setup_render_passes[ds][0], 0); - m_date_image_setup_pipelines[ds][datm] = + gpb.SetRenderPass(m_primid_image_setup_render_passes[ds][0], 0); + m_primid_image_setup_pipelines[ds][datm] = gpb.Create(m_device, g_vulkan_shader_cache->GetPipelineCache(true), false); - if (!m_date_image_setup_pipelines[ds][datm]) + if (!m_primid_image_setup_pipelines[ds][datm]) return false; - Vulkan::SetObjectName(m_device, m_date_image_setup_pipelines[ds][datm], + Vulkan::SetObjectName(m_device, m_primid_image_setup_pipelines[ds][datm], "DATE image clear pipeline (ds=%u, datm=%u)", ds, (datm == 1 || datm == 3)); } } @@ -4249,7 +4211,7 @@ bool GSDeviceVK::CompilePresentPipelines() { const int index = static_cast(i); - VkShaderModule ps = GetUtilityFragmentShader(*shader, shaderName(i)); + VkShaderModule ps = GetUtilityFragmentShader(*shader, ShaderEntryPoint(i)); if (ps == VK_NULL_HANDLE) return false; @@ -4708,20 +4670,15 @@ void GSDeviceVK::DestroyResources() if (it != VK_NULL_HANDLE) vkDestroyPipeline(m_device, it, nullptr); } - for (VkPipeline it : m_color_copy) - { - if (it != VK_NULL_HANDLE) - vkDestroyPipeline(m_device, it, nullptr); - } for (VkPipeline it : m_present) { if (it != VK_NULL_HANDLE) vkDestroyPipeline(m_device, it, nullptr); } - for (VkPipeline it : m_convert) + for (const auto& pipe : m_convert) { - if (it != VK_NULL_HANDLE) - vkDestroyPipeline(m_device, it, nullptr); + if (pipe != VK_NULL_HANDLE) + vkDestroyPipeline(m_device, pipe, nullptr); } for (u32 ds = 0; ds < 2; ds++) { @@ -4737,8 +4694,8 @@ void GSDeviceVK::DestroyResources() { for (u32 datm = 0; datm < 4; datm++) { - if (m_date_image_setup_pipelines[ds][datm] != VK_NULL_HANDLE) - vkDestroyPipeline(m_device, m_date_image_setup_pipelines[ds][datm], nullptr); + if (m_primid_image_setup_pipelines[ds][datm] != VK_NULL_HANDLE) + vkDestroyPipeline(m_device, m_primid_image_setup_pipelines[ds][datm], nullptr); } } if (m_fxaa_pipeline != VK_NULL_HANDLE) @@ -4957,7 +4914,7 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p) if (IsDATEModePrimIDInit(p.ps.date)) { // DATE image prepass - gpb.SetRenderPass(m_date_image_setup_render_passes[p.ds][0], 0); + gpb.SetRenderPass(m_primid_image_setup_render_passes[p.ds][0], 0); } else { @@ -5691,7 +5648,7 @@ void GSDeviceVK::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV SetUtilityTexture(rt, m_point_sampler); OMSetRenderTargets(nullptr, ds, bbox); IASetVertexBuffer(vertices, sizeof(vertices[0]), 4); - SetPipeline(m_convert[SetDATMShader(datm)]); + SetPipeline(GetConvertPipeline(SetDATMShader(datm))); BeginClearRenderPass(m_date_setup_render_pass, bbox, 0.0f, 0); if (ApplyUtilityState()) DrawPrimitive(); @@ -5732,11 +5689,11 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config) VkClearValue cv[2] = {}; cv[1].depthStencil.depth = static_cast(config.ds)->GetClearDepth(); cv[1].depthStencil.stencil = 1; - BeginClearRenderPass(m_date_image_setup_render_passes[ds][1], GSVector4i::loadh(rtsize), cv, 2); + BeginClearRenderPass(m_primid_image_setup_render_passes[ds][1], GSVector4i::loadh(rtsize), cv, 2); } else { - BeginRenderPass(m_date_image_setup_render_passes[ds][0], config.drawarea); + BeginRenderPass(m_primid_image_setup_render_passes[ds][0], config.drawarea); } // draw the quad to prefill the image @@ -5748,7 +5705,7 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config) {GSVector4(dst.x, -dst.w, 0.5f, 1.0f), GSVector2(src.x, src.w)}, {GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(src.z, src.w)}, }; - const VkPipeline pipeline = m_date_image_setup_pipelines[ds][static_cast(config.datm)]; + const VkPipeline pipeline = m_primid_image_setup_pipelines[ds][static_cast(config.datm)]; SetPipeline(pipeline); IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices)); if (ApplyUtilityState()) @@ -5857,7 +5814,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) { alignas(16) VkClearValue cvs[2]; u32 cv_count = 0; - GSVector4::store(&cvs[cv_count++].color, draw_rt->GetUNormClearColor()); + GSVector4::store(&cvs[cv_count++].color, draw_rt->GetClearForFormat()); if (draw_ds) cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1}; @@ -6080,7 +6037,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) u32 cv_count = 0; if (draw_rt) { - GSVector4 clear_color = draw_rt->GetUNormClearColor(); + GSVector4 clear_color = draw_rt->GetClearForFormat(); if (pipe.ps.colclip_hw) { // Denormalize clear color for hw colclip. @@ -6197,7 +6154,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) { alignas(16) VkClearValue cvs[2]; u32 cv_count = 0; - GSVector4::store(&cvs[cv_count++].color, draw_rt->GetUNormClearColor()); + GSVector4::store(&cvs[cv_count++].color, draw_rt->GetClearForFormat()); if (draw_ds) cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1}; diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index 93d9eafbb1..ebd9c8f0bf 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -398,18 +398,27 @@ private: std::unordered_map m_samplers; - std::array(ShaderConvert::Count)> m_convert{}; + std::vector m_convert; std::array(PresentShader::Count)> m_present{}; - std::array m_color_copy{}; std::array m_merge{}; std::array m_interlace{}; VkPipeline m_colclip_setup_pipelines[2][2] = {}; // [depth][feedback_loop] VkPipeline m_colclip_finish_pipelines[2][2] = {}; // [depth][feedback_loop] - VkRenderPass m_date_image_setup_render_passes[2][2] = {}; // [depth][clear] - VkPipeline m_date_image_setup_pipelines[2][4] = {}; // [depth][datm] + VkRenderPass m_primid_image_setup_render_passes[2][2] = {}; // [depth][clear] + VkPipeline m_primid_image_setup_pipelines[2][4] = {}; // [depth][datm] VkPipeline m_fxaa_pipeline = {}; VkPipeline m_shadeboost_pipeline = {}; + VkPipeline GetConvertPipeline(ShaderConvertSelector shader) const + { + return m_convert[shader.Index()]; + } + + VkPipeline GetConvertPipeline(ShaderConvert shader) const + { + return m_convert[ShaderConvertSelector(shader).Index()]; + } + std::unordered_map m_tfx_vertex_shaders; std::unordered_map m_tfx_fragment_shaders; @@ -483,8 +492,14 @@ private: protected: virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, - GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override; - + ShaderConvertSelector shader, bool linear) override; + virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect, + PresentShader shader, bool linear) override; + ShaderConvertSelector ProcessShaderConvertSelector(ShaderConvertSelector shader) const + { + // Depth input handled same as color input. + return shader.SetDepthInput(false); + } public: GSDeviceVK(); ~GSDeviceVK() override; @@ -550,8 +565,8 @@ public: void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) override; void DrawMultiStretchRects( - const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; - void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvert shader); + const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override; + void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvertSelector shader); void BeginRenderPassForStretchRect( GSTextureVK* dTex, const GSVector4i& dtex_rc, const GSVector4i& dst_rc, bool allow_discard = true); diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp index ffd4b96a49..fcad57fbf9 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp @@ -550,7 +550,7 @@ void GSTextureVK::CommitClear(VkCommandBuffer cmdbuf) else { alignas(16) VkClearColorValue cv; - GSVector4::store(cv.float32, GetUNormClearColor()); + GSVector4::store(cv.float32, GetClearForFormat()); const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}; vkCmdClearColorImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cv, 1, &srr); } diff --git a/pcsx2/ShaderCacheVersion.h b/pcsx2/ShaderCacheVersion.h index 86923b8981..1240148238 100644 --- a/pcsx2/ShaderCacheVersion.h +++ b/pcsx2/ShaderCacheVersion.h @@ -3,4 +3,4 @@ /// Version number for GS and other shaders. Increment whenever any of the contents of the /// shaders change, to invalidate the cache. -static constexpr u32 SHADER_CACHE_VERSION = 96; // Last changed in PR 14479 +static constexpr u32 SHADER_CACHE_VERSION = 97; // Last changed in PR 14477