GS/HW: Refactor shader copy and texture formats.

Make it easier to add new depth formats, and code cleanup.

Co-authored-by: TellowKrinkle
This commit is contained in:
TJnotJT
2026-05-21 16:02:42 -04:00
committed by lightningterror
parent 093287f6bf
commit a44fe80caa
31 changed files with 2105 additions and 1371 deletions
+242 -138
View File
@@ -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
+2 -2
View File
@@ -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));
+166 -159
View File
@@ -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
+2 -2
View File
@@ -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);
+155 -140
View File
@@ -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
+2 -2
View File
@@ -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));
+287 -81
View File
@@ -22,29 +22,13 @@
#include <ostream>
#include <fstream>
int SetDATMShader(SetDATM datm)
{
switch (datm)
{
case SetDATM::DATM1_RTA_CORRECTION:
return static_cast<int>(ShaderConvert::DATM_1_RTA_CORRECTION);
case SetDATM::DATM0_RTA_CORRECTION:
return static_cast<int>(ShaderConvert::DATM_0_RTA_CORRECTION);
case SetDATM::DATM1:
return static_cast<int>(ShaderConvert::DATM_1);
case SetDATM::DATM0:
default:
return static_cast<int>(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<u32>(ShaderConvert::Count) * 8;
static constexpr ShaderConvertSelector GetRemappedShader(u32 idx)
{
ShaderConvert convert = static_cast<ShaderConvert>(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<ShaderConvert>(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<u8, NUM_REMAP_INPUTS> GenRemapArray()
{
std::array<u8, NUM_REMAP_INPUTS> 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<ShaderConvertSelector, NUM_TOTAL_SHADERS> GetPackedShaders()
{
std::array<ShaderConvertSelector, NUM_TOTAL_SHADERS> 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<u8, NUM_REMAP_INPUTS> ShaderConvertSelector::INDEX_REMAP = GenRemapArray();
static constexpr auto PACKED_SHADERS = GetPackedShaders();
const std::span<const ShaderConvertSelector> ShaderConvertSelector::SHADERS = PACKED_SHADERS;
// clang-format off
// Maps PS2 blend modes to our best approximation of them with PC hardware
+474 -80
View File
@@ -13,11 +13,13 @@
#include "GS/GSAlignedClass.h"
#include "GS/GSExtra.h"
#include <array>
#include <span>
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<u32>(shader) }
{
*this = SetMask(mask).SetDepthInput(depth_in).SetDepthOutput(depth_out).SetBiln(biln);
}
constexpr ShaderConvert Shader() const
{
return static_cast<ShaderConvert>(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<const ShaderConvertSelector> SHADERS;
static const std::array<u8, static_cast<u32>(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<ShaderConvert>(-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<GSDownloadTexture> 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);
+5 -5
View File
@@ -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
+13 -1
View File
@@ -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)
{
+46 -17
View File
@@ -219,15 +219,36 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
const std::optional<std::string> 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<ShaderConvert>(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<int>(shader.Biln()));
sm_ps.AddMacro("HAS_STENCIL_OUTPUT", static_cast<int>(shader.StencilOutput()));
sm_ps.AddMacro("HAS_INTEGER_OUTPUT", static_cast<int>(shader.IntegerOutputBpp() != 0));
sm_ps.AddMacro("HAS_DEPTH_INPUT", 0); // unused
sm_ps.AddMacro("HAS_DEPTH_OUTPUT", static_cast<int>(shader.DepthOutput()));
sm_ps.AddMacro("HAS_FLOAT32_INPUT", static_cast<int>(shader.Float32Input()));
sm_ps.AddMacro("HAS_FLOAT32_OUTPUT", static_cast<int>(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<PresentShader>(i)));
m_present.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, nullptr, ShaderEntryPoint(static_cast<PresentShader>(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<ID3D11RenderTargetView*>(*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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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
+18 -4
View File
@@ -182,7 +182,7 @@ private:
{
wil::com_ptr_nothrow<ID3D11InputLayout> il;
wil::com_ptr_nothrow<ID3D11VertexShader> vs;
wil::com_ptr_nothrow<ID3D11PixelShader> ps[static_cast<int>(ShaderConvert::Count)];
std::vector<wil::com_ptr_nothrow<ID3D11PixelShader>> ps;
wil::com_ptr_nothrow<ID3D11SamplerState> ln;
wil::com_ptr_nothrow<ID3D11SamplerState> pt;
wil::com_ptr_nothrow<ID3D11DepthStencilState> dss;
@@ -190,6 +190,16 @@ private:
std::array<wil::com_ptr_nothrow<ID3D11BlendState>, 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<ID3D11InputLayout> 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);
+18 -17
View File
@@ -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
}
+97 -128
View File
@@ -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<int>(shader)].get() : m_present[static_cast<int>(shader)].get();
pxAssert(dTex);
shader = ProcessShaderConvertSelector(shader); // Removes depth input
const bool allow_discard = (shader.Mask() == 0xf);
DoStretchRect(static_cast<GSTexture12*>(sTex), sRect, static_cast<GSTexture12*>(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<GSTexture12*>(sTex), sRect, nullptr, dRect,
m_present[static_cast<u32>(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<GSTexture12*>(sTex), GSVector4::zero(), static_cast<GSTexture12*>(dTex), dRect,
m_convert[static_cast<int>(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<GSTexture12*>(sTex), GSVector4::zero(), static_cast<GSTexture12*>(dTex), dRect,
m_convert[static_cast<int>(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<GSTexture12*>(sTex), GSVector4::zero(), static_cast<GSTexture12*>(dTex), dRect,
m_convert[static_cast<int>(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<int>(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<int>(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<int>(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<int>(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<ID3DBlob> 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<std::string> shader = ReadShaderSource("shaders/dx11/convert.fx");
if (!shader)
std::optional<std::string> 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<ShaderConvert>(static_cast<int>(i) + 1))
{
const bool depth = HasDepthOutput(i);
const int index = static_cast<int>(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<ID3DBlob> 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<int>(shader.Biln()));
sm.AddMacro("HAS_STENCIL_OUTPUT", static_cast<int>(shader.StencilOutput()));
sm.AddMacro("HAS_INTEGER_OUTPUT", static_cast<int>(shader.IntegerOutputBpp() != 0));
sm.AddMacro("HAS_DEPTH_INPUT", 0); // unused
sm.AddMacro("HAS_DEPTH_OUTPUT", static_cast<int>(shader.DepthOutput()));
sm.AddMacro("HAS_FLOAT32_INPUT", static_cast<int>(shader.Float32Input()));
sm.AddMacro("HAS_FLOAT32_OUTPUT", static_cast<int>(shader.Float32Output()));
sm.AddMacro(entry_point_macro.c_str(), 1);
ComPtr<ID3DBlob> 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<ID3D12PipelineState> 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<int>(i)));
D3D12::SetObjectName(pipe.get(),
TinyString::from_format("Convert pipeline ({}, mask={:x}, depth={}, biln={})",
shader.Name(), shader.Mask(), static_cast<int>(shader.DepthOutput()),
static_cast<int>(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<u8>(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<u8>(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<ComPtr<ID3D12PipelineState>, 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<ID3DBlob> 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<ID3DBlob> 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<int>(i);
ComPtr<ID3DBlob> ps(GetUtilityPixelShader(*shader, shaderName(i)));
ComPtr<ID3DBlob> 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<int>(ShaderConvert::COPY)].get());
SetPipeline(GetConvertPipeline(ShaderConvert::COPY));
DrawStretchRect(GSVector4(0.0f, 0.0f, 1.0f, 1.0f),
GSVector4(0.0f, 0.0f, static_cast<float>(dst_width), static_cast<float>(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<u8>(config.datm)].get());
SetPipeline(m_primid_image_setup_pipelines[pipe.ds][static_cast<u8>(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());
+22 -7
View File
@@ -346,18 +346,27 @@ private:
std::unordered_map<u32, D3D12DescriptorHandle> m_samplers;
std::array<ComPtr<ID3D12PipelineState>, static_cast<int>(ShaderConvert::Count)> m_convert{};
std::vector<ComPtr<ID3D12PipelineState>> m_convert;
std::array<ComPtr<ID3D12PipelineState>, static_cast<int>(PresentShader::Count)> m_present{};
std::array<ComPtr<ID3D12PipelineState>, 32> m_color_copy{};
std::array<ComPtr<ID3D12PipelineState>, 2> m_merge{};
std::array<ComPtr<ID3D12PipelineState>, NUM_INTERLACE_SHADERS> m_interlace{};
std::array<ComPtr<ID3D12PipelineState>, 2> m_colclip_setup_pipelines{}; // [depth]
std::array<ComPtr<ID3D12PipelineState>, 2> m_colclip_finish_pipelines{}; // [depth]
std::array<std::array<ComPtr<ID3D12PipelineState>, 4>, 2> m_date_image_setup_pipelines{}; // [depth][datm]
std::array<std::array<ComPtr<ID3D12PipelineState>, 4>, 2> m_primid_image_setup_pipelines{}; // [depth][datm]
ComPtr<ID3D12PipelineState> m_fxaa_pipeline;
ComPtr<ID3D12PipelineState> m_shadeboost_pipeline;
ComPtr<ID3D12PipelineState> 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<u32, ComPtr<ID3DBlob>> m_tfx_vertex_shaders;
std::unordered_map<GSHWDrawConfig::PSSelector, ComPtr<ID3DBlob>, 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);
+1 -1
View File
@@ -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);
+8 -7
View File
@@ -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;
+34 -31
View File
@@ -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<float>((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(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<int>(vertical_size))) * ds->m_scale;
const int new_width = std::min(2048, std::max(t_size.x, static_cast<int>(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<float>(z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x), static_cast<float>(z_vertical_offset) / static_cast<float>(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<float>((real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(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<float>((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(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<int>(std::ceil(static_cast<float>(copy_size.x) * scale)),
static_cast<int>(std::ceil(static_cast<float>(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);
}
+142 -179
View File
@@ -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<int>(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<u32>(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<float>(((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<float>(c) * mult;
case ShaderConvert::RGBA8_TO_FLOAT16:
return static_cast<float>(c & 0x0000FFFF) * mult;
case ShaderConvert::RGBA8_TO_FLOAT24:
case 24:
pxAssert(src_bpp == 32);
return static_cast<float>(c & 0x00FFFFFF) * mult;
case ShaderConvert::RGBA8_TO_FLOAT32:
default:
return static_cast<float>(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<float>(r | g | b | a) * mult;
}
else
{
return static_cast<float>(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<u32>(d * 0x1p32);
if (dst_bpp == 16)
{
case ShaderConvert::FLOAT16_TO_RGB5A1:
{
const u32 cc = static_cast<u32>(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<u32>(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<u32>(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<int>(std::ceil(static_cast<float>(w) * scale));
const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(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<float>(m_unscaled_size.x), total_rect.y / static_cast<float>(m_unscaled_size.y), (total_rect.z + (1.0f / m_scale)) / static_cast<float>(m_unscaled_size.x), (total_rect.w + (1.0f / m_scale)) / static_cast<float>(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<float>(m_unscaled_size.x),
total_rect.y / static_cast<float>(m_unscaled_size.y),
(total_rect.z + (1.0f / m_scale)) / static_cast<float>(m_unscaled_size.x),
(total_rect.w + (1.0f / m_scale)) / static_cast<float>(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
{
+2 -2
View File
@@ -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);
+13 -4
View File
@@ -249,9 +249,8 @@ public:
// Functions and Pipeline States
MRCOwned<id<MTLComputePipelineState>> m_cas_pipeline[2];
MRCOwned<id<MTLRenderPipelineState>> m_convert_pipeline[static_cast<int>(ShaderConvert::Count)];
std::vector<MRCOwned<id<MTLRenderPipelineState>>> m_convert_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_present_pipeline[static_cast<int>(PresentShader::Count)];
MRCOwned<id<MTLRenderPipelineState>> m_convert_pipeline_copy_mask[1 << 5];
MRCOwned<id<MTLRenderPipelineState>> m_merge_pipeline[4];
MRCOwned<id<MTLRenderPipelineState>> m_interlace_pipeline[NUM_INTERLACE_SHADERS];
MRCOwned<id<MTLRenderPipelineState>> m_datm_pipeline[4];
@@ -265,6 +264,16 @@ public:
MRCOwned<id<MTLRenderPipelineState>> m_shadeboost_pipeline;
MRCOwned<id<MTLRenderPipelineState>> m_imgui_pipeline;
id<MTLRenderPipelineState> GetConvertPipeline(ShaderConvertSelector shader) const
{
return m_convert_pipeline[shader.Index()];
}
id<MTLRenderPipelineState> GetConvertPipeline(ShaderConvert shader) const
{
return m_convert_pipeline[ShaderConvertSelector(shader).Index()];
}
MRCOwned<id<MTLFunction>> m_hw_vs[6 << 3];
std::unordered_map<PSSelector, MRCOwned<id<MTLFunction>>> m_hw_ps;
std::unordered_map<PipelineSelectorMTL, MRCOwned<id<MTLRenderPipelineState>>> 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<MTLRenderPipelineState> 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)
+90 -114
View File
@@ -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<GSTextureMTL*>(color);
GSTextureMTL* md = static_cast<GSTextureMTL*>(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<int>(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<ShaderConvert>(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<PresentShader>(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<MTLRenderPipelineState> 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<MTLRenderPipelineState> pipeline;
if (HasVariableWriteMask(shader))
pipeline = m_convert_pipeline_copy_mask[GetShaderIndexForMask(shader, cms.wrgba)];
else
pipeline = m_convert_pipeline[static_cast<int>(shader)];
pxAssertRel(pipeline, fmt::format("No pipeline for {}", shaderName(shader)).c_str());
const LoadAction load_action = (shader.Mask() == 0xf) ? LoadAction::DontCareIfFull : LoadAction::Load;
id<MTLRenderPipelineState> 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<MTLRenderPipelineState> new_pipeline = wmask == 0xf ? m_convert_pipeline[static_cast<int>(shader)]
: m_convert_pipeline_copy_mask[GetShaderIndexForMask(shader, wmask)];
id<MTLRenderPipelineState> 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<MTLRenderPipelineState> pipeline = m_convert_pipeline[static_cast<int>(shader)];
id<MTLRenderPipelineState> pipeline = GetConvertPipeline(shader);
if (!pipeline)
[NSException raise:@"StretchRect Missing Pipeline" format:@"No pipeline for %d", static_cast<int>(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<MTLRenderPipelineState> pipeline = m_convert_pipeline[static_cast<int>(shader)];
id<MTLRenderPipelineState> pipeline = GetConvertPipeline(shader);
if (!pipeline)
[NSException raise:@"StretchRect Missing Pipeline" format:@"No pipeline for %d", static_cast<int>(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<GSTextureMTL*>(m_ds_as_rt_gstexture)->GetTexture();
@autoreleasepool
{
@@ -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,
+57 -52
View File
@@ -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<float> 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<float> color [[texture(GSMTLTextureIndexNonHW), function_constant(COLOR_IN)]];
depth2d<float> 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<half> 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 (&convert)(half4)>
float sample_maybe_biln(float2 coord)
{
if (BILN)
return sample_biln<convert>(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<rgba8_to_depth32>(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<rgba8_to_depth24>(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<rgba8_to_depth16>(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<rgba8_to_depth32>(data.t);
}
fragment DepthOut ps_convert_rgba8_float24_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
{
return res.sample_biln<rgba8_to_depth24>(data.t);
}
fragment DepthOut ps_convert_rgba8_float16_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
{
return res.sample_biln<rgba8_to_depth16>(data.t);
}
fragment DepthOut ps_convert_rgb5a1_float16_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
{
return res.sample_biln<rgb5a1_to_depth16>(data.t);
return res.sample_maybe_biln<rgb5a1_to_depth16>(data.t);
}
fragment float4 ps_convert_rgb5a1_8i(ConvertShaderData data [[stage_in]], DirectReadTextureIn<float> res,
+62 -40
View File
@@ -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<ShaderConvert>(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<ShaderConvert>(i) == ShaderConvert::RGBA_TO_8I || static_cast<ShaderConvert>(i) == ShaderConvert::RGB5A1_TO_8I)
const char* name = shader.EntryPoint();
std::string macro;
macro += fmt::format("#define HAS_BILN {}\n", static_cast<int>(shader.Biln()));
macro += fmt::format("#define HAS_STENCIL_OUTPUT {}\n", static_cast<int>(shader.StencilOutput()));
macro += fmt::format("#define HAS_INTEGER_OUTPUT {}\n", static_cast<int>(shader.IntegerOutputBpp() != 0));
macro += fmt::format("#define HAS_DEPTH_INPUT {}\n", 0); // unused
macro += fmt::format("#define HAS_DEPTH_OUTPUT {}\n", static_cast<int>(shader.DepthOutput()));
macro += fmt::format("#define HAS_FLOAT32_INPUT {}\n", static_cast<int>(shader.Float32Input()));
macro += fmt::format("#define HAS_FLOAT32_OUTPUT {}\n", static_cast<int>(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<int>(shader.DepthOutput()),
static_cast<int>(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<ShaderConvert>(i) == ShaderConvert::YUV)
else if (shader.Shader() == ShaderConvert::YUV)
{
m_convert.ps[i].RegisterUniform("EMOD");
prog.RegisterUniform("EMOD");
}
else if (static_cast<ShaderConvert>(i) == ShaderConvert::CLUT_4 || static_cast<ShaderConvert>(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<ShaderConvert>(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<PresentShader>(i));
const char* name = ShaderEntryPoint(static_cast<PresentShader>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(shader)].Bind();
GetConvertProgram(shader).Bind();
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(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<int>(ShaderConvert::YUV)].Bind();
m_convert.ps[static_cast<int>(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
+18 -4
View File
@@ -182,13 +182,23 @@ private:
struct
{
std::string vs;
GLProgram ps[static_cast<int>(ShaderConvert::Count)]; // program object
std::vector<GLProgram> 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<int>(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;
+1 -1
View File
@@ -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;
+100 -143
View File
@@ -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<int>(format)] :
VK_FORMAT_D32_SFLOAT;
s_format_mapping[static_cast<int>(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<false>(ca.clearValue.color.float32, sTexVK->GetUNormClearColor());
GSVector4::store<false>(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<int>(shader)] : m_present[static_cast<int>(shader)];
DoStretchRect(static_cast<GSTextureVK*>(sTex), sRect, static_cast<GSTextureVK*>(dTex), dRect, state, linear, allow_discard);
pxAssert(dTex);
shader = ProcessShaderConvertSelector(shader); // Removes depth input
const bool allow_discard = (shader.Mask() == 0xf);
DoStretchRect(static_cast<GSTextureVK*>(sTex), sRect, static_cast<GSTextureVK*>(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<GSTextureVK*>(sTex), sRect, nullptr, dRect,
m_present.at(static_cast<u32>(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<int>(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<GSTextureVK*>(sTex), GSVector4::zero(), static_cast<GSTextureVK*>(dTex), dRect,
m_convert[static_cast<int>(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<GSTextureVK*>(sTex), GSVector4::zero(), static_cast<GSTextureVK*>(dTex), dRect,
m_convert[static_cast<int>(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<GSTextureVK*>(sTex), GSVector4::zero(), static_cast<GSTextureVK*>(dTex), dRect,
m_convert[static_cast<int>(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<int>(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<GSTextureVK*>(sTex[2]), fbarea, GSVector4i(dRect[2]));
if (dcleared)
{
SetPipeline(m_convert[static_cast<int>(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<int>(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<false>(ca.clearValue.color.float32, vkRt->GetUNormClearColor());
GSVector4::store<false>(ca.clearValue.color.float32, vkRt->GetClearForFormat());
}
vkRt->SetState(GSTexture::State::Dirty);
@@ -4005,14 +4005,14 @@ bool GSDeviceVK::CreateRenderPasses()
bool GSDeviceVK::CompileConvertPipelines()
{
const std::optional<std::string> shader = ReadShaderSource("shaders/vulkan/convert.glsl");
if (!shader)
const std::optional<std::string> 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<ShaderConvert>(static_cast<int>(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<int>(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<int>(shader.Biln()));
macro += fmt::format("#define HAS_STENCIL_OUTPUT {}\n", static_cast<int>(shader.StencilOutput()));
macro += fmt::format("#define HAS_INTEGER_OUTPUT {}\n", static_cast<int>(shader.IntegerOutputBpp() != 0));
macro += fmt::format("#define HAS_DEPTH_INPUT {}\n", 0); // unused
macro += fmt::format("#define HAS_DEPTH_OUTPUT {}\n", static_cast<int>(shader.DepthOutput()));
macro += fmt::format("#define HAS_FLOAT32_INPUT {}\n", static_cast<int>(shader.Float32Input()));
macro += fmt::format("#define HAS_FLOAT32_OUTPUT {}\n", static_cast<int>(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<int>(shader.DepthOutput()),
static_cast<int>(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<VkColorComponentFlags>(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<VkColorComponentFlags>(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<int>(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<GSTextureVK*>(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<u8>(config.datm)];
const VkPipeline pipeline = m_primid_image_setup_pipelines[ds][static_cast<u8>(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<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
GSVector4::store<true>(&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<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetClearForFormat());
if (draw_ds)
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
+23 -8
View File
@@ -398,18 +398,27 @@ private:
std::unordered_map<u32, VkSampler> m_samplers;
std::array<VkPipeline, static_cast<int>(ShaderConvert::Count)> m_convert{};
std::vector<VkPipeline> m_convert;
std::array<VkPipeline, static_cast<int>(PresentShader::Count)> m_present{};
std::array<VkPipeline, 32> m_color_copy{};
std::array<VkPipeline, 2> m_merge{};
std::array<VkPipeline, NUM_INTERLACE_SHADERS> 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<u32, VkShaderModule> m_tfx_vertex_shaders;
std::unordered_map<GSHWDrawConfig::PSSelector, VkShaderModule, GSHWDrawConfig::PSSelectorHash>
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);
+1 -1
View File
@@ -550,7 +550,7 @@ void GSTextureVK::CommitClear(VkCommandBuffer cmdbuf)
else
{
alignas(16) VkClearColorValue cv;
GSVector4::store<true>(cv.float32, GetUNormClearColor());
GSVector4::store<true>(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);
}
+1 -1
View File
@@ -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