vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL);
}
+TEST_F(VkLayerTest, InvalidDescriptorSetSamplerDestroyed) {
+ TEST_DESCRIPTION("Attempt to draw with a bound descriptor sets with a combined image sampler where sampler has been deleted.");
+ ASSERT_NO_FATAL_FAILURE(Init(nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
+ ASSERT_NO_FATAL_FAILURE(InitViewport());
+ ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+ OneOffDescriptorSet ds(m_device, {
+ {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr},
+ });
+
+ const VkPipelineLayoutObj pipeline_layout(m_device, {&ds.layout_});
+ // Create images to update the descriptor with
+ VkImageObj image(m_device);
+ const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
+ image.Init(32, 32, 1, tex_format, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
+ ASSERT_TRUE(image.initialized());
+
+ VkImageViewCreateInfo image_view_create_info = {};
+ image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ image_view_create_info.image = image.handle();
+ image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ image_view_create_info.format = tex_format;
+ image_view_create_info.subresourceRange.layerCount = 1;
+ image_view_create_info.subresourceRange.baseMipLevel = 0;
+ image_view_create_info.subresourceRange.levelCount = 1;
+ image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+
+ VkImageView view;
+ VkResult err = vkCreateImageView(m_device->device(), &image_view_create_info, NULL, &view);
+ ASSERT_VK_SUCCESS(err);
+ // Create Samplers
+ VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
+ VkSampler sampler;
+ err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler);
+ ASSERT_VK_SUCCESS(err);
+ // Update descriptor with image and sampler
+ VkDescriptorImageInfo img_info = {};
+ img_info.sampler = sampler;
+ img_info.imageView = view;
+ img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ VkWriteDescriptorSet descriptor_write;
+ memset(&descriptor_write, 0, sizeof(descriptor_write));
+ descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptor_write.dstSet = ds.set_;
+ descriptor_write.dstBinding = 0;
+ descriptor_write.descriptorCount = 1;
+ descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptor_write.pImageInfo = &img_info;
+
+ vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
+ // Destroy the sampler before it's bound to the cmd buffer
+ vkDestroySampler(m_device->device(), sampler, NULL);
+
+ // Create PSO to be used for draw-time errors below
+ char const *vsSource =
+ "#version 450\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.AddDefaultColorAttachment();
+ pipe.CreateVKPipeline(pipeline_layout.handle(), renderPass());
+
+ // First error case is destroying sampler prior to cmd buffer submission
+ m_commandBuffer->begin();
+ m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
+ vkCmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle());
+ vkCmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, &ds.set_, 0,
+ NULL);
+ VkViewport viewport = {0, 0, 16, 16, 0, 1};
+ VkRect2D scissor = {{0, 0}, {16, 16}};
+ vkCmdSetViewport(m_commandBuffer->handle(), 0, 1, &viewport);
+ vkCmdSetScissor(m_commandBuffer->handle(), 0, 1, &scissor);
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ " Descriptor in binding #0 at global descriptor index 0 is using sampler ");
+ m_commandBuffer->Draw(1, 0, 0, 0);
+ m_errorMonitor->VerifyFound();
+
+ vkDestroyImageView(m_device->device(), view, NULL);
+}
+
TEST_F(VkLayerTest, ImageDescriptorLayoutMismatch) {
TEST_DESCRIPTION("Update an image sampler with a layout that doesn't match the actual image layout at the image is used.");
ASSERT_NO_FATAL_FAILURE(Init(nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));