From 3e641e4e7c4ff6edce2f65467cdb1ff988c78e16 Mon Sep 17 00:00:00 2001 From: Tobin Ehlis Date: Wed, 17 Aug 2016 14:57:58 -0600 Subject: [PATCH] tests: Add InvalidCmdBufferDescriptorSetBufferDestroyed test This test creates a cmd buffer and binds a buffer-type descriptor set. Then it detroys the buffer prior to submitting cmd buffer and verifies that the cmd buffer is flagged as invalid. --- layers/vk_validation_layer_details.md | 2 +- tests/layer_validation_tests.cpp | 166 ++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 1 deletion(-) diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md index 0b3ee77..1a73172 100644 --- a/layers/vk_validation_layer_details.md +++ b/layers/vk_validation_layer_details.md @@ -41,7 +41,7 @@ The Draw State portion of the core validation layer tracks state leading into Dr | Valid RenderArea | Flag renderArea field that is outside of the framebuffer | INVALID_RENDER_AREA | vkCmdBeginRenderPass | RenderPassInvalidRenderArea | Anywhere else to check this? | | Valid Pipeline | Flag VkPipeline object that was not properly created, or case when Draw/Dispatch is bound to cmd buffer without a pipeline being bound | INVALID_PIPELINE | vkCmdBindPipeline | InvalidPipeline | NA | | Valid Pipeline Create Info | Tests for the following: That compute shaders are not specified for the graphics pipeline, tess evaluation and tess control shaders are included or excluded as a pair, that VK_PRIMITIVE_TOPOLOGY_PATCH_LIST is set as IA topology for tessellation pipelines, that VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only set for tessellation pipelines, and that Vtx Shader specified | INVALID_PIPELINE_CREATE_STATE | vkCreateGraphicsPipelines | InvalidPipelineCreateState | NA | -| Valid CommandBuffer | Validates that the command buffer object was properly created and is currently valid | INVALID_COMMAND_BUFFER | vkQueueSubmit vkBeginCommandBuffer vkEndCommandBuffer vkCmdBindPipeline vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearAttachments vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdBeginRenderPass vkCmdNextSubpass vkCmdEndRenderPass vkCmdExecuteCommands vkAllocateCommandBuffers | InvalidCmdBufferBufferDestroyed InvalidCmdBufferImageDestroyed InvalidCmdBufferEventDestroyed InvalidCmdBufferQueryPoolDestroyed InvalidCmdBufferPipelineDestroyed ExecuteCommandsPrimaryCB | TODO - missing tests for 8 separate cases where this error is flagged. Cases are getCBNode(), 1st case in validateCmdsInCmdBuffer(), checkGraphicsBit(), checkComputeBit(), checkGraphicsOrComputeBit(), BeginCommandBuffer(), validatePrimaryCommandBuffer() and CmdExecuteCommands() | +| Valid CommandBuffer | Validates that the command buffer object was properly created and is currently valid | INVALID_COMMAND_BUFFER | vkQueueSubmit vkBeginCommandBuffer vkEndCommandBuffer vkCmdBindPipeline vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearAttachments vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp vkCmdBeginRenderPass vkCmdNextSubpass vkCmdEndRenderPass vkCmdExecuteCommands vkAllocateCommandBuffers | InvalidCmdBufferBufferDestroyed InvalidCmdBufferImageDestroyed InvalidCmdBufferEventDestroyed InvalidCmdBufferQueryPoolDestroyed InvalidCmdBufferPipelineDestroyed ExecuteCommandsPrimaryCB InvalidCmdBufferDescriptorSetBufferDestroyed | TODO - missing tests for 8 separate cases where this error is flagged. Cases are getCBNode(), 1st case in validateCmdsInCmdBuffer(), checkGraphicsBit(), checkComputeBit(), checkGraphicsOrComputeBit(), BeginCommandBuffer(), validatePrimaryCommandBuffer() and CmdExecuteCommands() | | Vtx Buffer Bounds | Check if VBO index too large for PSO Vtx binding count, and that at least one vertex buffer is attached to pipeline object | VTX_INDEX_OUT_OF_BOUNDS | vkCmdBindDescriptorSets vkCmdBindVertexBuffers | VtxBufferBadIndex | NA | | Idx Buffer Alignment | Verify that offset of Index buffer falls on an alignment boundary as defined by IdxBufferAlignmentError param | VTX_INDEX_ALIGNMENT_ERROR | vkCmdBindIndexBuffer | IdxBufferAlignmentError | NA | | Cmd Buffer End | Verifies that EndCommandBuffer was called for this commandBuffer at QueueSubmit time | NO_END_COMMAND_BUFFER | vkQueueSubmit | TODO | NA | diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp index 4426597..d207b55 100644 --- a/tests/layer_validation_tests.cpp +++ b/tests/layer_validation_tests.cpp @@ -7738,6 +7738,172 @@ TEST_F(VkLayerTest, InvalidCmdBufferPipelineDestroyed) { vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); } +TEST_F(VkLayerTest, InvalidCmdBufferDescriptorSetBufferDestroyed) { + TEST_DESCRIPTION("Attempt to draw with a command buffer that is invalid " + "due to a bound descriptor set with a buffer dependency " + "being destroyed."); + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitViewport()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + VkDescriptorPoolSize ds_type_count = {}; + ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + ds_type_count.descriptorCount = 1; + + VkDescriptorPoolCreateInfo ds_pool_ci = {}; + ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + ds_pool_ci.pNext = NULL; + ds_pool_ci.maxSets = 1; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &ds_type_count; + + VkDescriptorPool ds_pool; + VkResult err = + vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSetLayoutBinding dsl_binding = {}; + dsl_binding.binding = 0; + dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + dsl_binding.descriptorCount = 1; + dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; + dsl_binding.pImmutableSamplers = NULL; + + VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; + ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + ds_layout_ci.pNext = NULL; + ds_layout_ci.bindingCount = 1; + ds_layout_ci.pBindings = &dsl_binding; + VkDescriptorSetLayout ds_layout; + err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, + &ds_layout); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSet descriptorSet; + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorSetCount = 1; + alloc_info.descriptorPool = ds_pool; + alloc_info.pSetLayouts = &ds_layout; + err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, + &descriptorSet); + ASSERT_VK_SUCCESS(err); + + VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; + pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_ci.pNext = NULL; + pipeline_layout_ci.setLayoutCount = 1; + pipeline_layout_ci.pSetLayouts = &ds_layout; + + VkPipelineLayout pipeline_layout; + err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, + &pipeline_layout); + ASSERT_VK_SUCCESS(err); + + // Create a buffer to update the descriptor with + uint32_t qfi = 0; + VkBufferCreateInfo buffCI = {}; + buffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffCI.size = 1024; + buffCI.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + buffCI.queueFamilyIndexCount = 1; + buffCI.pQueueFamilyIndices = &qfi; + + VkBuffer buffer; + err = vkCreateBuffer(m_device->device(), &buffCI, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + // Allocate memory and bind to buffer so we can make it to the appropriate + // error + VkMemoryAllocateInfo mem_alloc = {}; + mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc.pNext = NULL; + mem_alloc.allocationSize = 1024; + mem_alloc.memoryTypeIndex = 0; + + VkMemoryRequirements memReqs; + vkGetBufferMemoryRequirements(m_device->device(), buffer, &memReqs); + bool pass = + m_device->phy().set_memory_type(memReqs.memoryTypeBits, &mem_alloc, 0); + if (!pass) { + vkDestroyBuffer(m_device->device(), buffer, NULL); + return; + } + + VkDeviceMemory mem; + err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); + ASSERT_VK_SUCCESS(err); + err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); + ASSERT_VK_SUCCESS(err); + // Correctly update descriptor to avoid "NOT_UPDATED" error + VkDescriptorBufferInfo buffInfo = {}; + buffInfo.buffer = buffer; + buffInfo.offset = 0; + buffInfo.range = 1024; + + VkWriteDescriptorSet descriptor_write; + memset(&descriptor_write, 0, sizeof(descriptor_write)); + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.dstSet = descriptorSet; + descriptor_write.dstBinding = 0; + descriptor_write.descriptorCount = 1; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.pBufferInfo = &buffInfo; + + vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); + + // Create PSO to be used for draw-time errors below + char const *vsSource = "#version 450\n" + "\n" + "out gl_PerVertex { \n" + " vec4 gl_Position;\n" + "};\n" + "void main(){\n" + " gl_Position = vec4(1);\n" + "}\n"; + char const *fsSource = + "#version 450\n" + "\n" + "layout(location=0) out vec4 x;\n" + "layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;\n" + "void main(){\n" + " x = vec4(bar.y);\n" + "}\n"; + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + VkPipelineObj pipe(m_device); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + pipe.AddColorAttachment(); + pipe.CreateVKPipeline(pipeline_layout, renderPass()); + + BeginCommandBuffer(); + vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), + VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); + vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), + VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, + 1, &descriptorSet, 0, NULL); + Draw(1, 0, 0, 0); + EndCommandBuffer(); + m_errorMonitor->SetDesiredFailureMsg( + VK_DEBUG_REPORT_ERROR_BIT_EXT, + " that is invalid because bound buffer "); + // Destroy buffer should invalidate the cmd buffer, causing error on submit + vkDestroyBuffer(m_device->device(), buffer, NULL); + // Attempt to submit cmd buffer + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &m_commandBuffer->handle(); + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + m_errorMonitor->VerifyFound(); + // Cleanup + vkFreeMemory(m_device->device(), mem, NULL); + + vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); + vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); + vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); +} + TEST_F(VkLayerTest, InvalidPipeline) { // Attempt to bind an invalid Pipeline to a valid Command Buffer // ObjectTracker should catch this. -- 2.7.4