GS/HW: Improve ROV discard behavior.

Try to avoid color/depth write when it's discarded.
This commit is contained in:
TJnotJT
2026-06-28 21:14:04 -04:00
committed by lightningterror
parent 05015bc476
commit 017b4d07da
3 changed files with 62 additions and 64 deletions
+43 -49
View File
@@ -192,7 +192,7 @@ struct PS_INPUT
#ifdef PIXEL_SHADER
struct PS_OUTPUT_REAL
struct PS_OUTPUT
{
#define NUM_RTS 0
@@ -231,20 +231,6 @@ struct PS_OUTPUT_REAL
#undef NUM_RTS
};
struct PS_OUTPUT
{
#if !PS_NO_COLOR
#if PS_DATE == 1 || PS_DATE == 2
float c;
#else
float4 c0;
#if !PS_NO_COLOR1
float4 c1;
#endif
#endif
#endif
};
Texture2D<float4> Texture : register(t0);
Texture2D<float4> Palette : register(t1);
#if !PS_ROV_COLOR
@@ -1326,13 +1312,17 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
#define DISCARD rov_discard = true
#define DISCARD { rov_discard_color = true; rov_discard_depth = true; }
#define DISCARD_COLOR rov_discard_color = true
#define DISCARD_DEPTH rov_discard_depth = true
#else
#define DISCARD discard
#define DISCARD discard
#define DISCARD_COLOR o_col0 = RtLoad(input.p.xy)
#define DISCARD_DEPTH input.p.z = DepthLoad(input.p.xy)
#endif
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
PS_OUTPUT_REAL ps_main(PS_INPUT input)
PS_OUTPUT ps_main(PS_INPUT input)
#else
void ps_main(PS_INPUT input)
#endif
@@ -1351,7 +1341,8 @@ void ps_main(PS_INPUT input)
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
bool rov_discard = false;
bool rov_discard_color = false;
bool rov_discard_depth = false;
#endif
// Use ROV discard macro for since we cannot do
@@ -1458,19 +1449,29 @@ if (bad)
discard;
#endif
PS_OUTPUT output;
// Output values
#if !PS_NO_COLOR
#if PS_DATE == 1 || PS_DATE == 2
float o_col0;
#else
float4 o_col0;
#if !PS_NO_COLOR1
float4 o_col1;
#endif
#endif
#endif
// Get first primitive that will write a failling alpha value
#if PS_DATE == 1
// DATM == 0
// Pixel with alpha equal to 1 will failed (128-255)
output.c = (C.a > 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
o_col0 = (C.a > 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
#elif PS_DATE == 2
// DATM == 1
// Pixel with alpha equal to 0 will failed (0-127)
output.c = (C.a < 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
o_col0 = (C.a < 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
#else
// Not primid DATE setup
@@ -1547,26 +1548,26 @@ if (bad)
// Output color scaling
#if !PS_NO_COLOR
output.c0.a = PS_RTA_CORRECTION ? C.a / 128.0f : C.a / 255.0f;
output.c0.rgb = PS_COLCLIP_HW ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
o_col0.a = PS_RTA_CORRECTION ? C.a / 128.0f : C.a / 255.0f;
o_col0.rgb = PS_COLCLIP_HW ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
#if !PS_NO_COLOR1
output.c1 = alpha_blend;
o_col1 = alpha_blend;
#endif
#endif // !PS_NO_COLOR
// Alpha test with feedback
#if PS_AFAIL == AFAIL_FB_ONLY
if (!atst_pass)
input.p.z = DepthLoad(input.p.xy);
DISCARD_DEPTH;
#elif PS_AFAIL == AFAIL_ZB_ONLY
if (!atst_pass)
output.c0 = RtLoad(input.p.xy);
DISCARD_COLOR;
#elif PS_AFAIL == AFAIL_RGB_ONLY || PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
if (!atst_pass)
{
output.c0.a = RtLoad(input.p.xy).a;
o_col0.a = RtLoad(input.p.xy).a; // discard alpha
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
input.p.z = DepthLoad(input.p.xy);
DISCARD_DEPTH;
#endif
}
#endif
@@ -1579,46 +1580,39 @@ if (bad)
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
if (!bool(input.interior))
input.p.z = DepthLoad(input.p.xy); // No depth update for triangle edges.
DISCARD_DEPTH; // No depth update for triangle edges.
#endif
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
// Output struct with the actual system values output semantics.
PS_OUTPUT_REAL output_real;
PS_OUTPUT output;
#endif
// Color write back
#if PS_RETURN_COLOR
#if PS_DATE == 1 || PS_DATE == 2
output_real.c = output.c;
#else
output_real.c0 = output.c0;
#if !PS_NO_COLOR1
output_real.c1 = output.c1;
#endif
output.c0 = o_col0;
#if !PS_NO_COLOR1
output.c1 = o_col1;
#endif
#elif PS_RETURN_COLOR_ROV
output.c0 = (rov_discard | (FbMask == 0xFFu)) ? RtLoad(input.p.xy) : output.c0;
RtWrite(input.p.xy, output.c0);
o_col0 = (FbMask == 0xFFu) ? RtLoad(input.p.xy) : o_col0; // channel masking
if (!rov_discard_color)
RtWrite(input.p.xy, o_col0);
#endif
// Depth write back
#if PS_RETURN_DEPTH
output_real.depth = input.p.z;
output.depth = input.p.z;
#if SW_DEPTH && PS_NO_COLOR1 && PS_DEPTH_FEEDBACK_SUPPORT == 2
// Output color clone for feedback.
output_real.depth_color = input.p.z;
output.depth_color = input.p.z;
#endif
#elif PS_RETURN_DEPTH_ROV
#if SW_DEPTH
input.p.z = rov_discard ? DepthLoad(input.p.xy) : input.p.z;
#endif
DepthWrite(input.p.xy, input.p.z);
if (!rov_discard_depth)
DepthWrite(input.p.xy, input.p.z);
#endif
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
return output_real;
return output;
#endif
}
+18 -14
View File
@@ -1720,9 +1720,13 @@ layout(early_fragment_tests) in;
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
#define DISCARD rov_discard = true
#define DISCARD { rov_discard_color = true; rov_discard_depth = true; }
#define DISCARD_COLOR rov_discard_color = true
#define DISCARD_DEPTH rov_discard_depth = true
#else
#define DISCARD discard
#define DISCARD discard
#define DISCARD_COLOR o_col0 = sample_from_rt()
#define DISCARD_DEPTH input_z = sample_from_depth()
#endif
void main()
@@ -1747,7 +1751,8 @@ void main()
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
bool rov_discard = gl_HelperInvocation;
bool rov_discard_color = gl_HelperInvocation;
bool rov_discard_depth = gl_HelperInvocation;
#endif
#if PS_ZTST == ZTST_GEQUAL
@@ -1940,16 +1945,16 @@ void main()
// Alpha test with feedback
#if PS_AFAIL == AFAIL_FB_ONLY
if (!atst_pass)
input_z = sample_from_depth();
DISCARD_DEPTH;
#elif PS_AFAIL == AFAIL_ZB_ONLY
if (!atst_pass)
o_col0 = sample_from_rt();
DISCARD_COLOR;
#elif (PS_AFAIL == AFAIL_RGB_ONLY || PS_AFAIL == AFAIL_RGB_ONLY_SW_Z)
if (!atst_pass)
{
o_col0.a = sample_from_rt().a;
o_col0.a = sample_from_rt().a; // discard alpha
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
input_z = sample_from_depth();
DISCARD_DEPTH;
#endif
}
#endif
@@ -1961,24 +1966,23 @@ void main()
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
if (!bool(vsIn.interior))
input_z = sample_from_depth(); // No depth update for triangle edges.
DISCARD_DEPTH; // No depth update for triangle edges.
#endif
// Writing back color (result already written to o_col0 for non-ROV)
#if PS_RETURN_COLOR_ROV
bvec4 discard_channels = bvec4(uvec4(rov_discard) | uvec4(equal(FbMask, uvec4(0xFFu))));
o_col0 = mix(o_col0, sample_from_rt(), discard_channels);
o_col0 = mix(o_col0, sample_from_rt(), equal(FbMask, uvec4(0xFFu))); // channel masking
imageStore(RtImageRov, ivec2(gl_FragCoord.xy), o_col0);
if (!rov_discard_color)
imageStore(RtImageRov, ivec2(gl_FragCoord.xy), o_col0);
#endif
// Writing back depth
#if PS_RETURN_DEPTH
gl_FragDepth = input_z;
#elif PS_RETURN_DEPTH_ROV
input_z = rov_discard ? sample_from_depth() : input_z;
imageStore(DepthImageRov, ivec2(gl_FragCoord.xy), vec4(input_z, 0, 0, 1.0f));
if (!rov_discard_depth)
imageStore(DepthImageRov, ivec2(gl_FragCoord.xy), vec4(input_z, 0, 0, 1.0f));
#endif
#if PS_ROV_COLOR || PS_ROV_DEPTH
+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 = 105; // Last changed in PR 14465
static constexpr u32 SHADER_CACHE_VERSION = 106; // Last changed in PR 14643