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.
This commit is contained in:
baldurk
2025-10-12 16:22:06 +01:00
parent cf42a3ea5c
commit 7ef6d5d3e0
3 changed files with 57 additions and 7 deletions
+10 -1
View File
@@ -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.
+9
View File
@@ -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
{
+38 -6
View File
@@ -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 = {};