Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encode astc support #952

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ macro(common_libktx_settings target enable_write library_type)
${target}
PRIVATE
lib/basis_encode.cpp
lib/astc_encode.cpp
lib/astc_codec.cpp
${BASISU_ENCODER_C_SRC}
${BASISU_ENCODER_CXX_SRC}
lib/writer1.c
Expand Down
3 changes: 3 additions & 0 deletions include/ktx.h
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,9 @@ ktxTexture2_CompressAstcEx(ktxTexture2* This, ktxAstcParams* params);
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);

/**
* @memberof ktxTexture2
* @~English
Expand Down
318 changes: 315 additions & 3 deletions lib/astc_encode.cpp → lib/astc_codec.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/cts
Submodule cts updated 94 files
+4 −0 clitests/CMakeLists.txt
+1 −1 clitests/golden/create/cli_errors/non_encode_compare_psnr.err.txt
+1 −1 clitests/golden/create/cli_errors/non_encode_compare_ssim.err.txt
+2 −2 clitests/golden/create/help/help.out.txt
+ clitests/golden/encode/astc_params/output_exhaustive_only.ktx2
+ clitests/golden/encode/astc_params/output_exhaustive_perceptual.ktx2
+ clitests/golden/encode/astc_params/output_fast_only.ktx2
+ clitests/golden/encode/astc_params/output_fast_perceptual.ktx2
+ clitests/golden/encode/astc_params/output_fastes_perceptual.ktx2
+ clitests/golden/encode/astc_params/output_fastest_only.ktx2
+ clitests/golden/encode/astc_params/output_fastest_perceptual.ktx2
+ clitests/golden/encode/astc_params/output_medium_only.ktx2
+ clitests/golden/encode/astc_params/output_medium_perceptual.ktx2
+ clitests/golden/encode/astc_params/output_perceptual_only.ktx2
+ clitests/golden/encode/astc_params/output_thorough_only.ktx2
+ clitests/golden/encode/astc_params/output_thorough_perceptual.ktx2
+2 −0 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_SRGB_2D.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_2D.out.txt
+35 −0 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_2D_ARRAY_MIP.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_2D_ZLIB_9.out.txt
+99 −0 clitests/golden/encode/compare/astc_0_psnr_R8G8B8A8_UNORM_CUBE_ARRAY_MIP.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_psnr_R8G8B8_UNORM_2D.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_psnr_R8G8_UNORM_2D.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_psnr_R8_UNORM_2D.out.txt
+3 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_SRGB_2D.out.txt
+3 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_2D.out.txt
+52 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_2D_ARRAY_MIP.out.txt
+3 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_2D_ZLIB_9.out.txt
+148 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8A8_UNORM_CUBE_ARRAY_MIP.out.txt
+3 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8B8_UNORM_2D.out.txt
+3 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8G8_UNORM_2D.out.txt
+3 −0 clitests/golden/encode/compare/astc_0_psnr_ssim_R8_UNORM_2D.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_SRGB_2D.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_2D.out.txt
+35 −0 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_2D_ARRAY_MIP.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_2D_ZLIB_9.out.txt
+99 −0 clitests/golden/encode/compare/astc_0_ssim_R8G8B8A8_UNORM_CUBE_ARRAY_MIP.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_ssim_R8G8B8_UNORM_2D.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_ssim_R8G8_UNORM_2D.out.txt
+2 −0 clitests/golden/encode/compare/astc_0_ssim_R8_UNORM_2D.out.txt
+ clitests/golden/encode/encode_astc/output_ASTC_10x10_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x10_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x10_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x5_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x5_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x5_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x6_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x6_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x6_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x8_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x8_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_10x8_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_12x10_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_12x10_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_12x10_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_12x12_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_12x12_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_12x12_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_4x4_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_4x4_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_4x4_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_5x4_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_5x4_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_5x4_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_5x5_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_5x5_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_5x5_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_6x5_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_6x5_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_6x5_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_6x6_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_6x6_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_6x6_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x5_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x5_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x5_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x6_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x6_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x6_UNORM_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x8_SFLOAT_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x8_SRGB_BLOCK.ktx2
+ clitests/golden/encode/encode_astc/output_ASTC_8x8_UNORM_BLOCK.ktx2
+1 −0 clitests/golden/encode/encode_error_codec/codec_format.err.txt
+1 −1 clitests/golden/encode/encode_error_codec/missing_codec.err.txt
+1 −0 clitests/golden/encode/encode_error_format/astc_format.err.txt
+1 −0 clitests/golden/encode/encode_error_format/common_format.err.txt
+27 −2 clitests/golden/encode/help/help.out.txt
+ clitests/input/ktx2/valid_known_R8G8B8_UNORM_2D.ktx2
+2 −1 clitests/tests/encode/compare.json
+54 −0 clitests/tests/encode/encode_astc.json
+52 −0 clitests/tests/encode/encode_astc_bad_astc_format.json
+258 −0 clitests/tests/encode/encode_astc_bad_format.json
+24 −0 clitests/tests/encode/encode_astc_params.json
+1 −0 clitests/tests/encode/encode_error_codec.json
19 changes: 13 additions & 6 deletions tools/ktx/command_create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,8 @@ Create a KTX2 file from various input files.
is present in the input. @c SRGB or @c UNORM is chosen depending on the
specified ASTC format. The ASTC-specific and common encoder options listed
@ref ktx_create_options_encoding "below" become valid, otherwise they are ignored.
<!--This matches the functionality of the @ref ktx_encode "ktx encode" command
when an ASTC format is specified.<br /> -->
This matches the functionality of the @ref ktx_encode "ktx encode" command
when an ASTC format is specified.<br />
<br />
When used with @b \--encode it specifies the target format before the encoding step.
In this case it must be one of:
Expand Down Expand Up @@ -874,15 +874,17 @@ void CommandCreate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult&
}
}

const auto canCompare = options.codec == BasisCodec::BasisLZ || options.codec == BasisCodec::UASTC;
const auto basisCodec = options.codec == BasisCodec::BasisLZ || options.codec == BasisCodec::UASTC;
const auto astcCodec = isFormatAstc(options.vkFormat);
const auto canCompare = basisCodec || astcCodec;

if (canCompare)
if (basisCodec)
fillOptionsCodecBasis<decltype(options)>(options);

if (options.compare_ssim && !canCompare)
fatal_usage("--compare-ssim can only be used with BasisLZ or UASTC encoding.");
fatal_usage("--compare-ssim can only be used with BasisLZ, UASTC or ASTC encoding.");
if (options.compare_psnr && !canCompare)
fatal_usage("--compare-psnr can only be used with BasisLZ or UASTC encoding.");
fatal_usage("--compare-psnr can only be used with BasisLZ, UASTC or ASTC encoding.");

if (isFormatAstc(options.vkFormat) && !options.raw) {
options.encodeASTC = true;
Expand Down Expand Up @@ -1226,11 +1228,16 @@ void CommandCreate::encodeBasis(KTXTexture2& texture, OptionsEncodeBasis<false>&
}

void CommandCreate::encodeASTC(KTXTexture2& texture, OptionsEncodeASTC& opts) {
MetricsCalculator metrics;
metrics.saveReferenceImages(texture, options, *this);

if (opts.encodeASTC) {
const auto ret = ktxTexture2_CompressAstcEx(texture, &opts);
if (ret != KTX_SUCCESS)
fatal(rc::KTX_FAILURE, "Failed to encode KTX2 file with codec ASTC. KTX Error: {}", ktxErrorString(ret));
}

metrics.decodeAndCalculateMetrics(texture, options, *this);
}

void CommandCreate::compress(KTXTexture2& texture, const OptionsDeflate& opts) {
Expand Down
78 changes: 64 additions & 14 deletions tools/ktx/command_encode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0

#include "command.h"
#include "encode_utils_astc.h"
#include "encode_utils_common.h"
#include "platform_utils.h"
#include "metrics_utils.h"
Expand Down Expand Up @@ -40,12 +41,12 @@ Encode a KTX2 file.

@section ktx_encode_description DESCRIPTION
@b ktx @b encode can encode the KTX file specified as the @e input-file argument
to a universal format<!-- or one of the ASTC formats,--> optionally supercompress the result,
to a universal format or one of the ASTC formats, optionally supercompress the result,
and save it as the @e output-file.
If the @e input-file is '-' the file will be read from the stdin.
If the @e output-path is '-' the output file will be written to the stdout.

For universal <!-- and ASTC LDR--> formats, the input file must be R8, R8G8, R8G8B8
For universal and ASTC LDR formats, the input file must be R8, R8G8, R8G8B8
or R8G8B8A8 (or their sRGB variants).

<!--For ASTC HDR formats the input file must be TBD (e.g. R16_{,S}FLOAT,
Expand All @@ -67,12 +68,11 @@ Encode a KTX2 file.
they are ignored. Case-insensitive.</dd>

@snippet{doc} ktx/encode_utils_basis.h command options_basis_encoders
<!-- <dt>\--format</dt>
<dt>\--format</dt>
<dd>KTX format enum that specifies the target ASTC format. Non-ASTC
formats are invalid. When specified the ASTC-specific and common
encoder options listed @ref ktx\_encode\_options\_encoding "below"
become valid, otherwise they are ignored.
-->
</dl>
@snippet{doc} ktx/deflate_utils.h command options_deflate
@snippet{doc} ktx/command.h command options_generic
Expand All @@ -81,7 +81,7 @@ Encode a KTX2 file.
The following specific and common encoder options are available. Specific options
become valid only if their encoder has been selected. Common encoder options
become valid when an encoder they apply to has been selected. Otherwise they are ignored.
<!--@snippet{doc} ktx/encode_utils_astc.h command options_encode_astc-->
@snippet{doc} ktx/encode_utils_astc.h command options_encode_astc
@snippet{doc} ktx/encode_utils_basis.h command options_encode_basis
@snippet{doc} ktx/encode_utils_common.h command options_encode_common
@snippet{doc} ktx/metrics_utils.h command options_metrics
Expand All @@ -103,11 +103,16 @@ Encode a KTX2 file.
*/
class CommandEncode : public Command {
struct OptionsEncode {
inline static const char* kFormat = "format";
inline static const char* kCodec = "codec";

VkFormat vkFormat = VK_FORMAT_UNDEFINED;

void init(cxxopts::Options& opts);
void process(cxxopts::Options& opts, cxxopts::ParseResult& args, Reporter& report);
};

Combine<OptionsEncode, OptionsEncodeBasis<true>, OptionsEncodeCommon, OptionsMetrics, OptionsDeflate, OptionsSingleInSingleOut, OptionsGeneric> options;
Combine<OptionsEncode, OptionsEncodeASTC, OptionsEncodeBasis<true>, OptionsEncodeCommon, OptionsMetrics, OptionsDeflate, OptionsSingleInSingleOut, OptionsGeneric> options;

public:
virtual int main(int argc, char* argv[]) override;
Expand Down Expand Up @@ -138,13 +143,35 @@ int CommandEncode::main(int argc, char* argv[]) {

void CommandEncode::OptionsEncode::init(cxxopts::Options& opts) {
opts.add_options()
("codec", "Target codec."
(kFormat, "KTX format enum that specifies the KTX file output format."
" The enum names are matching the VkFormats without the VK_FORMAT_ prefix."
" The VK_FORMAT_ prefix is ignored if present."
"\nIt can't be used with --codec."
"\nThe value must be an ASTC format. When specified the ASTC encoder specific"
" options becomes valid."
" Case insensitive.", cxxopts::value<std::string>(), "<enum>")
(kCodec, "Target codec."
" With each encoding option the encoder specific options become valid,"
" otherwise they are ignored. Case-insensitive."
"\nPossible options are: basis-lz | uastc", cxxopts::value<std::string>(), "<target>");
}

void CommandEncode::OptionsEncode::process(cxxopts::Options&, cxxopts::ParseResult&, Reporter&) {
void CommandEncode::OptionsEncode::process(cxxopts::Options&, cxxopts::ParseResult& args, Reporter& report) {
if (args[kCodec].count() && args[kFormat].count())
report.fatal_usage("Format and codec can't be both specified together.");

if (args[kFormat].count()) {
const auto formatStr = args[kFormat].as<std::string>();
const auto parsedVkFormat = parseVkFormat(formatStr);
if (!parsedVkFormat)
report.fatal_usage("The requested format is invalid or unsupported: \"{}\".", formatStr);

vkFormat = *parsedVkFormat;

if (!isFormatAstc(vkFormat)) {
report.fatal_usage("Optional option 'format' is not an ASTC format.");
}
}
}

void CommandEncode::initOptions(cxxopts::Options& opts) {
Expand All @@ -156,6 +183,10 @@ void CommandEncode::processOptions(cxxopts::Options& opts, cxxopts::ParseResult&

fillOptionsCodecBasis<decltype(options)>(options);

if ((options.codec == BasisCodec::NONE || options.codec == BasisCodec::INVALID) &&
options.vkFormat == VK_FORMAT_UNDEFINED)
fatal_usage("Either codec or format must be specified");

if (options.codec == BasisCodec::BasisLZ) {
if (options.zstd.has_value())
fatal_usage("Cannot encode to BasisLZ and supercompress with Zstd.");
Expand All @@ -164,11 +195,17 @@ void CommandEncode::processOptions(cxxopts::Options& opts, cxxopts::ParseResult&
fatal_usage("Cannot encode to BasisLZ and supercompress with ZLIB.");
}

const auto canCompare = options.codec == BasisCodec::BasisLZ || options.codec == BasisCodec::UASTC;
const auto basisCodec = options.codec == BasisCodec::BasisLZ || options.codec == BasisCodec::UASTC;
const auto astcCodec = isFormatAstc(options.vkFormat);
const auto canCompare = basisCodec || astcCodec;

if (options.compare_ssim && !canCompare)
fatal_usage("--compare-ssim can only be used with BasisLZ or UASTC encoding.");
fatal_usage("--compare-ssim can only be used with BasisLZ, UASTC or ASTC encoding.");
if (options.compare_psnr && !canCompare)
fatal_usage("--compare-psnr can only be used with BasisLZ or UASTC encoding.");
fatal_usage("--compare-psnr can only be used with BasisLZ, UASTC or ASTC encoding.");

if (astcCodec)
options.encodeASTC = true;
}

void CommandEncode::executeEncode() {
Expand All @@ -185,6 +222,10 @@ void CommandEncode::executeEncode() {
fatal(rc::INVALID_FILE, "Cannot encode KTX2 file with {} supercompression.",
toString(ktxSupercmpScheme(texture->supercompressionScheme)));

const auto* bdfd = texture->pDfd + 1;
if (khr_df_model_e(KHR_DFDVAL(bdfd, MODEL)) == KHR_DF_MODEL_ASTC && options.encodeASTC)
fatal_usage("Encoding from ASTC format {} to another ASTC format {} is not supported.", toString(VkFormat(texture->vkFormat)), toString(options.vkFormat));

switch (texture->vkFormat) {
case VK_FORMAT_R8_UNORM:
case VK_FORMAT_R8_SRGB:
Expand Down Expand Up @@ -220,9 +261,18 @@ void CommandEncode::executeEncode() {

MetricsCalculator metrics;
metrics.saveReferenceImages(texture, options, *this);
ret = ktxTexture2_CompressBasisEx(texture, &options);
if (ret != KTX_SUCCESS)
fatal(rc::IO_FAILURE, "Failed to encode KTX2 file with codec \"{}\". KTX Error: {}", ktxErrorString(ret));

if (options.vkFormat != VK_FORMAT_UNDEFINED) {
options.mode = KTX_PACK_ASTC_ENCODER_MODE_LDR; // TODO: Fix me for HDR textures
ret = ktxTexture2_CompressAstcEx(texture, &options);
if (ret != KTX_SUCCESS)
fatal(rc::IO_FAILURE, "Failed to encode KTX2 file to ASTC. KTX Error: {}", ktxErrorString(ret));
} else {
ret = ktxTexture2_CompressBasisEx(texture, &options);
if (ret != KTX_SUCCESS)
fatal(rc::IO_FAILURE, "Failed to encode KTX2 file with codec \"{}\". KTX Error: {}", options.codecName, ktxErrorString(ret));
}

metrics.decodeAndCalculateMetrics(texture, options, *this);

if (options.zstd) {
Expand Down
52 changes: 19 additions & 33 deletions tools/ktx/encode_utils_basis.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,40 +349,26 @@ struct OptionsEncodeBasis : public ktxBasisParams {
}

void process(cxxopts::Options&, cxxopts::ParseResult& args, Reporter& report) {
std::string codec_option{"encode"};

if (ENCODE_CMD) {
// "encode" command - required "codec" argument
codec = validateBasisCodec(args["codec"]);
switch (codec) {
case BasisCodec::NONE:
report.fatal(rc::INVALID_ARGUMENTS, "Missing codec argument.");
break;

case BasisCodec::BasisLZ:
case BasisCodec::UASTC:
codecName = to_lower_copy(args["codec"].as<std::string>());
break;

default:
report.fatal_usage("Invalid encode codec: \"{}\".", args["codec"].as<std::string>());
break;
}
} else {
// "create" command - optional "encode" argument
codec = validateBasisCodec(args["encode"]);
switch (codec) {
case BasisCodec::NONE:
// Not specified
break;

case BasisCodec::BasisLZ:
case BasisCodec::UASTC:
codecName = to_lower_copy(args["encode"].as<std::string>());
break;

default:
report.fatal_usage("Invalid encode codec: \"{}\".", args["encode"].as<std::string>());
break;
}
codec_option = "codec";
}

codec = validateBasisCodec(args[codec_option]);
switch (codec) {
case BasisCodec::NONE:
// Not specified
break;

case BasisCodec::BasisLZ:
case BasisCodec::UASTC:
codecName = to_lower_copy(args[codec_option].as<std::string>());
break;

default:
report.fatal_usage("Invalid encode codec: \"{}\".", args[codec_option].as<std::string>());
break;
}

if (codec == BasisCodec::UASTC) {
Expand Down
25 changes: 19 additions & 6 deletions tools/ktx/metrics_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ namespace ktx {
<dl>
<dt>\--compare-ssim</dt>
<dd>Calculate encoding structural similarity index measure (SSIM) and print it to stdout.
Requires Basis-LZ or UASTC encoding.</dd>
Requires Basis-LZ, UASTC or ASTC encoding.</dd>
<dt>\--compare-psnr</dt>
<dd>Calculate encoding peak signal-to-noise ratio (PSNR) and print it to stdout.
Requires Basis-LZ or UASTC encoding.</dd>
Requires Basis-LZ, UASTC or ASTC encoding.</dd>
</dl>
</dl>
//! [command options_metrics]
Expand All @@ -43,8 +43,8 @@ struct OptionsMetrics {

void init(cxxopts::Options& opts) {
opts.add_options()
("compare-ssim", "Calculate encoding structural similarity index measure (SSIM) and print it to stdout. Requires Basis-LZ or UASTC encoding.")
("compare-psnr", "Calculate encoding peak signal-to-noise ratio (PSNR) and print it to stdout. Requires Basis-LZ or UASTC encoding.");
("compare-ssim", "Calculate encoding structural similarity index measure (SSIM) and print it to stdout. Requires Basis-LZ, UASTC or ASTC encoding.")
("compare-psnr", "Calculate encoding peak signal-to-noise ratio (PSNR) and print it to stdout. Requires Basis-LZ, UASTC or ASTC encoding.");
}

void process(cxxopts::Options&, cxxopts::ParseResult& args, Reporter&) {
Expand Down Expand Up @@ -101,11 +101,24 @@ class MetricsCalculator {
KTXTexture2 texture{static_cast<ktxTexture2*>(malloc(sizeof(ktxTexture2)))};
ktxTexture2_constructCopy(texture, encodedTexture);

const auto tSwizzleInfo = determineTranscodeSwizzle(texture, report);
// Start with a default swizzle
TranscodeSwizzleInfo tSwizzleInfo{};
tSwizzleInfo.defaultNumComponents = 4;
tSwizzleInfo.swizzle = "rgba";

ktx_error_code_e ec = KTX_SUCCESS;

// Decode the encoded texture to observe the compression losses
ec = ktxTexture2_TranscodeBasis(texture, KTX_TTF_RGBA32, 0);
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);
}
else
{
tSwizzleInfo = determineTranscodeSwizzle(texture, report);
ec = ktxTexture2_TranscodeBasis(texture, KTX_TTF_RGBA32, 0);
}
if (ec != KTX_SUCCESS)
report.fatal(rc::KTX_FAILURE, "Failed to transcode KTX2 texture to calculate error metrics: {}", ktxErrorString(ec));

Expand Down
Loading