diff --git a/include/ktx.h b/include/ktx.h index 267d716cba..7e442a6950 100644 --- a/include/ktx.h +++ b/include/ktx.h @@ -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 diff --git a/lib/astc_codec.cpp b/lib/astc_codec.cpp index 3a62d412f3..d1166dd64a 100644 --- a/lib/astc_codec.cpp +++ b/lib/astc_codec.cpp @@ -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 @@ -222,6 +223,7 @@ astcDefaultOptions() { /** * @memberof ktxTexture + * @internal * @ingroup writer * @~English * @brief Should be used to get VkFormat from ASTC block enum @@ -291,22 +293,58 @@ 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 ¶ms, 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; @@ -314,15 +352,62 @@ astcEncoderAction(const ktxAstcParams ¶ms, const uint32_t* bdb) { // 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 ¶ms, 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 */ @@ -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) { @@ -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) @@ -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. @@ -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. * @@ -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); @@ -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. @@ -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; diff --git a/tests/cts b/tests/cts index 33801c64b2..66b97a5b34 160000 --- a/tests/cts +++ b/tests/cts @@ -1 +1 @@ -Subproject commit 33801c64b21f629b84a200939e85fa82fca042e2 +Subproject commit 66b97a5b342889d5332a6485882fa549b8aaffe0 diff --git a/tools/ktx/metrics_utils.h b/tools/ktx/metrics_utils.h index 7e8512fcd6..12ec23136c 100644 --- a/tools/ktx/metrics_utils.h +++ b/tools/ktx/metrics_utils.h @@ -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); }