Skip to content

Commit aa6af91

Browse files
Add vkformat checks to ktxTexture2_DecodeAstc (#967)
* Adds checks for vkformat fixes #960 * Propogates vkformat correctly into creating astc profile
1 parent 7a8cd47 commit aa6af91

File tree

4 files changed

+115
-110
lines changed

4 files changed

+115
-110
lines changed

include/ktx.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ KTX_API KTX_error_code KTX_APIENTRY
13131313
ktxTexture2_CompressAstc(ktxTexture2* This, ktx_uint32_t quality);
13141314

13151315
KTX_API KTX_error_code KTX_APIENTRY
1316-
ktxTexture2_DecodeAstc(ktxTexture2* This, ktx_uint32_t vkformat);
1316+
ktxTexture2_DecodeAstc(ktxTexture2* This);
13171317

13181318
/**
13191319
* @memberof ktxTexture2

lib/astc_codec.cpp

Lines changed: 110 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ unorm8x4ArrayToImage(const uint8_t *data, uint32_t dim_x, uint32_t dim_y) {
201201

202202
/**
203203
* @memberof ktxTexture
204+
* @internal
204205
* @ingroup writer
205206
* @~English
206207
* @brief Creates default ASTC parameters
@@ -222,6 +223,7 @@ astcDefaultOptions() {
222223

223224
/**
224225
* @memberof ktxTexture
226+
* @internal
225227
* @ingroup writer
226228
* @~English
227229
* @brief Should be used to get VkFormat from ASTC block enum
@@ -291,38 +293,121 @@ astcVkFormat(ktx_uint32_t block_size, bool sRGB) {
291293

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

303-
ktx_uint32_t transfer = KHR_DFDVAL(bdb, TRANSFER);
309+
if (KHR_DFDSVAL(BDB, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) {
310+
return VK_FORMAT_R32G32B32A32_SFLOAT;
311+
} else {
312+
if (khr_df_transfer_e(KHR_DFDVAL(BDB, TRANSFER) == KHR_DF_TRANSFER_SRGB))
313+
return VK_FORMAT_R8G8B8A8_SRGB;
314+
else
315+
return VK_FORMAT_R8G8B8A8_UNORM;
316+
}
317+
}
304318

305-
if (transfer == KHR_DF_TRANSFER_SRGB &&
306-
params.mode == KTX_PACK_ASTC_ENCODER_MODE_LDR)
319+
/**
320+
* @memberof ktxTexture
321+
* @internal
322+
* @ingroup reader
323+
* @~English
324+
* @brief Should be used to check if an ASTC VkFormat is LDR format or not.
325+
*
326+
* @return true if the VkFormat is an ASTC LDR format.
327+
*/
328+
inline bool isFormatAstcLDR(ktxTexture2* This) noexcept {
329+
return (KHR_DFDSVAL(This->pDfd + 1, 0, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) == 0;
330+
}
331+
332+
/**
333+
* @memberof ktxTexture
334+
* @internal
335+
* @ingroup reader writer
336+
* @~English
337+
* @brief Creates valid ASTC decoder profile from VkFormat
338+
*
339+
* @return Valid astc_profile from VkFormat
340+
*/
341+
static astcenc_profile
342+
astcProfile(bool sRGB, bool ldr) {
343+
344+
if (sRGB && ldr)
307345
return ASTCENC_PRF_LDR_SRGB;
308-
else if (transfer == KHR_DF_TRANSFER_LINEAR) {
309-
if (params.mode == KTX_PACK_ASTC_ENCODER_MODE_LDR)
346+
else if (!sRGB) {
347+
if (ldr)
310348
return ASTCENC_PRF_LDR;
311349
else
312350
return ASTCENC_PRF_HDR;
313351
}
314352
// TODO: Add support for the following
315353
// KTX_PACK_ASTC_ENCODER_ACTION_COMP_HDR_RGB_LDR_ALPHA; currently not supported
316354

355+
assert(ldr && "HDR sRGB profile not supported");
356+
317357
return ASTCENC_PRF_LDR_SRGB;
318358
}
319359

360+
/**
361+
* @memberof ktxTexture
362+
* @internal
363+
* @ingroup writer
364+
* @~English
365+
* @brief Creates valid ASTC encoder profile provided params and bdb
366+
*
367+
* @return Valid astc_profile from params and bdb
368+
*/
369+
static astcenc_profile
370+
astcEncoderProfile(const ktxAstcParams &params, const uint32_t* bdb) {
371+
372+
ktx_uint32_t transfer = KHR_DFDVAL(bdb, TRANSFER);
373+
374+
bool sRGB = transfer == KHR_DF_TRANSFER_SRGB;
375+
bool ldr = params.mode == KTX_PACK_ASTC_ENCODER_MODE_LDR;
376+
377+
if (!sRGB) {
378+
assert(transfer == KHR_DF_TRANSFER_LINEAR && "Unsupported transfer function, only support sRGB and Linear");
379+
}
380+
381+
return astcProfile(sRGB, ldr);
382+
}
383+
384+
/**
385+
* @memberof ktxTexture
386+
* @internal
387+
* @ingroup reader
388+
* @~English
389+
* @brief Creates valid ASTC decoder profile from VkFormat
390+
*
391+
* @return Valid astc_profile from VkFormat
392+
*/
393+
static astcenc_profile
394+
astcDecoderProfile(ktxTexture2 *This) {
395+
396+
uint32_t* BDB = This->pDfd + 1;
397+
ktx_uint32_t transfer = KHR_DFDVAL(BDB, TRANSFER);
398+
399+
bool sRGB = transfer == KHR_DF_TRANSFER_SRGB;
400+
bool ldr = isFormatAstcLDR(This);
401+
402+
return astcProfile(sRGB, ldr);
403+
}
320404

321405
/**
322406
* @memberof ktxTexture
407+
* @internal
323408
* @ingroup writer
324409
* @~English
325-
* @brief Creates valid ASTC encoder swizzle from string.
410+
* @brief Creates valid ASTC encoder swizzle from string.
326411
*
327412
* @return Valid astcenc_swizzle from string
328413
*/
@@ -391,88 +476,6 @@ astcBlockDimensions(ktx_uint32_t block_size,
391476
}
392477
}
393478

394-
395-
static void
396-
astcBlockDimensions(VkFormat format,
397-
uint32_t &x, uint32_t &y, uint32_t &z) noexcept {
398-
switch (format) {
399-
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: x = 4; y = 4; z = 0; break;
400-
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: x = 4; y = 4; z = 0; break;
401-
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: x = 5; y = 4; z = 0; break;
402-
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: x = 5; y = 4; z = 0; break;
403-
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: x = 5; y = 5; z = 0; break;
404-
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: x = 5; y = 5; z = 0; break;
405-
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: x = 6; y = 5; z = 0; break;
406-
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: x = 6; y = 5; z = 0; break;
407-
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: x = 6; y = 6; z = 0; break;
408-
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: x = 6; y = 6; z = 0; break;
409-
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: x = 8; y = 5; z = 0; break;
410-
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: x = 8; y = 5; z = 0; break;
411-
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: x = 8; y = 6; z = 0; break;
412-
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: x = 8; y = 6; z = 0; break;
413-
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: x = 8; y = 8; z = 0; break;
414-
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: x = 8; y = 8; z = 0; break;
415-
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: x = 10; y = 5; z = 0; break;
416-
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: x = 10; y = 5; z = 0; break;
417-
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: x = 10; y = 6; z = 0; break;
418-
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: x = 10; y = 6; z = 0; break;
419-
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: x = 10; y = 8; z = 0; break;
420-
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: x = 10; y = 8; z = 0; break;
421-
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: x = 10; y = 10; z = 0; break;
422-
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: x = 10; y = 10; z = 0; break;
423-
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: x = 12; y = 10; z = 0; break;
424-
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: x = 12; y = 10; z = 0; break;
425-
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: x = 12; y = 12; z = 0; break;
426-
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: x = 12; y = 12; z = 0; break;
427-
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: x = 4; y = 4; z = 0; break;
428-
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: x = 5; y = 4; z = 0; break;
429-
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: x = 5; y = 5; z = 0; break;
430-
case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: x = 6; y = 5; z = 0; break;
431-
case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: x = 6; y = 6; z = 0; break;
432-
case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: x = 8; y = 5; z = 0; break;
433-
case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: x = 8; y = 6; z = 0; break;
434-
case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: x = 8; y = 8; z = 0; break;
435-
case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: x = 10; y = 5; z = 0; break;
436-
case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: x = 10; y = 6; z = 0; break;
437-
case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: x = 10; y = 8; z = 0; break;
438-
case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: x = 10; y = 10; z = 0; break;
439-
case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: x = 12; y = 10; z = 0; break;
440-
case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: x = 12; y = 12; z = 0; break;
441-
case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: x = 3; y = 3; z = 3; break;
442-
case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: x = 3; y = 3; z = 3; break;
443-
case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: x = 3; y = 3; z = 3; break;
444-
case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT: x = 4; y = 3; z = 3; break;
445-
case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT: x = 4; y = 3; z = 3; break;
446-
case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT: x = 4; y = 3; z = 3; break;
447-
case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT: x = 4; y = 4; z = 3; break;
448-
case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT: x = 4; y = 4; z = 3; break;
449-
case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT: x = 4; y = 4; z = 3; break;
450-
case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT: x = 4; y = 4; z = 4; break;
451-
case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT: x = 4; y = 4; z = 4; break;
452-
case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT: x = 4; y = 4; z = 4; break;
453-
case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT: x = 5; y = 4; z = 4; break;
454-
case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT: x = 5; y = 4; z = 4; break;
455-
case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT: x = 5; y = 4; z = 4; break;
456-
case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT: x = 5; y = 5; z = 4; break;
457-
case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT: x = 5; y = 5; z = 4; break;
458-
case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT: x = 5; y = 5; z = 4; break;
459-
case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT: x = 5; y = 5; z = 5; break;
460-
case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT: x = 5; y = 5; z = 5; break;
461-
case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT: x = 5; y = 5; z = 5; break;
462-
case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT: x = 6; y = 5; z = 5; break;
463-
case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT: x = 6; y = 5; z = 5; break;
464-
case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT: x = 6; y = 5; z = 5; break;
465-
case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT: x = 6; y = 6; z = 5; break;
466-
case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT: x = 6; y = 6; z = 5; break;
467-
case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: x = 6; y = 6; z = 5; break;
468-
case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: x = 6; y = 6; z = 6; break;
469-
case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: x = 6; y = 6; z = 6; break;
470-
case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: x = 6; y = 6; z = 6; break;
471-
default:
472-
x = 0; y = 0; z = 0;
473-
}
474-
}
475-
476479
static float
477480
astcQuality(ktx_uint32_t quality_level) {
478481
switch (quality_level) {
@@ -756,7 +759,7 @@ ktxTexture2_CompressAstcEx(ktxTexture2* This, ktxAstcParams* params) {
756759
astcBlockDimensions(params->blockDimension,
757760
block_size_x, block_size_y, block_size_z);
758761
quality = astcQuality(params->qualityLevel);
759-
profile = astcEncoderAction(*params, BDB);
762+
profile = astcEncoderProfile(*params, BDB);
760763
swizzle = astcSwizzle(*params);
761764

762765
if(params->perceptual)
@@ -958,6 +961,7 @@ struct decompression_workload
958961

959962
/**
960963
* @internal
964+
* @ingroup reader
961965
* @brief Runner callback function for a decompression worker thread.
962966
*
963967
* @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*
981985
/**
982986
* @ingroup reader
983987
* @brief Decodes a ktx2 texture object, if it is ASTC encoded.
988+
989+
* The decompressed format is calculated from corresponding ASTC format. There are
990+
* only 3 possible options currently supported. RGBA8, SRGBA8 and RGBA32.
991+
* @note 3d textures are decoded to a multi-slice 3d texture.
984992
*
985993
* Updates @p This with the decoded image.
986994
*
987995
* @param This The texture to decode
988-
* @param vkformat The decoding format to use
989996
*
990997
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
991998
*
@@ -1011,7 +1018,7 @@ static void decompression_workload_runner(int thread_count, int thread_id, void*
10111018
* not happen in release package.
10121019
*/
10131020
KTX_error_code
1014-
ktxTexture2_DecodeAstc(ktxTexture2 *This, ktx_uint32_t vkformat) {
1021+
ktxTexture2_DecodeAstc(ktxTexture2 *This) {
10151022
// Decompress This using astc-decoder
10161023
uint32_t* BDB = This->pDfd + 1;
10171024
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) {
10341041
return KTX_FILE_DATA_ERROR;
10351042
}
10361043

1044+
ktx_uint32_t vkformat = (ktx_uint32_t)getUncompressedFormat(This);
1045+
10371046
// Create a prototype texture to use for calculating sizes in the target
10381047
// format and, as useful side effects, provide us with a properly sized
10391048
// data allocation and the DFD for the target format.
@@ -1077,23 +1086,21 @@ ktxTexture2_DecodeAstc(ktxTexture2 *This, ktx_uint32_t vkformat) {
10771086
}
10781087

10791088
// This is where I do the decompression from "This" to prototype target
1080-
astcenc_profile profile{ASTCENC_PRF_LDR_SRGB};
10811089
astcenc_swizzle swizzle{ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A};
1082-
1083-
uint32_t block_size_x{4}; // Get the right blocks from vkformat
1084-
uint32_t block_size_y{4};
1085-
uint32_t block_size_z{1};
10861090
float quality{ASTCENC_PRE_MEDIUM};
10871091
uint32_t flags{0}; // TODO: Use normals mode to reconstruct normals params->normalMap ? ASTCENC_FLG_MAP_NORMAL : 0};
10881092

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

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

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

1102+
astcenc_profile profile = astcDecoderProfile(This);
1103+
10971104
uint32_t threadCount{1}; // Decompression isn't the bottleneck and only used when checking for psnr and ssim
10981105
astcenc_config astc_config;
10991106
astcenc_context *astc_context;

tests/cts

Submodule cts updated 21 files

tools/ktx/metrics_utils.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,10 @@ class MetricsCalculator {
110110

111111
// Decode the encoded texture to observe the compression losses
112112
const auto* bdfd = texture->pDfd + 1;
113-
if (khr_df_model_e(KHR_DFDVAL(bdfd, MODEL)) == KHR_DF_MODEL_ASTC)
114-
{
115-
ec = ktxTexture2_DecodeAstc(texture, VK_FORMAT_R8G8B8A8_UNORM);
113+
if (khr_df_model_e(KHR_DFDVAL(bdfd, MODEL)) == KHR_DF_MODEL_ASTC) {
114+
ec = ktxTexture2_DecodeAstc(texture);
116115
}
117-
else
118-
{
116+
else {
119117
tSwizzleInfo = determineTranscodeSwizzle(texture, report);
120118
ec = ktxTexture2_TranscodeBasis(texture, KTX_TTF_RGBA32, 0);
121119
}

0 commit comments

Comments
 (0)