Skip to content

Commit

Permalink
Add vkformat checks to ktxTexture2_DecodeAstc (#967)
Browse files Browse the repository at this point in the history
* Adds checks for vkformat fixes #960 
* Propogates vkformat correctly into creating astc profile
  • Loading branch information
wasimabbas-arm authored Jan 8, 2025
1 parent 7a8cd47 commit aa6af91
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 110 deletions.
2 changes: 1 addition & 1 deletion include/ktx.h
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ KTX_API KTX_error_code KTX_APIENTRY
ktxTexture2_CompressAstc(ktxTexture2* This, ktx_uint32_t quality);

KTX_API KTX_error_code KTX_APIENTRY
ktxTexture2_DecodeAstc(ktxTexture2* This, ktx_uint32_t vkformat);
ktxTexture2_DecodeAstc(ktxTexture2* This);

/**
* @memberof ktxTexture2
Expand Down
213 changes: 110 additions & 103 deletions lib/astc_codec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ unorm8x4ArrayToImage(const uint8_t *data, uint32_t dim_x, uint32_t dim_y) {

/**
* @memberof ktxTexture
* @internal
* @ingroup writer
* @~English
* @brief Creates default ASTC parameters
Expand All @@ -222,6 +223,7 @@ astcDefaultOptions() {

/**
* @memberof ktxTexture
* @internal
* @ingroup writer
* @~English
* @brief Should be used to get VkFormat from ASTC block enum
Expand Down Expand Up @@ -291,38 +293,121 @@ astcVkFormat(ktx_uint32_t block_size, bool sRGB) {

/**
* @memberof ktxTexture
* @ingroup writer
* @internal
* @ingroup reader
* @~English
* @brief Creates valid ASTC encoder action from string.
* @brief Should be used to get uncompressed version of ASTC VkFormat
*
* @return Valid astc_profile from string
* The decompressed format is calculated from corresponding ASTC format. There are
* only 3 possible options currently supported. RGBA8, SRGBA8 and RGBA32.
*
* @return Uncompressed version of VKFormat for a specific ASTC VkFormat
*/
static astcenc_profile
astcEncoderAction(const ktxAstcParams &params, const uint32_t* bdb) {
inline VkFormat getUncompressedFormat(ktxTexture2* This) noexcept {
uint32_t* BDB = This->pDfd + 1;

ktx_uint32_t transfer = KHR_DFDVAL(bdb, TRANSFER);
if (KHR_DFDSVAL(BDB, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) {
return VK_FORMAT_R32G32B32A32_SFLOAT;
} else {
if (khr_df_transfer_e(KHR_DFDVAL(BDB, TRANSFER) == KHR_DF_TRANSFER_SRGB))
return VK_FORMAT_R8G8B8A8_SRGB;
else
return VK_FORMAT_R8G8B8A8_UNORM;
}
}

if (transfer == KHR_DF_TRANSFER_SRGB &&
params.mode == KTX_PACK_ASTC_ENCODER_MODE_LDR)
/**
* @memberof ktxTexture
* @internal
* @ingroup reader
* @~English
* @brief Should be used to check if an ASTC VkFormat is LDR format or not.
*
* @return true if the VkFormat is an ASTC LDR format.
*/
inline bool isFormatAstcLDR(ktxTexture2* This) noexcept {
return (KHR_DFDSVAL(This->pDfd + 1, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) == 0;
}

/**
* @memberof ktxTexture
* @internal
* @ingroup reader writer
* @~English
* @brief Creates valid ASTC decoder profile from VkFormat
*
* @return Valid astc_profile from VkFormat
*/
static astcenc_profile
astcProfile(bool sRGB, bool ldr) {

if (sRGB && ldr)
return ASTCENC_PRF_LDR_SRGB;
else if (transfer == KHR_DF_TRANSFER_LINEAR) {
if (params.mode == KTX_PACK_ASTC_ENCODER_MODE_LDR)
else if (!sRGB) {
if (ldr)
return ASTCENC_PRF_LDR;
else
return ASTCENC_PRF_HDR;
}
// TODO: Add support for the following
// KTX_PACK_ASTC_ENCODER_ACTION_COMP_HDR_RGB_LDR_ALPHA; currently not supported

assert(ldr && "HDR sRGB profile not supported");

return ASTCENC_PRF_LDR_SRGB;
}

/**
* @memberof ktxTexture
* @internal
* @ingroup writer
* @~English
* @brief Creates valid ASTC encoder profile provided params and bdb
*
* @return Valid astc_profile from params and bdb
*/
static astcenc_profile
astcEncoderProfile(const ktxAstcParams &params, const uint32_t* bdb) {

ktx_uint32_t transfer = KHR_DFDVAL(bdb, TRANSFER);

bool sRGB = transfer == KHR_DF_TRANSFER_SRGB;
bool ldr = params.mode == KTX_PACK_ASTC_ENCODER_MODE_LDR;

if (!sRGB) {
assert(transfer == KHR_DF_TRANSFER_LINEAR && "Unsupported transfer function, only support sRGB and Linear");
}

return astcProfile(sRGB, ldr);
}

/**
* @memberof ktxTexture
* @internal
* @ingroup reader
* @~English
* @brief Creates valid ASTC decoder profile from VkFormat
*
* @return Valid astc_profile from VkFormat
*/
static astcenc_profile
astcDecoderProfile(ktxTexture2 *This) {

uint32_t* BDB = This->pDfd + 1;
ktx_uint32_t transfer = KHR_DFDVAL(BDB, TRANSFER);

bool sRGB = transfer == KHR_DF_TRANSFER_SRGB;
bool ldr = isFormatAstcLDR(This);

return astcProfile(sRGB, ldr);
}

/**
* @memberof ktxTexture
* @internal
* @ingroup writer
* @~English
* @brief Creates valid ASTC encoder swizzle from string.
* @brief Creates valid ASTC encoder swizzle from string.
*
* @return Valid astcenc_swizzle from string
*/
Expand Down Expand Up @@ -391,88 +476,6 @@ astcBlockDimensions(ktx_uint32_t block_size,
}
}


static void
astcBlockDimensions(VkFormat format,
uint32_t &x, uint32_t &y, uint32_t &z) noexcept {
switch (format) {
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: x = 4; y = 4; z = 0; break;
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: x = 4; y = 4; z = 0; break;
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: x = 5; y = 4; z = 0; break;
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: x = 5; y = 4; z = 0; break;
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: x = 5; y = 5; z = 0; break;
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: x = 5; y = 5; z = 0; break;
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: x = 6; y = 5; z = 0; break;
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: x = 6; y = 5; z = 0; break;
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: x = 6; y = 6; z = 0; break;
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: x = 6; y = 6; z = 0; break;
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: x = 8; y = 5; z = 0; break;
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: x = 8; y = 5; z = 0; break;
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: x = 8; y = 6; z = 0; break;
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: x = 8; y = 6; z = 0; break;
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: x = 8; y = 8; z = 0; break;
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: x = 8; y = 8; z = 0; break;
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: x = 10; y = 5; z = 0; break;
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: x = 10; y = 5; z = 0; break;
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: x = 10; y = 6; z = 0; break;
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: x = 10; y = 6; z = 0; break;
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: x = 10; y = 8; z = 0; break;
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: x = 10; y = 8; z = 0; break;
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: x = 10; y = 10; z = 0; break;
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: x = 10; y = 10; z = 0; break;
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: x = 12; y = 10; z = 0; break;
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: x = 12; y = 10; z = 0; break;
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: x = 12; y = 12; z = 0; break;
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: x = 12; y = 12; z = 0; break;
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: x = 4; y = 4; z = 0; break;
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: x = 5; y = 4; z = 0; break;
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: x = 5; y = 5; z = 0; break;
case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: x = 6; y = 5; z = 0; break;
case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: x = 6; y = 6; z = 0; break;
case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: x = 8; y = 5; z = 0; break;
case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: x = 8; y = 6; z = 0; break;
case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: x = 8; y = 8; z = 0; break;
case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: x = 10; y = 5; z = 0; break;
case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: x = 10; y = 6; z = 0; break;
case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: x = 10; y = 8; z = 0; break;
case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: x = 10; y = 10; z = 0; break;
case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: x = 12; y = 10; z = 0; break;
case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: x = 12; y = 12; z = 0; break;
case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: x = 3; y = 3; z = 3; break;
case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: x = 3; y = 3; z = 3; break;
case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: x = 3; y = 3; z = 3; break;
case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT: x = 4; y = 3; z = 3; break;
case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT: x = 4; y = 3; z = 3; break;
case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT: x = 4; y = 3; z = 3; break;
case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT: x = 4; y = 4; z = 3; break;
case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT: x = 4; y = 4; z = 3; break;
case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT: x = 4; y = 4; z = 3; break;
case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT: x = 4; y = 4; z = 4; break;
case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT: x = 4; y = 4; z = 4; break;
case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT: x = 4; y = 4; z = 4; break;
case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT: x = 5; y = 4; z = 4; break;
case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT: x = 5; y = 4; z = 4; break;
case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT: x = 5; y = 4; z = 4; break;
case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT: x = 5; y = 5; z = 4; break;
case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT: x = 5; y = 5; z = 4; break;
case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT: x = 5; y = 5; z = 4; break;
case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT: x = 5; y = 5; z = 5; break;
case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT: x = 5; y = 5; z = 5; break;
case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT: x = 5; y = 5; z = 5; break;
case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT: x = 6; y = 5; z = 5; break;
case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT: x = 6; y = 5; z = 5; break;
case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT: x = 6; y = 5; z = 5; break;
case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT: x = 6; y = 6; z = 5; break;
case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT: x = 6; y = 6; z = 5; break;
case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: x = 6; y = 6; z = 5; break;
case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: x = 6; y = 6; z = 6; break;
case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: x = 6; y = 6; z = 6; break;
case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: x = 6; y = 6; z = 6; break;
default:
x = 0; y = 0; z = 0;
}
}

static float
astcQuality(ktx_uint32_t quality_level) {
switch (quality_level) {
Expand Down Expand Up @@ -756,7 +759,7 @@ ktxTexture2_CompressAstcEx(ktxTexture2* This, ktxAstcParams* params) {
astcBlockDimensions(params->blockDimension,
block_size_x, block_size_y, block_size_z);
quality = astcQuality(params->qualityLevel);
profile = astcEncoderAction(*params, BDB);
profile = astcEncoderProfile(*params, BDB);
swizzle = astcSwizzle(*params);

if(params->perceptual)
Expand Down Expand Up @@ -958,6 +961,7 @@ struct decompression_workload

/**
* @internal
* @ingroup reader
* @brief Runner callback function for a decompression worker thread.
*
* @param thread_count The number of threads in the worker pool.
Expand All @@ -981,11 +985,14 @@ static void decompression_workload_runner(int thread_count, int thread_id, void*
/**
* @ingroup reader
* @brief Decodes a ktx2 texture object, if it is ASTC encoded.
* The decompressed format is calculated from corresponding ASTC format. There are
* only 3 possible options currently supported. RGBA8, SRGBA8 and RGBA32.
* @note 3d textures are decoded to a multi-slice 3d texture.
*
* Updates @p This with the decoded image.
*
* @param This The texture to decode
* @param vkformat The decoding format to use
*
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
*
Expand All @@ -1011,7 +1018,7 @@ static void decompression_workload_runner(int thread_count, int thread_id, void*
* not happen in release package.
*/
KTX_error_code
ktxTexture2_DecodeAstc(ktxTexture2 *This, ktx_uint32_t vkformat) {
ktxTexture2_DecodeAstc(ktxTexture2 *This) {
// Decompress This using astc-decoder
uint32_t* BDB = This->pDfd + 1;
khr_df_model_e colorModel = (khr_df_model_e)KHR_DFDVAL(BDB, MODEL);
Expand All @@ -1034,6 +1041,8 @@ ktxTexture2_DecodeAstc(ktxTexture2 *This, ktx_uint32_t vkformat) {
return KTX_FILE_DATA_ERROR;
}

ktx_uint32_t vkformat = (ktx_uint32_t)getUncompressedFormat(This);

// Create a prototype texture to use for calculating sizes in the target
// format and, as useful side effects, provide us with a properly sized
// data allocation and the DFD for the target format.
Expand Down Expand Up @@ -1077,23 +1086,21 @@ ktxTexture2_DecodeAstc(ktxTexture2 *This, ktx_uint32_t vkformat) {
}

// This is where I do the decompression from "This" to prototype target
astcenc_profile profile{ASTCENC_PRF_LDR_SRGB};
astcenc_swizzle swizzle{ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A};

uint32_t block_size_x{4}; // Get the right blocks from vkformat
uint32_t block_size_y{4};
uint32_t block_size_z{1};
float quality{ASTCENC_PRE_MEDIUM};
uint32_t flags{0}; // TODO: Use normals mode to reconstruct normals params->normalMap ? ASTCENC_FLG_MAP_NORMAL : 0};

astcBlockDimensions((VkFormat)This->vkFormat, block_size_x, block_size_y, block_size_z);
uint32_t block_size_x = KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION0) + 1;
uint32_t block_size_y = KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION1) + 1;
uint32_t block_size_z = KHR_DFDVAL(BDB, TEXELBLOCKDIMENSION2) + 1;

// quality = astcQuality(params->qualityLevel);
// profile = astcEncoderAction(*params, BDB);
// swizzle = astcSwizzle(*params);

// if(params->perceptual) flags |= ASTCENC_FLG_USE_PERCEPTUAL;

astcenc_profile profile = astcDecoderProfile(This);

uint32_t threadCount{1}; // Decompression isn't the bottleneck and only used when checking for psnr and ssim
astcenc_config astc_config;
astcenc_context *astc_context;
Expand Down
2 changes: 1 addition & 1 deletion tests/cts
Submodule cts updated 21 files
+1 −1 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_2D.out.txt
+11 −11 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_2D_ARRAY_MIP.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_2D_ZLIB_9.out.txt
+35 −35 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_CUBE_ARRAY_MIP.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_psnr_R8G8B8_UNORM_2D.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_psnr_R8G8_UNORM_2D.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_psnr_R8_UNORM_2D.out.txt
+2 −2 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_2D.out.txt
+24 −24 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_2D_ARRAY_MIP.out.txt
+2 −2 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_2D_ZLIB_9.out.txt
+72 −72 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_CUBE_ARRAY_MIP.out.txt
+2 −2 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8_UNORM_2D.out.txt
+2 −2 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8_UNORM_2D.out.txt
+2 −2 clitests/golden/encode/compare/astc_0_psnr_ssim_R8_UNORM_2D.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_2D.out.txt
+13 −13 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_2D_ARRAY_MIP.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_2D_ZLIB_9.out.txt
+37 −37 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_CUBE_ARRAY_MIP.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_ssim_R8G8B8_UNORM_2D.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_ssim_R8G8_UNORM_2D.out.txt
+1 −1 clitests/golden/encode/compare/astc_0_ssim_R8_UNORM_2D.out.txt
8 changes: 3 additions & 5 deletions tools/ktx/metrics_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,10 @@ class MetricsCalculator {

// Decode the encoded texture to observe the compression losses
const auto* bdfd = texture->pDfd + 1;
if (khr_df_model_e(KHR_DFDVAL(bdfd, MODEL)) == KHR_DF_MODEL_ASTC)
{
ec = ktxTexture2_DecodeAstc(texture, VK_FORMAT_R8G8B8A8_UNORM);
if (khr_df_model_e(KHR_DFDVAL(bdfd, MODEL)) == KHR_DF_MODEL_ASTC) {
ec = ktxTexture2_DecodeAstc(texture);
}
else
{
else {
tSwizzleInfo = determineTranscodeSwizzle(texture, report);
ec = ktxTexture2_TranscodeBasis(texture, KTX_TTF_RGBA32, 0);
}
Expand Down

0 comments on commit aa6af91

Please sign in to comment.