Reputation: 1588
What I'm trying to achieve is load an image file into memory and copy its contents into a new VkImage
. There's a lot of steps involved, but this question only seeks some clarification regarding the possibilities of using _PREINITIALIZED
as the initial image layout.
According to the spec, I can use preinitialized image layout to remove the need for an initial layout transition:
VK_IMAGE_LAYOUT_PREINITIALIZED specifies that an image’s memory is in a defined layout and can be populated by data, but that it has not yet been initialized by the driver. Image memory cannot be transitioned into this layout. This layout can be used as the initialLayout member of VkImageCreateInfo. This layout is intended to be used as the initial layout for an image whose contents are written by the host, and hence the data can be written to memory immediately, without first executing a layout transition. Currently, VK_IMAGE_LAYOUT_PREINITIALIZED is only useful with linear images because there is not a standard layout defined for VK_IMAGE_TILING_OPTIMAL images.
This is my program flow:
unsigned char* imgData = ... // image loaded from disk
VkBuffer stagingBuffer = ... // host-visible memory!
VkImageCreateInfo imageInfo{};
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; // <-- This is what I want!
VkImage img = // image created
vmaMapMemory(...); // on the staging buffer
memcpy(...); // using the mapped pointer and the loaded image data
vmaUnmap(...); // remove the mapping
VkCommandBuffer cmdBuf = ... // single-use transfer
vkBeginCommandBuffer(...);
VkBufferImageCopy copyRegion{}; // filled out appropriately
vkCmdCopyBufferToImage(cmdBuf, stagingBuffer, img, VK_IMAGE_LAYOUT_PREINITIALIZED, 1, ©Region);
VkImageMemoryBarrier barrier{};
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.image = img;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
// NOTE: I have also tried using VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier(
cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0, 0, nullptr, 0, nullptr, 1, &barrier);
vkEndCommandBuffer(cmdBuf);
vkQueueSubmit(...); // do the stuff
I get a validation error which confuses me:
Validation Error: [ VUID-vkCmdCopyBufferToImage-dstImageLayout-00181 ] Object 0: handle = 0x561d95599b70, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x98877a9a | vkCmdCopyBufferToImage: Layout for VkImage 0x1c000000001c[] is VK_IMAGE_LAYOUT_PREINITIALIZED but can only be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL. The Vulkan spec states: dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.3/html/vkspec.html#VUID-vkCmdCopyBufferToImage-dstImageLayout-00181)
I thought the whole point of having the possibility to specify _PREINITIALIZED
was to explicitly NOT do an initial layout transition. But apparently, the image must be _TRANSFER_DST_OPTIMAL
- otherwise I can't write to it.
I should note that I want the final image to have _TILING_OPTIMAL
! And this is probably the most important design goal here.
Upvotes: 0
Views: 586
Reputation: 13306
VK_IMAGE_LAYOUT_PREINITIALIZED
permits writing to the mapped memory (via vkMapMemory
. It does not permit any other use, such as copy commands.
Upvotes: 2