Vulkan icon indicating copy to clipboard operation
Vulkan copied to clipboard

Sparse texture example leaves mips > 0 in UNDEFINED layout

Open baldurk opened this issue 4 years ago • 1 comments

The texturesparseresidency example only seems to barrier/transition image layout for mip 0. This produces validation layer errors because the other mips are in UNDEFINED:

ERROR: [1303270965][UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout] : Validation Error: [ UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout ] Object 0: handle = 0x52f21b8, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x4dae5635 | Submitted command buffer expects VkImage 0xd20a5a000000003f[] (subresource: aspectMask 0x1 array layer 0, mip level 1) to be in layout VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL--instead, current layout is VK_IMAGE_LAYOUT_UNDEFINED.

And similarly for mips 2-13.

The overload of vks::tools::setImageLayout that is called within the sample only transitions the first mip in the first slice (I assumed a shortcut for the common case of a render target with no mips/slices). I locally switched to store the subresource range and use the other overload, but there may be a better fix you prefer especially if you don't want to transition the whole image every time:

diff --git a/examples/texturesparseresidency/texturesparseresidency.cpp b/examples/texturesparseresidency/texturesparseresidency.cpp
index 1c7a348..a47bfe1 100644
--- a/examples/texturesparseresidency/texturesparseresidency.cpp
+++ b/examples/texturesparseresidency/texturesparseresidency.cpp
@@ -187,6 +187,8 @@ void VulkanExample::prepareSparseTexture(uint32_t width, uint32_t height, uint32
 	texture.layerCount = layerCount;
 	texture.format = format;
 
+	texture.subRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, texture.mipLevels, 0, 1 };
+
 	// Get device properties for the requested texture format
 	VkFormatProperties formatProperties;
 	vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
@@ -236,7 +238,7 @@ void VulkanExample::prepareSparseTexture(uint32_t width, uint32_t height, uint32
 	VK_CHECK_RESULT(vkCreateImage(device, &sparseImageCreateInfo, nullptr, &texture.image));
 
 	VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
-	vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+	vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, texture.subRange);
 	vulkanDevice->flushCommandBuffer(copyCmd, queue);
 
 	// Get memory requirements
@@ -733,7 +735,7 @@ void VulkanExample::uploadContent(VirtualTexturePage page, VkImage image)
 	}
 
 	VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
-	vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
+	vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
 	VkBufferImageCopy region{};
 	region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 	region.imageSubresource.layerCount = 1;
@@ -741,7 +743,7 @@ void VulkanExample::uploadContent(VirtualTexturePage page, VkImage image)
 	region.imageOffset = page.offset;
 	region.imageExtent = page.extent;
 	vkCmdCopyBufferToImage(copyCmd, imageBuffer.buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
-	vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+	vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
 	vulkanDevice->flushCommandBuffer(copyCmd, queue);
 
 	imageBuffer.destroy();
@@ -850,7 +852,7 @@ void VulkanExample::fillMipTail()
 		}
 
 		VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
-		vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
+		vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
 		VkBufferImageCopy region{};
 		region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 		region.imageSubresource.layerCount = 1;
@@ -858,7 +860,7 @@ void VulkanExample::fillMipTail()
 		region.imageOffset = {};
 		region.imageExtent = { width, height, depth };
 		vkCmdCopyBufferToImage(copyCmd, imageBuffer.buffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
-		vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
+		vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
 		vulkanDevice->flushCommandBuffer(copyCmd, queue);
 
 		imageBuffer.destroy();
diff --git a/examples/texturesparseresidency/texturesparseresidency.h b/examples/texturesparseresidency/texturesparseresidency.h
index bcc1958..05adaa7 100644
--- a/examples/texturesparseresidency/texturesparseresidency.h
+++ b/examples/texturesparseresidency/texturesparseresidency.h
@@ -73,6 +73,7 @@ public:
 		uint32_t width, height;
 		uint32_t mipLevels;
 		uint32_t layerCount;
+		VkImageSubresourceRange subRange;
 	} texture;
 
 	vkglTF::Model plane;

baldurk avatar Mar 08 '21 16:03 baldurk

The dreaded sparse residency sample ;) I never got myself to put much work into it.

Thanks for raising this issue and posting your fix. I'll take a look at it and see if this is viable.

SaschaWillems avatar Mar 12 '21 19:03 SaschaWillems

Looks like I fixed this at some point using a very similar approach. At least I'm not getting any validation layer errors with the current state of the sample.

SaschaWillems avatar Dec 13 '22 19:12 SaschaWillems