From 3aa863ec4141955eb5d0b1bffe64dfe00b127cde Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 6 Oct 2022 00:34:02 -0700 Subject: [PATCH] GPU: Clip against neg Z even w/o cull support. This should fix rendering issues on Apple devices. --- GPU/Common/VertexShaderGenerator.cpp | 29 +++++++++++++++------------- GPU/GPUCommon.cpp | 9 +++++---- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 658cbb27f6..24f118603f 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -1287,19 +1287,22 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (vertexRangeCulling && !IsVRBuild()) { WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n"); WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n"); - // Vertex range culling doesn't happen when Z clips, note sign of w is important. - WRITE(p, " if (u_cullRangeMin.w <= 0.0 || projZ * outPos.w > -outPos.w) {\n"); - const char *outMin = "projPos.x < u_cullRangeMin.x || projPos.y < u_cullRangeMin.y"; - const char *outMax = "projPos.x > u_cullRangeMax.x || projPos.y > u_cullRangeMax.y"; - WRITE(p, " if ((%s) || (%s)) {\n", outMin, outMax); - WRITE(p, " outPos.xyzw = u_cullRangeMax.wwww;\n"); - WRITE(p, " }\n"); - WRITE(p, " }\n"); - WRITE(p, " if (u_cullRangeMin.w <= 0.0) {\n"); - WRITE(p, " if (projPos.z < u_cullRangeMin.z || projPos.z > u_cullRangeMax.z) {\n"); - WRITE(p, " outPos.xyzw = u_cullRangeMax.wwww;\n"); - WRITE(p, " }\n"); - WRITE(p, " }\n"); + + if (!bugs.Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) { + // Vertex range culling doesn't happen when Z clips, note sign of w is important. + WRITE(p, " if (u_cullRangeMin.w <= 0.0 || projZ * outPos.w > -outPos.w) {\n"); + const char *outMin = "projPos.x < u_cullRangeMin.x || projPos.y < u_cullRangeMin.y"; + const char *outMax = "projPos.x > u_cullRangeMax.x || projPos.y > u_cullRangeMax.y"; + WRITE(p, " if ((%s) || (%s)) {\n", outMin, outMax); + WRITE(p, " outPos.xyzw = u_cullRangeMax.wwww;\n"); + WRITE(p, " }\n"); + WRITE(p, " }\n"); + WRITE(p, " if (u_cullRangeMin.w <= 0.0) {\n"); + WRITE(p, " if (projPos.z < u_cullRangeMin.z || projPos.z > u_cullRangeMax.z) {\n"); + WRITE(p, " outPos.xyzw = u_cullRangeMax.wwww;\n"); + WRITE(p, " }\n"); + WRITE(p, " }\n"); + } const char *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]"; const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]"; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 7c6e7620eb..9830984739 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -3305,10 +3305,11 @@ u32 GPUCommon::CheckGPUFeatures() const { features |= GPU_SUPPORTS_DEPTH_TEXTURE; } - if (!draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) { - if (draw_->GetDeviceCaps().clipDistanceSupported && draw_->GetDeviceCaps().cullDistanceSupported) { - features |= GPU_SUPPORTS_VS_RANGE_CULLING; - } + bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported; + bool canDiscardVertex = draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL); + if (canClipOrCull || canDiscardVertex) { + // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible. + features |= GPU_SUPPORTS_VS_RANGE_CULLING; } if (draw_->GetDeviceCaps().framebufferFetchSupported) {