## 18.4. Copying Data Between Buffers and Images

To copy data from a buffer object to an image object, call:

void vkCmdCopyBufferToImage(
VkCommandBuffer                             commandBuffer,
VkBuffer                                    srcBuffer,
VkImage                                     dstImage,
VkImageLayout                               dstImageLayout,
uint32_t                                    regionCount,
const VkBufferImageCopy*                    pRegions);

• commandBuffer is the command buffer into which the command will be recorded.
• srcBuffer is the source buffer.
• dstImage is the destination image.
• dstImageLayout is the layout of the destination image subresources for the copy.
• regionCount is the number of regions to copy.
• pRegions is a pointer to an array of VkBufferImageCopy structures specifying the regions to copy.

Each region in pRegions is copied from the specified region of the source buffer to the specified region of the destination image.

To copy data from an image object to a buffer object, call:

void vkCmdCopyImageToBuffer(
VkCommandBuffer                             commandBuffer,
VkImage                                     srcImage,
VkImageLayout                               srcImageLayout,
VkBuffer                                    dstBuffer,
uint32_t                                    regionCount,
const VkBufferImageCopy*                    pRegions);

• commandBuffer is the command buffer into which the command will be recorded.
• srcImage is the source image.
• srcImageLayout is the layout of the source image subresources for the copy.
• dstBuffer is the destination buffer.
• regionCount is the number of regions to copy.
• pRegions is a pointer to an array of VkBufferImageCopy structures specifying the regions to copy.

Each region in pRegions is copied from the specified region of the source image to the specified region of the destination buffer.

For both vkCmdCopyBufferToImage and vkCmdCopyImageToBuffer, each element of pRegions is a structure defined as:

typedef struct VkBufferImageCopy {
VkDeviceSize                bufferOffset;
uint32_t                    bufferRowLength;
uint32_t                    bufferImageHeight;
VkImageSubresourceLayers    imageSubresource;
VkOffset3D                  imageOffset;
VkExtent3D                  imageExtent;
} VkBufferImageCopy;

• bufferOffset is the offset in bytes from the start of the buffer object where the image data is copied from or to.
• bufferRowLength and bufferImageHeight specify the data in buffer memory as a subregion of a larger two- or three-dimensional image, and control the addressing calculations of data in buffer memory. If either of these values is zero, that aspect of the buffer memory is considered to be tightly packed according to the imageExtent.
• imageSubresource is a VkImageSubresourceLayers used to specify the specific image subresources of the image used for the source or destination image data.
• imageOffset selects the initial x, y, z offsets in texels of the sub-region of the source or destination image data.
• imageExtent is the size in texels of the image to copy in width, height and depth. 1D images use only x and width. 2D images use x, y, width and height. 3D images use x, y, z, width, height and depth.

When copying to or from a depth or stencil aspect, the data in buffer memory uses a layout that is a (mostly) tightly packed representation of the depth or stencil data. Specifically:

• data copied to or from the stencil aspect of any depth/stencil format is tightly packed with one VK_FORMAT_S8_UINT value per texel.
• data copied to or from the depth aspect of a VK_FORMAT_D16_UNORM or VK_FORMAT_D16_UNORM_S8_UINT format is tightly packed with one VK_FORMAT_D16_UNORM value per texel.
• data copied to or from the depth aspect of a VK_FORMAT_D32_SFLOAT or VK_FORMAT_D32_SFLOAT_S8_UINT format is tightly packed with one VK_FORMAT_D32_SFLOAT value per texel.
• data copied to or from the depth aspect of a VK_FORMAT_X8_D24_UNORM_PACK32 or VK_FORMAT_D24_UNORM_S8_UINT format is packed with one 32-bit word per texel with the D24 value in the LSBs of the word, and undefined values in the eight MSBs.
Note To copy both the depth and stencil aspects of a depth/stencil format, two entries in pRegions can be used, where one specifies the depth aspect in imageSubresource, and the other specifies the stencil aspect.

Because depth or stencil aspect buffer to image copies may require format conversions on some implementations, they are not supported on queues that do not support graphics.

Copies are done layer by layer starting with image layer baseArrayLayer member of imageSubresource. layerCount layers are copied from the source image or to the destination image.

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}.

Note that imageOffset does not affect addressing calculations for buffer memory. Instead, bufferOffset can be used to select the starting address in buffer memory.

For block-compression formats, all parameters are still specified in texels rather than compressed texel blocks, but the addressing math operates on whole compressed texel blocks. Pseudocode for compressed copy addressing is:

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

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

compressedTexelBlockSizeInBytes = <compressed texel block size taken from the src/dstImage>;
rowLength /= compressedTexelBlockWidth;
imageHeight /= compressedTexelBlockHeight;

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

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

Copying to or from block-compressed images is typically done in multiples of the compressed texel block. For this reason the imageExtent must be a multiple of the compressed texel block dimension. There is one exception to this rule which is required to handle compressed images created with dimensions that are not a multiple of the compressed texel block dimensions. If imageExtent.width is not a multiple of the compressed texel block width then (imageExtent.width + imageOffset.x) must equal the image subresource width, if imageExtent.height is not a multiple of the compressed texel block height then (imageExtent.height imageOffset.y) must equal the image subresource height and if imageExtent.depth is not a multiple of the compressed texel block depth then (imageExtent.depth + imageOffset.z) must equal the image subresource depth. This allows the last compressed texel block of the image in each non-multiple dimension to be included as a source or destination of the copy.