src/ktx/libktx/vkloader.c
/**
 * @internal
 * @~English
 * @brief Callback for optimally tiled textures with possible source row
 *        padding.
 *
 * Copies data to the staging buffer removing row padding, if necessary.
 * Increments the offset for destination of the next copy increasing it to an
 * appropriate common multiple of the element size and 4 to comply with Vulkan
 * valid usage. Finally sets up a region to copy the face/lod from the staging
 * buffer to the final image.
 *
 * This longer method is needed because row padding is different between
 * KTX (pad to 4) and Vulkan (none). Also region->bufferOffset, i.e. the start
 * of each image, has to be a multiple of 4 and also a multiple of the
 * element size.
 *
 * This should be used with @c ktx_Texture_IterateFaceLevels or
 * @c ktx_Texture_IterateLoadLevelFaces. Face-level iteration has been
 * selected to minimize the buffering needed between reading the file and
 * copying the data into the staging buffer. Obviously when
 * @c ktx_Texture_IterateFaceLevels is being used, this is a moot point.
*
 * @copydetails PFNKTXITERCB
 */
@internal
@~English
@brief Callback for optimally tiled textures with possible source row
padding.

Copies data to the staging buffer removing row padding, if necessary.
Increments the offset for destination of the next copy increasing it to an
appropriate common multiple of the element size and 4 to comply with Vulkan
valid usage. Finally sets up a region to copy the face/lod from the staging
buffer to the final image.

This longer method is needed because row padding is different between
KTX (pad to 4) and Vulkan (none).

This should be used with @c ktx_Texture_IterateFaceLevels or
@c ktx_Texture_IterateLoadLevelFaces. Face-level iteration has been
selected to minimize the buffering needed between reading the file and
copying the data into the staging buffer. Obviously when
@c ktx_Texture_IterateFaceLevels is being used, this is a moot point.

@copydetails PFNKTXITERCB
@internal @~English @brief Callback for optimally tiled textures with possible source row padding . Copies data to the staging buffer removing row padding if necessary . Increments the offset for destination of the next copy increasing it to an appropriate common multiple of the element size and 4 to comply with Vulkan valid usage . Finally sets up a region to copy the face / lod from the staging buffer to the final image . This longer method is needed because row padding is different between KTX ( pad to 4 ) and Vulkan ( none ) . This should be used with @c ktx_Texture_IterateFaceLevels or @c ktx_Texture_IterateLoadLevelFaces . Face - level iteration has been selected to minimize the buffering needed between reading the file and copying the data into the staging buffer . Obviously when @c ktx_Texture_IterateFaceLevels is being used this is a moot point . @copydetails PFNKTXITERCB
KTX_error_code
optimalTilingPadCallback(int miplevel, int face,
                         int width, int height, int depth,
                         ktx_uint64_t faceLodSize,
                         void* pixels, void* userdata)
{
    user_cbdata_optimal* ud = (user_cbdata_optimal*)userdata;
    ktx_uint32_t rowPitch = width * ud->elementSize;
#if defined(_DEBUG)
    assert(ud->region < ud->regionsArrayEnd);
#endif
    ud->region->bufferOffset = ud->offset;
    if (_KTX_PAD_UNPACK_ALIGN_LEN(rowPitch) == 0) {
        memcpy(ud->dest + ud->offset, pixels, faceLodSize);
        ud->offset += faceLodSize;
    } else {
		ktx_uint32_t image, imageIterations;
		ktx_int32_t row;
        ktx_uint32_t rowPitch, paddedRowPitch;
        if (ud->numDimensions == 3)
            imageIterations = depth;
        else if (ud->numLayers > 1)
            imageIterations = ud->numLayers * ud->numFaces;
        else
            imageIterations = 1;
        rowPitch = paddedRowPitch = width * ud->elementSize;
        paddedRowPitch = _KTX_PAD_UNPACK_ALIGN(paddedRowPitch);
        for (image = 0; image < imageIterations; image++) {
            for (row = 0; row < height; row++) {
                memcpy(ud->dest + ud->offset, pixels, rowPitch);
                ud->offset += rowPitch;
                pixels = (ktx_uint8_t*)pixels + paddedRowPitch;
            }
        }
    }
    if (ud->offset % ud->elementSize != 0 || ud->offset % 4 != 0) {
        assert(ud->elementSize < 4 && ud->elementSize > 0);
        ktx_uint32_t lcm = lcm4(ud->elementSize);
        ud->offset = _KTX_PADN(lcm, ud->offset);
    }
    ud->region->bufferRowLength = 0;
    ud->region->bufferImageHeight = 0;
    ud->region->imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    ud->region->imageSubresource.mipLevel = miplevel;
    ud->region->imageSubresource.baseArrayLayer = face;
    ud->region->imageSubresource.layerCount = ud->numLayers * ud->numFaces;
    ud->region->imageOffset.x = 0;
    ud->region->imageOffset.y = 0;
    ud->region->imageOffset.z = 0;
    ud->region->imageExtent.width = width;
    ud->region->imageExtent.height = height;
    ud->region->imageExtent.depth = depth;
    ud->region += 1;
    return KTX_SUCCESS;
}
KTX_error_code optimalTilingPadCallback ( int miplevel , int face , int width , int height , int depth , ktx_uint64_t faceLodSize , void * pixels , void * userdata ) { user_cbdata_optimal * ud = ( user_cbdata_optimal * ) userdata ; ktx_uint32_t rowPitch = width * ud -> elementSize ; #if defined ( _DEBUG ) assert ( ud -> region < ud -> regionsArrayEnd ) ; #endif ud -> region -> bufferOffset = ud -> offset ; if ( _KTX_PAD_UNPACK_ALIGN_LEN ( rowPitch ) == 0 ) { memcpy ( ud -> dest + ud -> offset , pixels , faceLodSize ) ; ud -> offset += faceLodSize ; } else { ktx_uint32_t image , imageIterations ; ktx_int32_t row ; ktx_uint32_t rowPitch , paddedRowPitch ; if ( ud -> numDimensions == 3 ) imageIterations = depth ; else if ( ud -> numLayers > 1 ) imageIterations = ud -> numLayers * ud -> numFaces ; else imageIterations = 1 ; rowPitch = paddedRowPitch = width * ud -> elementSize ; paddedRowPitch = _KTX_PAD_UNPACK_ALIGN ( paddedRowPitch ) ; for ( image = 0 ; image < imageIterations ; image ++ ) { for ( row = 0 ; row < height ; row ++ ) { memcpy ( ud -> dest + ud -> offset , pixels , rowPitch ) ; ud -> offset += rowPitch ; pixels = ( ktx_uint8_t * ) pixels + paddedRowPitch ; } } } if ( ud -> offset % ud -> elementSize != 0 || ud -> offset % 4 != 0 ) { assert ( ud -> elementSize < 4 && ud -> elementSize > 0 ) ; ktx_uint32_t lcm = lcm4 ( ud -> elementSize ) ; ud -> offset = _KTX_PADN ( lcm , ud -> offset ) ; } ud -> region -> bufferRowLength = 0 ; ud -> region -> bufferImageHeight = 0 ; ud -> region -> imageSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ; ud -> region -> imageSubresource . mipLevel = miplevel ; ud -> region -> imageSubresource . baseArrayLayer = face ; ud -> region -> imageSubresource . layerCount = ud -> numLayers * ud -> numFaces ; ud -> region -> imageOffset . x = 0 ; ud -> region -> imageOffset . y = 0 ; ud -> region -> imageOffset . z = 0 ; ud -> region -> imageExtent . width = width ; ud -> region -> imageExtent . height = height ; ud -> region -> imageExtent . depth = depth ; ud -> region += 1 ; return KTX_SUCCESS ; }
@internal
 @~English
 @brief Callback for optimally tiled textures with possible source row
        padding.
@internal @~English @brief Callback for optimally tiled textures with possible source row padding .
// Set bufferOffset in destination region in final image // Copy data into staging buffer // No padding. Can copy in bulk. // Must remove padding. Copy a row at a time. // Round to needed multiples for next region, if necessary. // Only elementSizes of 1,2 and 3 will bring us here. // These 2 are expressed in texels; not suitable for dealing with padding.