diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 4b62f48c14..8d6917fd6a 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -145,11 +145,28 @@ protected: return 1; } + inline void UpdateEverUsedEqualDepth(GEComparison comp) { + switch (comp) { + case GE_COMP_EQUAL: + case GE_COMP_NOTEQUAL: + case GE_COMP_LEQUAL: + case GE_COMP_GEQUAL: + everUsedEqualDepth_ = true; + break; + + default: + break; + } + } + bool useHWTransform_ = false; bool useHWTessellation_ = false; // Used to prevent unnecessary flushing in softgpu. bool flushOnParams_ = true; + // Set once a equal depth test is encountered. + bool everUsedEqualDepth_ = false; + // Vertex collector buffers u8 *decoded = nullptr; u16 *decIndex = nullptr; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index e0c33e5d76..9ef139486f 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -643,6 +643,10 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(result.setStencil, result.stencilValue); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index efbbcad31b..c840265540 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -274,6 +274,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { keys_.depthStencil.depthTestEnable = true; keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { keys_.depthStencil.depthTestEnable = false; keys_.depthStencil.depthWriteEnable = false; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 33117be1c9..1e6bd62d61 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -611,6 +611,10 @@ rotateVBO: swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(); diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 951a401189..b6918027f8 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -232,6 +232,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { dxstate.depthTest.enable(); dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]); dxstate.depthWrite.set(gstate.isDepthWriteEnabled()); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { dxstate.depthTest.disable(); } diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index e95afe57ed..2c0c54304d 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -404,6 +404,10 @@ void DrawEngineGLES::DoFlush() { swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, maxIndex, &result); if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; ApplyDrawStateLate(result.setStencil, result.stencilValue); diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index f80a3f5490..0330cdf9f6 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -254,6 +254,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) { } else { // Depth Test renderManager->SetDepth(gstate.isDepthTestEnabled(), gstate.isDepthWriteEnabled(), compareOps[gstate.getDepthTestFunction()]); + if (gstate.isDepthTestEnabled()) + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); // Stencil Test if (stencilState.enabled) { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index de81929a32..c1d1871140 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -899,6 +899,10 @@ void DrawEngineVulkan::DoFlush() { if (result.setSafeSize) framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); + // Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values. + // Games sometimes expect exact matches (see #12626, for example) for equal comparisons. + if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f) + result.action = SW_DRAW_PRIMITIVES; // Only here, where we know whether to clear or to draw primitives, should we actually set the current framebuffer! Because that gives use the opportunity // to use a "pre-clear" render pass, for high efficiency on tilers. diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 9e2177b901..7c23c67126 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -278,6 +278,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag key.depthTestEnable = true; key.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; key.depthWriteEnable = gstate.isDepthWriteEnabled(); + UpdateEverUsedEqualDepth(gstate.getDepthTestFunction()); } else { key.depthTestEnable = false; key.depthWriteEnable = false;