From 7ef6d5d3e091343bddcd440f7aafe4ba6bda7cbd Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 12 Oct 2025 16:22:06 +0100 Subject: [PATCH] If there's no depth attachment, disable depth testing during history * When we add a depth attachment we want to ensure this doesn't "activate" a dormant depth test/bounds state which was inactive before due to the lack of an attachment, so turn them off explicitly in our replacement pipelines. --- renderdoc/driver/d3d12/d3d12_pixelhistory.cpp | 11 ++++- renderdoc/driver/gl/gl_pixelhistory.cpp | 9 ++++ renderdoc/driver/vulkan/vk_pixelhistory.cpp | 44 ++++++++++++++++--- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp b/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp index e7bf445c6..621822cb4 100644 --- a/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp +++ b/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp @@ -2102,7 +2102,8 @@ struct D3D12PixelHistoryPerFragmentCallback : D3D12PixelHistoryCallback colorCopyParams.arraySlice = m_CallbackInfo.targetSubresource.slice; colorCopyParams.scratchBuffer = true; - bool depthEnabled = origPipeDesc.DepthStencilState.DepthEnable != FALSE; + bool depthEnabled = + state.GetDSVID() != ResourceId() && origPipeDesc.DepthStencilState.DepthEnable != FALSE; D3D12MarkerRegion::Set( cmd, StringFormat::Fmt("Event %u has %u fragments", eid, numFragmentsInEvent)); @@ -2342,6 +2343,14 @@ struct D3D12PixelHistoryPerFragmentCallback : D3D12PixelHistoryCallback pipeDesc.DepthStencilState.BackFace = pipeDesc.DepthStencilState.FrontFace; } + // if there was no depth attachment before these were implicitly disabled, so ensure we don't + // run them now that we've inserted a depth attachment for stencil counting + if(state.GetDSVID() == ResourceId()) + { + pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; + pipeDesc.DepthStencilState.DepthBoundsTestEnable = FALSE; + } + // TODO: The original pixel shader may have side effects such as UAV writes. The Vulkan impl // removes side effects with shader patching but D3D12 does not support that yet. diff --git a/renderdoc/driver/gl/gl_pixelhistory.cpp b/renderdoc/driver/gl/gl_pixelhistory.cpp index 6b04a7e85..7a59239d9 100644 --- a/renderdoc/driver/gl/gl_pixelhistory.cpp +++ b/renderdoc/driver/gl/gl_pixelhistory.cpp @@ -1708,6 +1708,15 @@ void QueryPostModPerFragment(WrappedOpenGL *driver, GLReplay *replay, &curStencilLevel); } + // if we didn't have a depth buffer, turn off depth testing so we don't have to worry about + // incorrect depth failures with our forced depth + if(!curDepth) + { + if(HasExt[EXT_depth_bounds_test]) + driver->glDisable(eGL_DEPTH_BOUNDS_TEST_EXT); + driver->glDepthFunc(eGL_ALWAYS); + } + GLuint forcedDepth = 0; // replace depth and clear it to premod value { diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index 58b91c039..9e7449736 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -1079,6 +1079,28 @@ protected: dynState->dynamicStateCount = (uint32_t)m_DynamicStates.size(); } + bool HasDepthAttachment(const VulkanRenderState &pipestate) + { + if(pipestate.dynamicRendering.active) + { + const VulkanRenderState::DynamicRendering &dyn = pipestate.dynamicRendering; + + return dyn.depth.imageView != VK_NULL_HANDLE; + } + + ResourceId rp = pipestate.GetRenderPass(); + + const VulkanCreationInfo::RenderPass &rpInfo = + m_pDriver->GetDebugManager()->GetRenderPassInfo(rp); + + // TODO: this should retrieve the correct subpass, once multiple subpasses + // are supported. + // Currently only single subpass render passes are supported. + const VulkanCreationInfo::RenderPass::Subpass &sub = rpInfo.subpasses.front(); + + return (sub.depthstencilAttachment != -1); + } + // PatchRenderPass creates a new VkRenderPass based on the original that has a separate // depth-stencil attachment, and covers a single subpass. This will be used to replay a single // draw. The new renderpass also replaces the depth stencil attachment, so it can be used to count @@ -3120,6 +3142,8 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback } } + const bool hadDepthAttachment = HasDepthAttachment(state); + bool multiview = false; VkRenderPass origRpWithDepth = PatchRenderPass(state, multiview); state.SetRenderPass(prevState.GetRenderPass()); @@ -3134,8 +3158,8 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback if(!prevState.graphics.shaderObject) { - pipes = CreatePerFragmentPipelines(curPipeline, newRp, origRpWithDepth, eid, 0, - VK_FORMAT_R32G32B32A32_SFLOAT, colorOutputIndex); + pipes = CreatePerFragmentPipelines(curPipeline, newRp, origRpWithDepth, hadDepthAttachment, + eid, 0, VK_FORMAT_R32G32B32A32_SFLOAT, colorOutputIndex); } else { @@ -3171,7 +3195,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback colourCopyParams.srcImageLayout = srcImageLayout; } - bool depthEnabled = prevState.depthTestEnable != VK_FALSE; + bool depthEnabled = hadDepthAttachment && prevState.depthTestEnable != VK_FALSE; VkMarkerRegion::Set(StringFormat::Fmt("Event %u has %u fragments", eid, numFragmentsInEvent), cmd); @@ -3296,7 +3320,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback else { // second pass - blending OFF, to get shader output value - state.depthTestEnable = prevState.depthTestEnable; + state.depthTestEnable = depthEnabled ? VK_TRUE : VK_FALSE; state.depthWriteEnable = true; } } @@ -3416,7 +3440,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback state.colorBlendEnable = prevState.colorBlendEnable; state.colorWriteMask = prevState.colorWriteMask; - state.depthTestEnable = prevState.depthTestEnable; + state.depthTestEnable = depthEnabled ? VK_TRUE : VK_FALSE; state.depthWriteEnable = prevState.depthWriteEnable; state.depthCompareOp = prevState.depthCompareOp; @@ -3495,7 +3519,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback void PostRedraw(uint32_t eid, ActionFlags flags, VkCommandBuffer cmd) {} // CreatePerFragmentPipelines for getting per fragment information. Pipelines CreatePerFragmentPipelines(ResourceId pipe, VkRenderPass rp, VkRenderPass origRpWithDepth, - uint32_t eid, uint32_t fragmentIndex, + bool hadDepthAttachment, uint32_t eid, uint32_t fragmentIndex, VkFormat colorOutputFormat, uint32_t colorOutputIndex) { const VulkanCreationInfo::Pipeline &p = m_pDriver->GetDebugManager()->GetPipelineInfo(pipe); @@ -3579,6 +3603,14 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback } pipeCreateInfo.pStages = stages.data(); + // if there was no depth attachment before these were implicitly disabled, so ensure we don't + // run them now that we've inserted a depth attachment for stencil counting + if(!hadDepthAttachment) + { + ds->depthTestEnable = VK_FALSE; + ds->depthBoundsTestEnable = VK_FALSE; + } + // the postmod pipe is used with the renderpass with added depth/stencil pipeCreateInfo.renderPass = origRpWithDepth; Pipelines pipes = {};