// Copyright (c) 2020 Qualcomm Technologies Incorporated
//
// SPDX-License-Identifier: CC-BY-4.0


[[copies-buffers-images-rotation-addressing]]
=== Buffer and Image Addressing with Rotation

When slink:VkCopyCommandTransformInfoQCOM is in the pname:pNext chain of
slink:VkBufferImageCopy2KHR, a _rotated copy_ is specified.
For both flink:vkCmdCopyImageToBuffer2KHR and
flink:vkCmdCopyBufferToImage2KHR, a rotation is applied to the region used
for image accesses, but a non-rotated region is used for buffer accesses.
In the case of rotated flink:vkCmdCopyImageToBuffer2KHR, the source image
region is rotated.
In the case of rotated flink:vkCmdCopyBufferToImage2KHR, the destination
image region is rotated.

For a _rotated copy_, the following description of rotated addressing
replaces the description in <<copies-buffers-images-addressing,Buffer and
Image Addressing>>.

The following code computes rotation of unnormalized coordinates.
[source,c]
---------------------------------------------------
// Forward rotation of unnormalized coordinates
VkOffset2D RotateUV(VkOffset2D in, VkSurfaceTransformFlagBitsKHR flags)
{
    VkOffset2D output;
    switch (flags)
    {
        case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
            out.x = in.x;
            out.y = in.y;
            break;
        case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
            out.x = -in.y;
            out.y = in.x;
            break;
        case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
            out.x = -in.x;
            out.y = -in.y;
            break;
        case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
            out.x = in.y;
            out.y = -in.x;
            break;
    }
    return out;
}
---------------------------------------------------

Pseudocode for image/buffer addressing of uncompressed formats with rotation
is:

[source,c]
---------------------------------------------------
rowLength = region->bufferRowLength;
if (rowLength == 0)
    rowLength = region->imageExtent.width;

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

texelBlockSize = <texel block size of the format of the src/dstImage>;

// Buffer addressing is unaffected by rotation:
address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize;

// When copying from buffer to image, the source buffer coordinates x,y,z range from (0,0,0) to
// region->imageExtent.{width,height,depth}.  The source extent is rotated by the specified
// VK_SURFACE_TRANSFORM, centered on the imageOffset, to define a rotated destination region.
// For each source buffer texel with coordinates (x,y) the rotated destination image texel has
// coordinates (x',y') defined as:
(x',y')= RotateUV(x,y) + ImageOffset.{x,y}

// When copying from image to buffer, the the destination buffer coordinates x,y,z range from (0,0,0) to
// region->imageExtent.{width,height,depth}.  The destination extent is rotated by the specified
//  VK_SURFACE_TRANSFORM, centered on the imageOffset, to define a rotated source region.  For each destination
// buffer texel with coordinates (x,y) the rotated source image texel has coordinates (x',y') defined as:
(x',y')= RotateUV(x,y) + ImageOffset.{x,y}

---------------------------------------------------

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