Vulkan编程指南翻译 第四章 队列和命令 第4节 复制图像数据

2017-02-28

4.4  复制图像数据

前一节,我们讨论了如何清空图像并通过一个简单的数据结构来填充数据。在很多情况下,你需要把纹理数据上传到图像或者复制图像数据到另一图像。Vulkan支持从缓冲区向图像复制数据,在图像之间复制数据,和从图像向缓冲区复制数据。

调用vkCmdCopyBufferToImage()缓冲区向图像的一个或者多个区域复制数据原型如下:

void vkCmdCopyBufferToImage (

VkCommandBuffer  commandBuffer,

VkBuffer  srcBuffer,

VkImage  dstImage,

VkImageLayout  dstImageLayout,

uint32_t  regionCount,

const VkBufferImageCopy*  pRegions);

将要执行复制操作命令的命令缓冲区通过commandBuffer参数指定,源缓冲区srcBuffer参数指定,数据将要复制到的目标图像dstImage参数指定和需要清空的目标图像一样,目标图像的布局为 VK_IMAGE_LAYOUT_GENERAL  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL通过dstImageLayout参数指定。

需要更新的区域数量regionCount参数给定,pRegions参数是一个指针,指向一个大小为regionCount类型为VkBufferImageCopy的数组,每一个元素定义图像中需要向其复制数据的一区域VkBufferImageCopy定义如下

typedef struct VkBufferImageCopy {

VkDeviceSize  bufferOffset;

uint32_t  bufferRowLength;

uint32_t  bufferImageHeight;

VkImageSubresourceLayers  imageSubresource;

VkOffset3D  imageOffset;

VkExtent3D  imageExtent;

} VkBufferImageCopy;bufferOffset包含了缓冲区中数据的偏移量,单位是byte。缓冲区内的数据从左到右、从上到排放如图4.1所示。bufferRowLength指定了源图像中纹素的个数,bufferImageHeight图像数据行数。如果bufferRowLength0,图像就被认为是缓冲区中紧致压缩因此和imageExtent.width相等。同样,如果bufferImageHeight0,那么图像的行数就被认为和图像extend的高度亦即 imageExtent.height相等

 

4.1 缓冲区中图像的数据排放

需要复制数据到的子资源,是通过一个VkImageSubresourceLayers类型的数据来指定的。原型如下:

typedef struct VkImageSubresourceLayers {

VkImageAspectFlags  aspectMask;

uint32_t  mipLevel;

uint32_t  baseArrayLayer;

uint32_t  layerCount;

} VkImageSubresourceLayers;

VkImageSubresourceLayersaspectMask包含复制数据操作目标图像的aspect或多个aspect。通常,这将会是VkImageAspectFlagBits枚举中的某一个。如果目标图像是颜色图像,那么将是VK_IMAGE_ASPECT_DEPTH_BIT如果图像是stencil-only图像,它将是VK_IMAGE_ASPECT_STENCIL_BIT如果图像是复合的depth-stencil图像,那么你需要指定VK_IMAGE_ASPECT_DEPTH_BIT  VK_IMAGE_ASPECT_STENCIL_BIT这两个标志位,以同时复制数据到深度和stencil aspect

目标mipmap层数通过mipLevel参数指定。你可以pRegions数组中每一元素复制到mipmap某一层,即使你可以指定多个元素,每个对应不同的层。

如果目标图像是array 图像,那么你就可以通过baseArrayLayer 和layerCount指定图像的起始层和层数。如果图像不是array图像,那么这两个域就应该分别置为0和1.

每个区域可以对应一整个mipmap层或者一层中更小的一块窗口。窗口的偏移量通过imageOffset指定,窗口的大小通过imageExtent指定。可以通过设置 imageOffset.x 和

imageOffset.y 为0,imageExtent.width 和imageExtent.height分别为mipmap level的大小,来覆盖掉整个mipmap层。需要你自己来做计算,Vulkan不会替你做这个工作的。

也可以反方向的做复制操作--从一个图像对象复制数据到缓冲区。需要调用vkCmdCopyImageToBuffer()命令,其原型如下:

 

void vkCmdCopyImageToBuffer (

VkCommandBuffer  commandBuffer,

VkImage  srcImage,

VkImageLayout  srcImageLayout,

VkBuffer  dstBuffer,

uint32_t  regionCount,

const VkBufferImageCopy*  pRegions);

做这个操作的命令缓冲区通过commandBuffer指定,含有源数据的图像通过srcImage参数传递,复制操作的目标图像通过dstImage参数传递。再有,两个图像的布局也需要传递到复制命令。srcImageLayout是复制操作中期望的源图像布局,值为VK_IMAGE_LAYOUT_GENERAL或VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL(当它是转移操作的源)。同样的,dstImageLayout是期望的目标图像布局,值为VK_IMAGE_LAYOUT_GENERAL或VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL。

和“缓冲区至图像”,“图像至缓冲区”命令一样,vkCmdCopyImage()可同时复制多个区域。regionCount指定了复制区域的个数,每一个都通过VkImageCopy类型数组内的一个实例表示,数组的地址通过pRegions传递。VkImageCopy定义如下:

typedef struct VkImageCopy {

VkImageSubresourceLayers  srcSubresource;

VkOffset3D  srcOffset;

VkImageSubresourceLayers  dstSubresource;

VkOffset3D  dstOffset;

VkExtent3D  extent;

} VkImageCopy;

每一个VkImageCopy实例包含子资源信息和源、目标的窗口起始位置。vkCmdCopyImage()不能改变数据的尺寸,所以源和目标图像的extent是相同的,且包含在extent域。

srcSubresource包含子对源数据子资源的定义,和传递给vkCmdCopyImageToBuffer()命令的VkBufferImageCopy的imageSubresource域是相同的意思。同样,dstSubresource包含了对目标区域的子资源的定义,和传递给vkCmdCopyImageToBuffer()命令的VkBufferImageCopy的imageSubresource域意思相同。

如果有任何意见,欢迎留言讨论。


[ 主页 ]
COMMENTS
POST A COMMENT

(optional)



(optional)