vkGetImageSubresourceLayout gives no row pitch

Hi! I’m creating an image with the following information:

VkImageCreateInfo info =
	height > 1 ? VK_IMAGE_TYPE_2D : VK_IMAGE_TYPE_1D,
	cube ? numFaces : numImages,

Where in my case mips is 9, cube is false and numImages is 1, height is 256 and extents is 256, 256, 1. The memory is created using the VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT only. However, when running the following:

vkImageSubresource subres;
subres.arrayLayer = 0;
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subres.mipLevel = mip;
VkSubresourceLayout layout;
vkGetImageSubresourceLayout(VkRenderDevice::dev, this->img, &subres, &layout);

‘layout’ becomes:
offset: 0
size: 65536
rowPitch: 0
arrayPitch: 89600
depthPitch: 89600

Basically I get no bytes per row, but I do get bytes per array layer, which is also bigger than the entire size of my image. Is the vkGetImageSubresourceLayout only available for certain types of images? The memoryTypeBits I get from vkGetImageMemoryRequirements is 2, and the two first memory properties are 0 and 1 respectively, so the only flags I can use when allocating image memory is either 0, or VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT.

Anyways, tested this on an AMD card and it works fine, I get a valid row, array and depth pitch for each mip level.


The Vulkan Spec 1.0.6 says on page 207: The layout of a subresource (mipLevel/arrayLayer) of an image created with linear tiling is queried by calling: void vkGetImageSubresourceLayout

So vkGetImageSubresourceLayout is only a valid call for images created with linear tiling. Images with optimal tiling may not even be arranged in rows, their layout in memory is unspecified. They could be arranged in 4x4 pixels, recursive quads, or any arbitrary mapping. Linear images on the other hand are kind of a niche feature, so i would not use them unless you know why you want them.

Instead you have to use the copy image commands to transfer data to and from optimal tiling images. So for textures, the usage should be at least VK_IMAGE_USAGE_SAMPLED_BIT (to sample in a shader) and VK_IMAGE_USAGE_TRANSFER_DST_BIT (to upload the texture). Then you can create a host-visible buffer with VK_BUFFER_USAGE_TRANSFER_SRC_BIT, memory map it, copy your texture to it, and then use vkCmdCopyBufferToImage to upload it to the image. The pixel layout in the buffer is always linear, and you set the row stride yourself and supply it to vkCmdCopyBufferToImage.

Hope this helps.