From f6babe77fdc2c0e31e2dc9a305569aa80825db55 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 20 Jul 2020 16:07:36 +0100 Subject: [PATCH] Handle depth clipping and depth bounds failure separately * This prevents truly depth-clipped fragments from being wrongly reported as other failures like backface culling. --- qrenderdoc/Windows/PixelHistoryView.cpp | 2 + renderdoc/api/replay/data_types.h | 16 +++-- renderdoc/driver/vulkan/vk_pixelhistory.cpp | 69 ++++++++++++++------- renderdoc/replay/renderdoc_serialise.inl | 1 + util/test/demos/vk/vk_pixel_history.cpp | 28 ++++++++- util/test/tests/Vulkan/VK_Pixel_History.py | 57 +++++++++++++++++ 6 files changed, 146 insertions(+), 27 deletions(-) diff --git a/qrenderdoc/Windows/PixelHistoryView.cpp b/qrenderdoc/Windows/PixelHistoryView.cpp index 6ef3d5fa7..3aa910e37 100644 --- a/qrenderdoc/Windows/PixelHistoryView.cpp +++ b/qrenderdoc/Windows/PixelHistoryView.cpp @@ -580,6 +580,8 @@ private: s += tr("\nBackface culled"); if(mod.depthClipped) s += tr("\nDepth Clipped"); + if(mod.depthBoundsFailed) + s += tr("\nDepth bounds test failed"); if(mod.scissorClipped) s += tr("\nScissor Clipped"); if(mod.shaderDiscarded) diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 47cb8bd56..19953f200 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -1797,9 +1797,10 @@ struct PixelModification unboundPS == o.unboundPS && fragIndex == o.fragIndex && primitiveID == o.primitiveID && preMod == o.preMod && shaderOut == o.shaderOut && postMod == o.postMod && sampleMasked == o.sampleMasked && backfaceCulled == o.backfaceCulled && - depthClipped == o.depthClipped && viewClipped == o.viewClipped && - scissorClipped == o.scissorClipped && shaderDiscarded == o.shaderDiscarded && - depthTestFailed == o.depthTestFailed && stencilTestFailed == o.stencilTestFailed; + depthClipped == o.depthClipped && depthBoundsFailed == o.depthBoundsFailed && + viewClipped == o.viewClipped && scissorClipped == o.scissorClipped && + shaderDiscarded == o.shaderDiscarded && depthTestFailed == o.depthTestFailed && + stencilTestFailed == o.stencilTestFailed; } bool operator<(const PixelModification &o) const { @@ -1825,6 +1826,8 @@ struct PixelModification return backfaceCulled < o.backfaceCulled; if(!(depthClipped == o.depthClipped)) return depthClipped < o.depthClipped; + if(!(depthBoundsFailed == o.depthBoundsFailed)) + return depthBoundsFailed < o.depthBoundsFailed; if(!(viewClipped == o.viewClipped)) return viewClipped < o.viewClipped; if(!(scissorClipped == o.scissorClipped)) @@ -1871,6 +1874,8 @@ pixel. bool backfaceCulled; DOCUMENT("``True`` if depth near/far clipping eliminated this fragment."); bool depthClipped; + DOCUMENT("``True`` if depth bounds clipping eliminated this fragment."); + bool depthBoundsFailed; DOCUMENT("``True`` if viewport clipping eliminated this fragment."); bool viewClipped; DOCUMENT("``True`` if scissor clipping eliminated this fragment."); @@ -1891,8 +1896,9 @@ pixel. )"); bool Passed() const { - return !sampleMasked && !backfaceCulled && !depthClipped && !viewClipped && !scissorClipped && - !shaderDiscarded && !depthTestFailed && !stencilTestFailed && !predicationSkipped; + return !sampleMasked && !backfaceCulled && !depthClipped && !depthBoundsFailed && + !viewClipped && !scissorClipped && !shaderDiscarded && !depthTestFailed && + !stencilTestFailed && !predicationSkipped; } }; diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index ed3efae4b..89393bce4 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -117,22 +117,23 @@ bool isDirectWrite(ResourceUsage usage) enum : uint32_t { - TestEnabled_Culling = 1 << 0, - TestEnabled_Scissor = 1 << 1, - TestEnabled_SampleMask = 1 << 2, - TestEnabled_DepthBounds = 1 << 3, - TestEnabled_StencilTesting = 1 << 4, - TestEnabled_DepthTesting = 1 << 5, - TestEnabled_FragmentDiscard = 1 << 6, + TestEnabled_DepthClipping = 1 << 0, + TestEnabled_Culling = 1 << 1, + TestEnabled_Scissor = 1 << 2, + TestEnabled_SampleMask = 1 << 3, + TestEnabled_DepthBounds = 1 << 4, + TestEnabled_StencilTesting = 1 << 5, + TestEnabled_DepthTesting = 1 << 6, + TestEnabled_FragmentDiscard = 1 << 7, - Blending_Enabled = 1 << 7, - UnboundFragmentShader = 1 << 8, - TestMustFail_Culling = 1 << 9, - TestMustFail_Scissor = 1 << 10, - TestMustPass_Scissor = 1 << 11, - TestMustFail_DepthTesting = 1 << 12, - TestMustFail_StencilTesting = 1 << 13, - TestMustFail_SampleMask = 1 << 14, + Blending_Enabled = 1 << 8, + UnboundFragmentShader = 1 << 9, + TestMustFail_Culling = 1 << 10, + TestMustFail_Scissor = 1 << 11, + TestMustPass_Scissor = 1 << 12, + TestMustFail_DepthTesting = 1 << 13, + TestMustFail_StencilTesting = 1 << 14, + TestMustFail_SampleMask = 1 << 15, DepthTest_Shift = 29, DepthTest_Always = 0U << DepthTest_Shift, @@ -1781,6 +1782,9 @@ private: // Culling { + if(p.depthClipEnable && !p.depthClampEnable) + flags |= TestEnabled_DepthClipping; + if(pipestate.cullMode != VK_CULL_MODE_NONE) flags |= TestEnabled_Culling; @@ -1912,8 +1916,9 @@ private: PipelineCreationFlags_DisableDepthTest = 1 << 1, PipelineCreationFlags_DisableStencilTest = 1 << 2, PipelineCreationFlags_DisableDepthBoundsTest = 1 << 3, - PipelineCreationFlags_FixedColorShader = 1 << 4, - PipelineCreationFlags_IntersectOriginalScissor = 1 << 5, + PipelineCreationFlags_DisableDepthClipping = 1 << 4, + PipelineCreationFlags_FixedColorShader = 1 << 5, + PipelineCreationFlags_IntersectOriginalScissor = 1 << 6, }; void ReplayDrawWithTests(VkCommandBuffer cmd, uint32_t eid, uint32_t eventFlags, @@ -1949,13 +1954,24 @@ private: if(eventFlags & TestEnabled_Culling) { uint32_t pipeFlags = - PipelineCreationFlags_DisableDepthTest | PipelineCreationFlags_DisableDepthBoundsTest | - PipelineCreationFlags_DisableStencilTest | PipelineCreationFlags_FixedColorShader; + PipelineCreationFlags_DisableDepthTest | PipelineCreationFlags_DisableDepthClipping | + PipelineCreationFlags_DisableDepthBoundsTest | PipelineCreationFlags_DisableStencilTest | + PipelineCreationFlags_FixedColorShader; VkPipeline pipe = CreatePipeline(basePipeline, pipeFlags, replacementShaders, outputIndex); VkMarkerRegion::Set(StringFormat::Fmt("Test culling on %u", eid), cmd); ReplayDraw(cmd, pipe, eid, TestEnabled_Culling); } + if(eventFlags & TestEnabled_DepthClipping) + { + uint32_t pipeFlags = + PipelineCreationFlags_DisableDepthTest | PipelineCreationFlags_DisableDepthBoundsTest | + PipelineCreationFlags_DisableStencilTest | PipelineCreationFlags_FixedColorShader; + VkPipeline pipe = CreatePipeline(basePipeline, pipeFlags, replacementShaders, outputIndex); + VkMarkerRegion::Set(StringFormat::Fmt("Test depth clipping on %u", eid), cmd); + ReplayDraw(cmd, pipe, eid, TestEnabled_DepthClipping); + } + // Scissor if(eventFlags & TestMustFail_Scissor) return; @@ -2081,6 +2097,8 @@ private: ds->stencilTestEnable = VK_FALSE; if(pipeCreateFlags & PipelineCreationFlags_DisableDepthBoundsTest) ds->depthBoundsTestEnable = VK_FALSE; + if(pipeCreateFlags & PipelineCreationFlags_DisableDepthClipping) + rs->depthClampEnable = VK_TRUE; rdcarray stages; stages.resize(ci.stageCount); @@ -3090,6 +3108,15 @@ void UpdateTestsFailed(const TestsFailedCallback *tfCb, uint32_t eventId, uint32 if(mod.backfaceCulled) return; + if(eventFlags & TestEnabled_DepthClipping) + { + uint64_t occlData = tfCb->GetOcclusionResult(eventId, TestEnabled_DepthClipping); + mod.depthClipped = (occlData == 0); + } + + if(mod.depthClipped) + return; + if((eventFlags & (TestEnabled_Scissor | TestMustPass_Scissor | TestMustFail_Scissor)) == TestEnabled_Scissor) { @@ -3121,9 +3148,9 @@ void UpdateTestsFailed(const TestsFailedCallback *tfCb, uint32_t eventId, uint32 if(eventFlags & TestEnabled_DepthBounds) { uint64_t occlData = tfCb->GetOcclusionResult(eventId, TestEnabled_DepthBounds); - mod.depthClipped = (occlData == 0); + mod.depthBoundsFailed = (occlData == 0); } - if(mod.depthClipped) + if(mod.depthBoundsFailed) return; if((eventFlags & (TestEnabled_StencilTesting | TestMustFail_StencilTesting)) == diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index f3eef4f72..3c206d5c2 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -896,6 +896,7 @@ void DoSerialise(SerialiserType &ser, PixelModification &el) SERIALISE_MEMBER(sampleMasked); SERIALISE_MEMBER(backfaceCulled); SERIALISE_MEMBER(depthClipped); + SERIALISE_MEMBER(depthBoundsFailed); SERIALISE_MEMBER(viewClipped); SERIALISE_MEMBER(scissorClipped); SERIALISE_MEMBER(shaderDiscarded); diff --git a/util/test/demos/vk/vk_pixel_history.cpp b/util/test/demos/vk/vk_pixel_history.cpp index 8f37d5518..fc46f01a2 100644 --- a/util/test/demos/vk/vk_pixel_history.cpp +++ b/util/test/demos/vk/vk_pixel_history.cpp @@ -224,6 +224,15 @@ void main() {Vec3f(0.6f, 0.8f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, {Vec3f(0.4f, 0.7f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(0.2f, 0.8f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + // depth bounds prep + {Vec3f(0.6f, -0.3f, 0.3f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.7f, -0.5f, 0.5f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.8f, -0.3f, 0.7f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + // depth bounds clip + {Vec3f(0.6f, -0.3f, 0.3f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.7f, -0.5f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.8f, -0.3f, 0.7f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, }; // negate y if we're using negative viewport height @@ -370,7 +379,7 @@ void main() depthPipeInfo.dynamicState.dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS); depthPipeInfo.depthStencilState.depthBoundsTestEnable = VK_TRUE; depthPipe = createGraphicsPipeline(depthPipeInfo); - setName(dynamicStencilMaskPipe, "depthPipe"); + setName(depthPipe, "depthPipe"); } pipeCreateInfo.depthStencilState.stencilTestEnable = VK_TRUE; @@ -386,11 +395,21 @@ void main() pipeCreateInfo.depthStencilState.stencilTestEnable = VK_TRUE; pipeCreateInfo.depthStencilState.front.compareOp = VK_COMPARE_OP_GREATER; VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo); + pipeCreateInfo.depthStencilState.stencilTestEnable = VK_FALSE; pipeCreateInfo.rasterizationState.cullMode = VK_CULL_MODE_FRONT_BIT; VkPipeline cullFrontPipe = createGraphicsPipeline(pipeCreateInfo); pipeCreateInfo.rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT; + pipeCreateInfo.depthStencilState.depthBoundsTestEnable = VK_TRUE; + pipeCreateInfo.depthStencilState.minDepthBounds = 0.0f; + pipeCreateInfo.depthStencilState.maxDepthBounds = 1.0f; + VkPipeline depthBoundsPipe1 = createGraphicsPipeline(pipeCreateInfo); + pipeCreateInfo.depthStencilState.minDepthBounds = 0.4f; + pipeCreateInfo.depthStencilState.maxDepthBounds = 0.6f; + VkPipeline depthBoundsPipe2 = createGraphicsPipeline(pipeCreateInfo); + pipeCreateInfo.depthStencilState.depthBoundsTestEnable = VK_FALSE; + renderPassCreateInfo.attachments.pop_back(); renderPassCreateInfo.subpasses[0].pDepthStencilAttachment = NULL; @@ -533,6 +552,13 @@ void main() vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cullFrontPipe); vkCmdDraw(cmd, 3, 1, 0, 0); + setMarker(cmd, "Depth Bounds Prep"); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, depthBoundsPipe1); + vkCmdDraw(cmd, 3, 1, 63, 0); + setMarker(cmd, "Depth Bounds Clip"); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, depthBoundsPipe2); + vkCmdDraw(cmd, 3, 1, 66, 0); + // add a marker so we can easily locate this draw setMarker(cmd, "Test Begin"); diff --git a/util/test/tests/Vulkan/VK_Pixel_History.py b/util/test/tests/Vulkan/VK_Pixel_History.py index 1d22e06aa..0da53071b 100644 --- a/util/test/tests/Vulkan/VK_Pixel_History.py +++ b/util/test/tests/Vulkan/VK_Pixel_History.py @@ -7,6 +7,8 @@ def passed(x): return x.Passed() def event_id(x): return x.eventId def culled(x): return x.backfaceCulled def depth_test_failed(x): return x.depthTestFailed +def depth_clipped(x): return x.depthClipped +def depth_bounds_failed(x): return x.depthBoundsFailed def scissor_clipped(x): return x.scissorClipped def stencil_test_failed(x): return x.stencilTestFailed def shader_discarded(x): return x.shaderDiscarded @@ -69,6 +71,8 @@ class VK_Pixel_History(rdtest.TestCase): dynamic_stencil_ref_eid = self.find_draw("Dynamic Stencil Ref").next.eventId dynamic_stencil_mask_eid = self.find_draw("Dynamic Stencil Mask").next.eventId depth_test_eid = self.find_draw("Depth Test").next.eventId + depth_bounds_prep_eid = self.find_draw("Depth Bounds Prep").next.eventId + depth_bounds_clip_eid = self.find_draw("Depth Bounds Clip").next.eventId # For pixel 190, 149 inside the red triangle x, y = 190, 149 @@ -118,6 +122,59 @@ class VK_Pixel_History(rdtest.TestCase): self.check_events(events, modifs, False) self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + x, y = 330, 145 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, test_eid], [passed, True], [primitive_id, 3], [shader_out_col, (0.0, 0.0, 0.0, 2.75)]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + + x, y = 340, 145 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, test_eid], [passed, False], [depth_clipped, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + + x, y = 330, 105 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]], + [[event_id, depth_bounds_clip_eid], [passed, True], [primitive_id, 0], [shader_out_col, (0.0, 1.0, 0.0, 2.75)]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + + x, y = 320, 105 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]], + [[event_id, depth_bounds_clip_eid], [passed, False], [depth_bounds_failed, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + + x, y = 345, 105 + rdtest.log.print("Testing pixel {}, {}".format(x, y)) + modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast) + events = [ + [[event_id, begin_renderpass_eid], [passed, True]], + [[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]], + [[event_id, depth_bounds_clip_eid], [passed, False], [depth_bounds_failed, True]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + rdtest.log.print("Testing dynamic state pipelines") self.controller.SetFrameEvent(dynamic_stencil_mask_eid, True)