diff --git a/util/test/demos/vk/vk_annotations.cpp b/util/test/demos/vk/vk_annotations.cpp index 9cdb8af0e..4c9ecece6 100644 --- a/util/test/demos/vk/vk_annotations.cpp +++ b/util/test/demos/vk/vk_annotations.cpp @@ -28,12 +28,51 @@ RD_TEST(VK_Annotations, VulkanGraphicsTest) { static constexpr const char *Description = "Test annotations via the vulkan API."; + float sqSize; + VkViewport viewPort; + + void NextTest() + { + viewPort.x += sqSize; + + if(viewPort.x + sqSize >= (float)screenWidth) + { + viewPort.x = 0.0f; + viewPort.y += sqSize; + } + } + + void Prepare(int argc, char **argv) + { + optDevExts.push_back(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME); + + features.multiDrawIndirect = VK_TRUE; + + VulkanGraphicsTest::Prepare(argc, argv); + + if(!Avail.empty()) + return; + } + int main() { // initialise, create window, create context, etc if(!Init()) return 3; + bool draw_indirect_count = false; + if(devVersion >= VK_MAKE_VERSION(1, 2, 0)) + { + draw_indirect_count = true; + } + else + { + draw_indirect_count = hasExt(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME); + } + + if(draw_indirect_count) + TEST_LOG("Running tests with draw indirect count"); + // these tags provide the layer a way (for dispatchable objects at least) to identify // dispatchable objects that may be wrapped by the loader VkDebugUtilsObjectTagInfoEXT tag = { @@ -66,6 +105,32 @@ RD_TEST(VK_Annotations, VulkanGraphicsTest) setName(img.image, "Annotated Image"); setName(DefaultTriVB.buffer, "Vertex Buffer"); + VkDeviceSize indirectDataSize = 16 * 1024; + struct uvec4 + { + uint32_t x; + uint32_t y; + uint32_t z; + uint32_t w; + }; + + AllocatedBuffer indirectData( + this, + vkh::BufferCreateInfo(indirectDataSize, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); + setName(indirectData.buffer, "Indirect Data"); + { + uvec4 data[4]; + // vkCmdDrawIndirect() (2 draws) + data[0] = {3, 1, 0, 0}; // draw verts 0..2 + data[1] = {3, 1, 0, 0}; // draw verts 0..2 + + // Counts + data[2] = {2, 0, 0, 0}; + indirectData.upload(data, sizeof(data)); + } + // cache the device pointer we pass in void *d = RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(instance); @@ -132,8 +197,12 @@ RD_TEST(VK_Annotations, VulkanGraphicsTest) rdoc->SetObjectAnnotation(d, img.image, "path.deleted", eRENDERDOC_Empty, 0, NULL); } + sqSize = float(screenHeight) / 3.0f; + while(Running()) { + viewPort = {0.0f, 0.0f, sqSize, sqSize, 0.0f, 1.0f}; + if(rdoc) { // queue annotations are only included when in the captured frame @@ -152,6 +221,9 @@ RD_TEST(VK_Annotations, VulkanGraphicsTest) rdoc->SetCommandAnnotation(d, queue, "command.deleted", eRENDERDOC_Int32, 0, RDAnnotationHelper(50)); + + rdoc->SetCommandAnnotation(d, queue, "draw.indirect", eRENDERDOC_Int32, 0, + RDAnnotationHelper(10000)); } VkCommandBuffer cmd = GetCommandBuffer(); @@ -172,6 +244,9 @@ RD_TEST(VK_Annotations, VulkanGraphicsTest) RDAnnotationHelper(3333)); rdoc->SetCommandAnnotation(d, cmd, "command.deleted", eRENDERDOC_Empty, 0, NULL); + + rdoc->SetCommandAnnotation(d, cmd, "draw.indirect", eRENDERDOC_Int32, 0, + RDAnnotationHelper(20000)); } setMarker(cmd, "Initial"); @@ -212,24 +287,104 @@ RD_TEST(VK_Annotations, VulkanGraphicsTest) setMarker(cmd, "Draw 1"); - vkCmdDraw(cmd, 3, 1, 0, 0); + vkCmdSetViewport(cmd, 0, 1, &viewPort); - VkViewport view = mainWindow->viewport; - view.width /= 2; - view.height /= 2; - vkCmdSetViewport(cmd, 0, 1, &view); + vkCmdDraw(cmd, 3, 1, 0, 0); + NextTest(); + + vkCmdSetViewport(cmd, 0, 1, &viewPort); setMarker(cmd, "Draw 2"); vkCmdDraw(cmd, 3, 1, 0, 0); + NextTest(); + + if(rdoc) + { + rdoc->SetCommandAnnotation(d, cmd, "draw.indirect", eRENDERDOC_Int32, 0, + RDAnnotationHelper(30000)); + } + setMarker(cmd, "Pre-DrawIndirectCount"); + if(draw_indirect_count) + { + const uint32_t strideDraw = sizeof(uvec4); + const size_t drawIndirectOffset = 0; + size_t countOffset = 2 * sizeof(uvec4); + size_t countZeroOffset = countOffset + sizeof(uint32_t); + + pushMarker(cmd, "DrawIndirectCount"); + + setMarker(cmd, "DrawIndirectCount(0:0)"); + vkCmdSetViewport(cmd, 0, 1, &viewPort); + if(rdoc) + { + rdoc->SetCommandAnnotation(d, cmd, "draw.indirect", eRENDERDOC_Int32, 0, + RDAnnotationHelper(1)); + } + vkCmdDrawIndirectCountKHR(cmd, indirectData.buffer, drawIndirectOffset, indirectData.buffer, + countOffset, 0, strideDraw); + NextTest(); + + setMarker(cmd, "DrawIndirectCount(10:0)"); + vkCmdSetViewport(cmd, 0, 1, &viewPort); + if(rdoc) + { + rdoc->SetCommandAnnotation(d, cmd, "draw.indirect", eRENDERDOC_Int32, 0, + RDAnnotationHelper(2)); + } + vkCmdDrawIndirectCountKHR(cmd, indirectData.buffer, drawIndirectOffset, indirectData.buffer, + countZeroOffset, 10, strideDraw); + NextTest(); + + setMarker(cmd, "DrawIndirectCount(10:N)"); + vkCmdSetViewport(cmd, 0, 1, &viewPort); + if(rdoc) + { + rdoc->SetCommandAnnotation(d, cmd, "draw.indirect", eRENDERDOC_Int32, 0, + RDAnnotationHelper(3)); + } + vkCmdDrawIndirectCountKHR(cmd, indirectData.buffer, drawIndirectOffset, indirectData.buffer, + countOffset, 10, strideDraw); + NextTest(); + + popMarker(cmd); + } + + if(rdoc) + { + rdoc->SetCommandAnnotation(d, cmd, "draw.indirect", eRENDERDOC_Int32, 0, + RDAnnotationHelper(40000)); + } + setMarker(cmd, "Post-DrawIndirectCount"); vkCmdEndRenderPass(cmd); + setMarker(cmd, "Loose"); + if(rdoc) + { + rdoc->SetCommandAnnotation(d, cmd, "loose.int", eRENDERDOC_Int32, 0, RDAnnotationHelper(1)); + } + FinishUsingBackbuffer(cmd); + if(rdoc) + { + rdoc->SetCommandAnnotation(d, cmd, "loose.int", eRENDERDOC_Int32, 0, RDAnnotationHelper(2)); + rdoc->SetCommandAnnotation(d, cmd, "new.value", eRENDERDOC_Empty, 0, NULL); + } vkEndCommandBuffer(cmd); - SubmitAndPresent({cmd}); + VkCommandBuffer empty = GetCommandBuffer(); + + vkBeginCommandBuffer(empty, vkh::CommandBufferBeginInfo()); + setMarker(empty, "Empty"); + if(rdoc) + { + rdoc->SetCommandAnnotation(d, empty, "empty.int", eRENDERDOC_Int32, 0, RDAnnotationHelper(1)); + } + vkEndCommandBuffer(empty); + + SubmitAndPresent({empty, cmd}); } return 0; diff --git a/util/test/tests/Vulkan/VK_Annotations.py b/util/test/tests/Vulkan/VK_Annotations.py index fe5d816a2..27911c480 100644 --- a/util/test/tests/Vulkan/VK_Annotations.py +++ b/util/test/tests/Vulkan/VK_Annotations.py @@ -8,4 +8,53 @@ class VK_Annotations(rdtest.Annotations): def check_capture(self): super().check_resource_annotations() - super().check_command_annotations(True) \ No newline at end of file + super().check_command_annotations(True) + + annot = lambda x: annots.FindChildByKeyPath(x) + + # Check annotations attached to indirect draws + draw_indirect_count = self.find_action("DrawIndirectCount") + with rdtest.log.auto_section('DrawIndirectCount'): + expected_values = [("Start", 10000), + ("Initial", 20000), + ("Pre-DrawIndirectCount", 30000)] + if draw_indirect_count is not None: + expected_values += [ + ("vkCmdDrawIndirectCount(0)", 1), + ("vkCmdDrawIndirectCount(<0>)", 2), + ("Indirect sub-command[0](<3, 1>)", 3), + ("Indirect sub-command[1](<3, 1>)", 3)] + expected_values += [("Post-DrawIndirectCount", 40000)] + + action = self.get_first_action() + for name, value in expected_values: + action = self.find_action(name, action.eventId) + annots = action.events[-1].annotations + key = "draw.indirect" + self.check_eq(annot(key).type.basetype, rd.SDBasic.SignedInteger) + self.check_eq(annot(key).AsInt(), value) + + # Check loose event annotation attached to a barrier + with rdtest.log.auto_section('Loose Event'): + marker = self.find_action("Loose") + action = marker.next + annots = action.events[0].annotations + self.check_eq(annot("loose.int").type.basetype, rd.SDBasic.SignedInteger) + self.check_eq(annot("loose.int").AsInt(), 1) + + # Check loose event annotation attached to vkEndCommandBuffer + with rdtest.log.auto_section('vkEndCommandBuffer Event'): + marker = self.find_action("Loose") + action = marker.next + annots = action.events[-1].annotations + self.check_eq(annot("loose.int").type.basetype, rd.SDBasic.SignedInteger) + self.check_eq(annot("loose.int").AsInt(), 2) + self.check(annot("new.value") is None) + + # Check loose event annotation in an empty command buffer + with rdtest.log.auto_section('Empty Command Buffer'): + marker = self.find_action("Empty") + action = marker.next + annots = action.events[0].annotations + self.check_eq(annot("empty.int").type.basetype, rd.SDBasic.SignedInteger) + self.check_eq(annot("empty.int").AsInt(), 1)