diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index b6c452df6..e03a1294a 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -461,12 +461,12 @@ protected: // TODO: should leave in the original state. ds->depthTestEnable = VK_FALSE; ds->depthWriteEnable = VK_FALSE; + ds->depthBoundsTestEnable = VK_FALSE; if(disableTests) { rs->cullMode = VK_CULL_MODE_NONE; rs->rasterizerDiscardEnable = VK_FALSE; - ds->depthBoundsTestEnable = VK_FALSE; if(m_pDriver->GetDeviceFeatures().depthClamp) rs->depthClampEnable = true; } @@ -1350,6 +1350,9 @@ private: m_pDriver->GetCmdRenderState().BeginRenderPassAndApplyState(m_pDriver, cmd, VulkanRenderState::BindGraphics); + ObjDisp(cmd)->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_AND_BACK, 0xff); + ObjDisp(cmd)->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_AND_BACK, 0xff); + if(clear) { VkClearAttachment att = {}; @@ -2002,11 +2005,11 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback DoPipelineBarrier(cmd, 1, &barrier); - // If depth is enabled, clear out the depth value so that the test always - // passes. Depth writes only work if depth test is enabled. - // Regardless also need to reset the stencil back to 0. + // Reset depth to 0.0f, depth test is set to always pass. + // This way we get the value for just that fragment. + // Reset stencil to 0. VkClearDepthStencilValue dsValue = {}; - dsValue.depth = 1.0f; + dsValue.depth = 0.0f; dsValue.stencil = 0; VkImageSubresourceRange range = {}; range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; @@ -2014,6 +2017,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback range.baseMipLevel = 0; range.layerCount = 1; range.levelCount = 1; + ObjDisp(cmd)->CmdClearDepthStencilImage(Unwrap(cmd), Unwrap(m_CallbackInfo.dsImage), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &dsValue, 1, &range); @@ -2205,21 +2209,6 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback stages[i].module = replacement; } pipeCreateInfo.pStages = stages.data(); - - VkPipelineDynamicStateCreateInfo *dynState = - (VkPipelineDynamicStateCreateInfo *)pipeCreateInfo.pDynamicState; - - rdcarray dynamicStates; - RDCASSERT(dynState != NULL); - if(!p.dynamicStates[VkDynamicStencilReference]) - { - dynamicStates.resize(dynState->dynamicStateCount); - memcpy(dynamicStates.data(), dynState->pDynamicStates, dynamicStates.byteSize()); - dynamicStates.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE); - dynState->dynamicStateCount = (uint32_t)dynamicStates.size(); - dynState->pDynamicStates = dynamicStates.data(); - } - pipeCreateInfo.renderPass = rp; Pipelines pipes = {}; @@ -2247,6 +2236,11 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback } } + { + ds->depthBoundsTestEnable = VK_FALSE; + ds->depthCompareOp = VK_COMPARE_OP_ALWAYS; + } + vkr = m_pDriver->vkCreateGraphicsPipelines(m_pDriver->GetDev(), VK_NULL_HANDLE, 1, &pipeCreateInfo, NULL, &pipes.shaderOutPipe); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -3014,6 +3008,7 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even uint32_t eventId = events[ev].eventId; bool clear = (events[ev].usage == ResourceUsage::Clear); bool directWrite = isDirectWrite(events[ev].usage); + if(drawEvents.contains(events[ev].eventId) || clear || directWrite) { PixelModification mod; @@ -3195,6 +3190,12 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even FillInColor(shaderOutFormat, bp[offset].postMod, history[h].postMod); history[h].postMod.depth = bp[offset].postMod.depth.fdepth; } + // If it is not the first fragment for the event, set the preMod to the + // postMod of the previous fragment. + if(h > 0 && (history[h].eventId == history[h - 1].eventId)) + { + history[h].preMod = history[h - 1].postMod; + } } } } diff --git a/util/test/demos/vk/vk_pixel_history_test.cpp b/util/test/demos/vk/vk_pixel_history_test.cpp index 284a8cb76..f72aab8a7 100644 --- a/util/test/demos/vk/vk_pixel_history_test.cpp +++ b/util/test/demos/vk/vk_pixel_history_test.cpp @@ -101,6 +101,8 @@ void main() void Prepare(int argc, char **argv) { + features.depthBounds = true; + features.geometryShader = true; features.sampleRateShading = true; VulkanGraphicsTest::Prepare(argc, argv); @@ -195,6 +197,33 @@ void main() {Vec3f(-0.6f, 0.75f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, {Vec3f(-0.5f, 0.65f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(-0.4f, 0.75f, 0.5f), Vec4f(0.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + // Different depth triangles + {Vec3f(0.0f, 0.8f, 0.97f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.4f, 0.2f, 0.97f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.8f, 0.8f, 0.97f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + {Vec3f(0.2f, 0.8f, 0.20f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.4f, 0.4f, 0.20f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.6f, 0.8f, 0.20f), Vec4f(1.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + {Vec3f(0.2f, 0.8f, 0.30f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.4f, 0.6f, 0.30f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.6f, 0.8f, 0.30f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + {Vec3f(0.2f, 0.8f, 0.10f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.4f, 0.7f, 0.10f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.6f, 0.8f, 0.10f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + // Fails depth bounds test. + {Vec3f(0.2f, 0.8f, 0.05f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.4f, 0.7f, 0.05f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.6f, 0.8f, 0.05f), Vec4f(1.0f, 1.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + // Should be back face culled. + {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)}, }; // negate y if we're using negative viewport height @@ -316,6 +345,16 @@ void main() } pipeCreateInfo.depthStencilState.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + + VkPipeline depthPipe; + { + vkh::GraphicsPipelineCreateInfo depthPipeInfo = pipeCreateInfo; + depthPipeInfo.dynamicState.dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS); + depthPipeInfo.depthStencilState.depthBoundsTestEnable = VK_TRUE; + depthPipe = createGraphicsPipeline(depthPipeInfo); + setName(dynamicStencilMaskPipe, "depthPipe"); + } + pipeCreateInfo.depthStencilState.stencilTestEnable = VK_TRUE; VkPipeline stencilWritePipe = createGraphicsPipeline(pipeCreateInfo); @@ -462,6 +501,18 @@ void main() vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FACE_FRONT_AND_BACK, 0); vkCmdDraw(cmd, 3, 1, 42, 0); + // Six triangles, five fragments reported. + // 0: Fails depth test + // 1: Passes + // 2: Fails depth test compared to 1st fragment + // 3: Passes + // 4: Fails depth bounds test + // 5: Fails backface culling, not reported. + setMarker(cmd, "Depth Test"); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, depthPipe); + vkCmdSetDepthBounds(cmd, 0.15f, 1.0f); + vkCmdDraw(cmd, 6 * 3, 1, 45, 0); + vkCmdEndRenderPass(cmd); { diff --git a/util/test/tests/Vulkan/VK_Pixel_History.py b/util/test/tests/Vulkan/VK_Pixel_History.py index acef96405..6aa644bc9 100644 --- a/util/test/tests/Vulkan/VK_Pixel_History.py +++ b/util/test/tests/Vulkan/VK_Pixel_History.py @@ -11,8 +11,10 @@ def scissor_clipped(x): return x.scissorClipped def stencil_test_failed(x): return x.stencilTestFailed def shader_discarded(x): return x.shaderDiscarded def shader_out_col(x): return value_selector(x.shaderOut.col) +def shader_out_depth(x): return x.shaderOut.depth def pre_mod_col(x): return value_selector(x.preMod.col) def post_mod_col(x): return value_selector(x.postMod.col) +def post_mod_depth(x): return x.postMod.depth def primitive_id(x): return x.primitiveID def unboundPS(x): return x.unboundPS @@ -59,6 +61,7 @@ class VK_Pixel_History(rdtest.TestCase): fixed_scissor_pass_eid = self.find_draw("Fixed Scissor Pass").next.eventId 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 # For pixel 190, 149 inside the red triangle x, y = 190, 149 @@ -125,6 +128,29 @@ 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) + rdtest.log.print("Testing depth test for per fragment reporting") + self.controller.SetFrameEvent(depth_test_eid, True) + + x, y = 275, 260 + 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, background_eid], [passed, True]], + [[event_id, depth_test_eid], [primitive_id, 0], [shader_out_col, (1.0, 1.0, 1.0, 1.0)], + [shader_out_depth, 0.97], [post_mod_col, (1.0, 0.0, 1.0, 1.0)], [post_mod_depth, 0.95]], + [[event_id, depth_test_eid], [primitive_id, 1], [shader_out_col, (1.0, 1.0, 0.0, 1.0)], + [shader_out_depth, 0.20], [post_mod_col, (1.0, 1.0, 0.0, 1.0)], [post_mod_depth, 0.20]], + [[event_id, depth_test_eid], [primitive_id, 2], [shader_out_col, (1.0, 0.0, 0.0, 1.0)], + [shader_out_depth, 0.30], [post_mod_col, (1.0, 1.0, 0.0, 1.0)], [post_mod_depth, 0.20]], + [[event_id, depth_test_eid], [primitive_id, 3], [shader_out_col, (0.0, 0.0, 1.0, 1.0)], + [shader_out_depth, 0.10], [post_mod_col, (0.0, 0.0, 1.0, 1.0)], [post_mod_depth, 0.10]], + [[event_id, depth_test_eid], [primitive_id, 4], [shader_out_col, (1.0, 1.0, 1.0, 1.0)], + [shader_out_depth, 0.05], [post_mod_col, (0.0, 0.0, 1.0, 1.0)], [post_mod_depth, 0.10]], + ] + self.check_events(events, modifs, False) + self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast) + def multisampled_image_test(self): test_marker: rd.DrawcallDescription = self.find_draw("Multisampled: test") draw_eid = test_marker.next.eventId @@ -231,7 +257,7 @@ class VK_Pixel_History(rdtest.TestCase): actual = events[i][c][0](modifs[i]) if not rdtest.value_compare(actual, expected): raise rdtest.TestFailureException( - "eventId {}, testing {} expected {}, got {}".format(modifs[i].eventId, + "eventId {}, primitiveID {}: testing {} expected {}, got {}".format(modifs[i].eventId, modifs[i].primitiveID, events[i][c][0].__name__, expected, actual)) @@ -241,9 +267,11 @@ class VK_Pixel_History(rdtest.TestCase): for i in range(len(modifs) - 1): if value_selector(modifs[i].postMod.col) != value_selector(modifs[i + 1].preMod.col): raise rdtest.TestFailureException( - "postmod at {}: {} doesn't match premod at {}: {}".format(modifs[i].eventId, + "postmod at {} primitive {}: {} doesn't match premod at {} primitive {}: {}".format(modifs[i].eventId, + modifs[i].primitiveID, value_selector(modifs[i].postMod.col), modifs[i + 1].eventId, + modifs[i + 1].primitiveID, value_selector(modifs[i].preMod.col))) # Check that if the test failed, its postmod is the same as premod @@ -251,6 +279,7 @@ class VK_Pixel_History(rdtest.TestCase): if not modifs[i].Passed(): if not rdtest.value_compare(value_selector(modifs[i].preMod.col), value_selector(modifs[i].postMod.col)): raise rdtest.TestFailureException( - "postmod at {}: {} doesn't match premod: {}".format(modifs[i].eventId, + "postmod at {} primitive {}: {} doesn't match premod: {}".format(modifs[i].eventId, + modifs[i].primitiveID, value_selector(modifs[i].postMod.col), value_selector(modifs[i].preMod.col)))