当源图像使用 VK_IMAGE_TILING_OPTIMAL 时,vkCmdCopyImageToBuffer 是否有效?

Does vkCmdCopyImageToBuffer work when source image uses VK_IMAGE_TILING_OPTIMAL?

我读过(在 运行 自己进入限制之后)从主机复制数据到 VK_IMAGE_TILING_OPTIMAL VkImage,你最好关闭使用 VkBuffer 而不是 VkImage 作为暂存图像,以避免对 mipmap 和层数的限制。 (Here and Here)

因此,在实现 glReadPixels 式的功能以将渲染到纹理的结果读回主机时,我认为使用 vkCmdCopyImageToBuffer 而不是使用暂存 VkImage 是个好主意。

但是,我还没有能够让它工作,我看到了大部分预期的图像,但是图像的矩形块位于不正确的位置,甚至有些位重复。

很有可能我在某处搞砸了我的同步或布局转换,我将继续调查这种可能性。

但是,我无法从规范中弄清楚将 vkCmdCopyImageToBuffer 与使用 VK_IMAGE_TILING_OPTIMAL 的图像源一起使用是否实际上应该 'un-tile' 图像,或者我是否真的应该如果我尝试这样做,预计会收到乱码的实现定义的图像布局。

所以我的问题是:使用 VK_IMAGE_TILING_OPTIMAL 源图像的 vkCmdCopyImageToBuffer 是否使用线性平铺数据或最佳(实现定义的)平铺数据填充缓冲区?

Section 18.4 描述了 source/destination 缓冲区中数据的布局,相对于正在复制的图像 from/to。 VkBufferImageCopy 结构的描述中对此进行了概述。本节中没有允许与平铺图像不同的行为的语言。

该规范甚至包含复制如何工作的伪代码(这是针对非块压缩图像):

rowLength = region->bufferRowLength;
if (rowLength == 0)
    rowLength = region->imageExtent.width;

imageHeight = region->bufferImageHeight;
if (imageHeight == 0)
    imageHeight = region->imageExtent.height;

texelSize = <texel size taken from the src/dstImage>;

address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelSize;

where x,y,z range from (0,0,0) to region->imageExtent.width,height,depth}.

x,y,z 部分是图像中相关像素的位置。由于此位置不依赖于图像的平铺(没有任何说明会如此),buffer/image 份副本将同样适用于两种平铺。

此外,请注意此规范在 vkCmdCopyImageToBuffervkCmdCopyBufferToImage 之间 共享 。因此,如果一个副本以一种方式工作,它必然必须以另一种方式工作。