tests: Add test for framebuffer image destroyed
Verify that if image attached to framebuffer is destroyed, any command
buffer bound to the framebuffer is correctly invalidated.
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index 9b28742..39c513d 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -7613,6 +7613,106 @@
vkFreeMemory(m_device->device(), image_mem, nullptr);
}
+TEST_F(VkLayerTest, InvalidCmdBufferFramebufferImageDestroyed) {
+ TEST_DESCRIPTION("Attempt to draw with a command buffer that is invalid "
+ "due to a framebuffer image dependency being destroyed.");
+ VkFormatProperties format_properties;
+ VkResult err = VK_SUCCESS;
+ vkGetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_B8G8R8A8_UNORM,
+ &format_properties);
+ if (!(format_properties.optimalTilingFeatures &
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
+ return;
+ }
+
+ ASSERT_NO_FATAL_FAILURE(InitState());
+ ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+ VkImageCreateInfo image_ci = {};
+ image_ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ image_ci.pNext = NULL;
+ image_ci.imageType = VK_IMAGE_TYPE_2D;
+ image_ci.format = VK_FORMAT_B8G8R8A8_UNORM;
+ image_ci.extent.width = 32;
+ image_ci.extent.height = 32;
+ image_ci.extent.depth = 1;
+ image_ci.mipLevels = 1;
+ image_ci.arrayLayers = 1;
+ image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
+ image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
+ image_ci.usage =
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+ image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ image_ci.flags = 0;
+ VkImage image;
+ ASSERT_VK_SUCCESS(
+ vkCreateImage(m_device->handle(), &image_ci, NULL, &image));
+
+ VkMemoryRequirements memory_reqs;
+ VkDeviceMemory image_memory;
+ bool pass;
+ VkMemoryAllocateInfo memory_info = {};
+ memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ memory_info.pNext = NULL;
+ memory_info.allocationSize = 0;
+ memory_info.memoryTypeIndex = 0;
+ vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs);
+ memory_info.allocationSize = memory_reqs.size;
+ pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits,
+ &memory_info, 0);
+ ASSERT_TRUE(pass);
+ err =
+ vkAllocateMemory(m_device->device(), &memory_info, NULL, &image_memory);
+ ASSERT_VK_SUCCESS(err);
+ err = vkBindImageMemory(m_device->device(), image, image_memory, 0);
+ ASSERT_VK_SUCCESS(err);
+
+ VkImageViewCreateInfo ivci = {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ nullptr,
+ 0,
+ image,
+ VK_IMAGE_VIEW_TYPE_2D,
+ VK_FORMAT_B8G8R8A8_UNORM,
+ {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
+ VK_COMPONENT_SWIZZLE_A},
+ {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
+ };
+ VkImageView view;
+ err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view);
+ ASSERT_VK_SUCCESS(err);
+
+ VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+ nullptr,
+ 0,
+ m_renderPass,
+ 1,
+ &view,
+ 32,
+ 32,
+ 1};
+ VkFramebuffer fb;
+ err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb);
+ ASSERT_VK_SUCCESS(err);
+
+ // Just use default renderpass with our framebuffer
+ m_renderPassBeginInfo.framebuffer = fb;
+ // Create Null cmd buffer for submit
+ BeginCommandBuffer();
+ EndCommandBuffer();
+ // Destroy image attached to framebuffer to invalidate cmd buffer
+ vkDestroyImage(m_device->device(), image, NULL);
+ // Now attempt to submit cmd buffer and verify error
+ m_errorMonitor->SetDesiredFailureMsg(
+ VK_DEBUG_REPORT_ERROR_BIT_EXT, " that is invalid because bound image ");
+ QueueCommandBuffer(false);
+ m_errorMonitor->VerifyFound();
+
+ vkDestroyFramebuffer(m_device->device(), fb, nullptr);
+ vkDestroyImageView(m_device->device(), view, nullptr);
+ vkFreeMemory(m_device->device(), image_memory, nullptr);
+}
+
TEST_F(VkLayerTest, ImageMemoryNotBound) {
TEST_DESCRIPTION(
"Attempt to draw with an image which has not had memory bound to it.");