4.6 展开图像
所有目前讲到的图片相关的命令,没有一个支持格式转换和改变复制区域的尺寸。你可以调用vkCmdBlitImage()实现这个功能,它可以接受不同格式的图像并展开或缩小需要复制的区域,当这些区域写入到目标图像时。术语blit是 block image transfer的缩写,指不仅需要复制图像数据,并且也可能需要在此过程中处理数据。vkCmdBlitImage()的原型如下:
void vkCmdBlitImage (
VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkImage dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkImageBlit* pRegions,
VkFilter filter);
将执行此命令的命令缓冲区通过commandBuffer参数传递。源图像和目标图像各通过srcImage 和dstImage 参数传递。再有,和vkCmdCopyImage()一样,期望的源图像和目标图像的布局通过srcImageLayout 和dstImageLayout参数传递。源图像的布局是VK_IMAGE_LAYOUT_GENERAL 或者VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,目标图像的布局是VK_IMAGE_LAYOUT_GENERAL 或者VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMA。
和其他的复制命令一样,vkCmdBlitImage()可复制源图像的任意数量区域到目标图像,每一个区域都通过一个数据结构表示。区域的数量由regionCount参数传递,pRegion指向了一个大小为regionCount的数组,每一个元素定义了一个需要复制的区域。VkImageBlit的定义为:
typedef struct VkImageBlit {
VkImageSubresourceLayers srcSubresource;
VkOffset3D srcOffsets[2];
VkImageSubresourceLayers dstSubresource;
VkOffset3D dstOffsets[2];
} VkImageBlit;
VkImageBlit的srcSubresource 和dstSubresource域定义了源图像和目标图像的子资源。然而,在VkImageCopy中每一个区域都被一个VkOffset3D类型的数据定义,并共享一个VkExtent3D,在VkImageBlit中每一个区域都通过一对VkOffset3D数据(两个元素的数组)定义。
srcOffsets 和dstOffsets数组的第一个元素定义了将被复制的区域的一侧,数组的第二个元素定义了区域的另外一侧。源图像中srcOffsets定义的区域被复制到了dstOffsets定义的目标图像。如果这两个区域其中一个对于另外一个是“上下颠倒的”,那么复制的区域将会被垂直翻转。同理,如果一个区域相对域另外一个“前后颠倒的”,那么图像就会被水平翻转。如果这两种情况都满足,那么复制的区域和原区域相比就被旋转180度了。
如果在源区域和目标区域的巨型尺寸不相同,那么图像就会被相应的放大或缩小。这种情况下,vkCmdBlitImage()命令filter参数定义的过滤模式将会被应用到数据的过滤上。Filter必须是VK_FILTER_NEAREST 或VK_FILTER_LINEAR其一,分别用于点采样或线性采样。
源图像的格式必须是支持VK_FORMAT_FEATURE_BLIT_SRC_BIT特性的其中一种。在绝大多数Vulkan实现中,这几乎包含了所有的图像格式。还有,目标图像格式必须是支持VK_FORMAT_FEATURE_BLIT_DST_BIT的其中一种。通常,这是任何可以在shader内渲染到或者设备可写入的格式。Vulkan设备不大有可能会支持在压缩图像格式上blit操作。
总结
本章讲解了如何清空图像并填充数据。我们使用命令缓冲区中的命令把少量的数据直接写入缓冲区对象,并解释了Vulkan是如何把在缓冲区和图像互相之间、和一对图像之间复制数据。最后,我们介绍了blit的概念,它是一个在复制数据时允许把数据缩放和转换图像格式的操作。这些操作提供了获取大量数据进出Vulkan设备以供后续处理的基础。