From 41660da03f3d77a21fc42c2a946bee0613582cb5 Mon Sep 17 00:00:00 2001 From: Tobin Ehlis Date: Wed, 7 Sep 2016 13:52:18 -0600 Subject: [PATCH] tests: Add in-use sampler test SamplerInUseDestroyedSignaled creates a sampler that is indirectly bound to cmd buffer via a descriptor set. Then submit cmd buffer, destroy sampler and verify that an error is correctly flagged. --- tests/layer_validation_tests.cpp | 170 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp index 2566f41..3497e14 100644 --- a/tests/layer_validation_tests.cpp +++ b/tests/layer_validation_tests.cpp @@ -14200,6 +14200,176 @@ TEST_F(VkLayerTest, PipelineInUseDestroyedSignaled) { vkDestroyPipelineLayout(m_device->handle(), pipeline_layout, nullptr); } +TEST_F(VkLayerTest, SamplerInUseDestroyedSignaled) { + TEST_DESCRIPTION("Delete in-use sampler."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + VkDescriptorPoolSize ds_type_count; + ds_type_count.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + ds_type_count.descriptorCount = 1; + + VkDescriptorPoolCreateInfo ds_pool_ci = {}; + ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + 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); + + VkSamplerCreateInfo sampler_ci = {}; + sampler_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + sampler_ci.pNext = NULL; + sampler_ci.magFilter = VK_FILTER_NEAREST; + sampler_ci.minFilter = VK_FILTER_NEAREST; + sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + sampler_ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler_ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler_ci.mipLodBias = 1.0; + sampler_ci.anisotropyEnable = VK_FALSE; + sampler_ci.maxAnisotropy = 1; + sampler_ci.compareEnable = VK_FALSE; + sampler_ci.compareOp = VK_COMPARE_OP_NEVER; + sampler_ci.minLod = 1.0; + sampler_ci.maxLod = 1.0; + sampler_ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + sampler_ci.unnormalizedCoordinates = VK_FALSE; + VkSampler sampler; + + err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSetLayoutBinding layout_binding; + layout_binding.binding = 0; + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + layout_binding.descriptorCount = 1; + layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layout_binding.pImmutableSamplers = NULL; + + VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; + ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + ds_layout_ci.bindingCount = 1; + ds_layout_ci.pBindings = &layout_binding; + VkDescriptorSetLayout ds_layout; + err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, + &ds_layout); + ASSERT_VK_SUCCESS(err); + + 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; + VkDescriptorSet descriptor_set; + err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, + &descriptor_set); + 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); + + VkImageObj image(m_device); + image.init(128, 128, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + + VkImageView view; + VkImageViewCreateInfo ivci = {}; + ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + ivci.image = image.handle(); + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; + ivci.format = VK_FORMAT_R8G8B8A8_UNORM; + ivci.subresourceRange.layerCount = 1; + ivci.subresourceRange.baseMipLevel = 0; + ivci.subresourceRange.levelCount = 1; + ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + err = vkCreateImageView(m_device->device(), &ivci, NULL, &view); + ASSERT_VK_SUCCESS(err); + + VkDescriptorImageInfo image_info{}; + image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info.imageView = view; + image_info.sampler = sampler; + + VkWriteDescriptorSet descriptor_write = {}; + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.dstSet = descriptor_set; + descriptor_write.dstBinding = 0; + descriptor_write.descriptorCount = 1; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptor_write.pImageInfo = &image_info; + + vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); + + // Create PSO to use the sampler + 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(set=0, binding=0) uniform sampler2D s;\n" + "layout(location=0) out vec4 x;\n" + "void main(){\n" + " x = texture(s, vec2(1));\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()); + + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, + "Cannot delete sampler 0x"); + + BeginCommandBuffer(); + // Bind pipeline to cmd buffer + vkCmdBindPipeline(m_commandBuffer->handle(), + VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); + vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), + VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, + 1, &descriptor_set, 0, nullptr); + Draw(1, 0, 0, 0); + EndCommandBuffer(); + // Submit cmd buffer then destroy sampler + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &m_commandBuffer->handle(); + // Submit cmd buffer and then destroy sampler while in-flight + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + + vkDestroySampler(m_device->device(), sampler, nullptr); + m_errorMonitor->VerifyFound(); + vkQueueWaitIdle(m_device->m_queue); + // Now we can actually destroy sampler + vkDestroySampler(m_device->device(), sampler, nullptr); + vkDestroyImageView(m_device->device(), view, 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, QueueForwardProgressFenceWait) { TEST_DESCRIPTION("Call VkQueueSubmit with a semaphore that is already " "signaled but not waited on by the queue. Wait on a " -- 2.7.4