Skip to content

Commit 0a16df8

Browse files
Refactor common options (#817)
These changes are to simplify addition of new commands and features. This PR * moves `thread-count`, `noSSE` and `normal-mode` from basis `OptionsCodec` in OptionsEncodeCommon in encode_utils_common.h. * renames encode_utils.h to encode_utils_basis.h * renames `OptionsCodec` to `OptionsBasisCodec`. * adds encode_utils_astc.h which holds OptionsEncodeASTC taken from command_create.cpp.
1 parent b73e546 commit 0a16df8

9 files changed

+432
-335
lines changed

tools/ktx/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ add_executable(ktxtools
1515
command_info.cpp
1616
command_transcode.cpp
1717
command_validate.cpp
18-
compress_utils.h
19-
encode_utils.h
18+
deflate_utils.h
19+
encode_utils_basis.h
2020
format_descriptor.h
2121
formats.h
2222
fragment_uri.h

tools/ktx/command_create.cpp

Lines changed: 31 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
// SPDX-License-Identifier: Apache-2.0
44

55
#include "command.h"
6+
#include "encode_utils_common.h"
67
#include "platform_utils.h"
78
#include "metrics_utils.h"
8-
#include "compress_utils.h"
9-
#include "encode_utils.h"
9+
#include "deflate_utils.h"
10+
#include "encode_utils_basis.h"
11+
#include "encode_utils_astc.h"
1012
#include "format_descriptor.h"
1113
#include "formats.h"
1214
#include "utility.h"
@@ -561,89 +563,6 @@ struct OptionsCreate {
561563
}
562564
};
563565

564-
struct OptionsASTC : public ktxAstcParams {
565-
inline static const char* kAstcQuality = "astc-quality";
566-
inline static const char* kAstcPerceptual = "astc-perceptual";
567-
568-
inline static const char* kAstcOptions[] = {
569-
kAstcQuality,
570-
kAstcPerceptual
571-
};
572-
573-
std::string astcOptions{};
574-
bool encodeASTC = false;
575-
ClampedOption<ktx_uint32_t> qualityLevel{ktxAstcParams::qualityLevel, 0, KTX_PACK_ASTC_QUALITY_LEVEL_MAX};
576-
577-
OptionsASTC() : ktxAstcParams() {
578-
threadCount = std::thread::hardware_concurrency();
579-
if (threadCount == 0)
580-
threadCount = 1;
581-
structSize = sizeof(ktxAstcParams);
582-
normalMap = false;
583-
for (int i = 0; i < 4; i++)
584-
inputSwizzle[i] = 0;
585-
qualityLevel.clear();
586-
}
587-
588-
void init(cxxopts::Options& opts) {
589-
opts.add_options("Encode ASTC")
590-
(kAstcQuality,
591-
"The quality level configures the quality-performance tradeoff for "
592-
"the compressor; more complete searches of the search space "
593-
"improve image quality at the expense of compression time. Default "
594-
"is 'medium'. The quality level can be set between fastest (0) and "
595-
"exhaustive (100) via the following fixed quality presets:\n\n"
596-
" Level | Quality\n"
597-
" ---------- | -----------------------------\n"
598-
" fastest | (equivalent to quality = 0)\n"
599-
" fast | (equivalent to quality = 10)\n"
600-
" medium | (equivalent to quality = 60)\n"
601-
" thorough | (equivalent to quality = 98)\n"
602-
" exhaustive | (equivalent to quality = 100)",
603-
cxxopts::value<std::string>(), "<level>")
604-
(kAstcPerceptual,
605-
"The codec should optimize for perceptual error, instead of direct "
606-
"RMS error. This aims to improve perceived image quality, but "
607-
"typically lowers the measured PSNR score. Perceptual methods are "
608-
"currently only available for normal maps and RGB color data.");
609-
}
610-
611-
void captureASTCOption(const char* name) {
612-
astcOptions += fmt::format(" --{}", name);
613-
}
614-
615-
template <typename T>
616-
T captureASTCOption(cxxopts::ParseResult& args, const char* name) {
617-
const T value = args[name].as<T>();
618-
astcOptions += fmt::format(" --{} {}", name, value);
619-
return value;
620-
}
621-
622-
void process(cxxopts::Options&, cxxopts::ParseResult& args, Reporter& report) {
623-
if (args[kAstcQuality].count()) {
624-
static std::unordered_map<std::string, ktx_pack_astc_quality_levels_e> astc_quality_mapping{
625-
{"fastest", KTX_PACK_ASTC_QUALITY_LEVEL_FASTEST},
626-
{"fast", KTX_PACK_ASTC_QUALITY_LEVEL_FAST},
627-
{"medium", KTX_PACK_ASTC_QUALITY_LEVEL_MEDIUM},
628-
{"thorough", KTX_PACK_ASTC_QUALITY_LEVEL_THOROUGH},
629-
{"exhaustive", KTX_PACK_ASTC_QUALITY_LEVEL_EXHAUSTIVE}
630-
};
631-
const auto qualityLevelStr = to_lower_copy(captureASTCOption<std::string>(args, kAstcQuality));
632-
const auto it = astc_quality_mapping.find(qualityLevelStr);
633-
if (it == astc_quality_mapping.end())
634-
report.fatal_usage("Invalid astc-quality: \"{}\"", qualityLevelStr);
635-
qualityLevel = it->second;
636-
} else {
637-
qualityLevel = KTX_PACK_ASTC_QUALITY_LEVEL_MEDIUM;
638-
}
639-
640-
if (args[kAstcPerceptual].count()) {
641-
captureASTCOption(kAstcPerceptual);
642-
perceptual = KTX_TRUE;
643-
}
644-
}
645-
};
646-
647566
// -------------------------------------------------------------------------------------------------
648567

649568
/** @page ktx_create ktx create
@@ -693,30 +612,7 @@ Create a KTX2 file from various input files.
693612
otherwise they are ignored.<br />
694613
The format will be used to verify and load all input files into a texture before encoding.<br />
695614
Case insensitive. Required.</dd>
696-
<dl>
697-
<dt>\--astc-quality &lt;level&gt;</dt>
698-
<dd>The quality level configures the quality-performance
699-
tradeoff for the compressor; more complete searches of the
700-
search space improve image quality at the expense of
701-
compression time. Default is 'medium'. The quality level can be
702-
set between fastest (0) and exhaustive (100) via the
703-
following fixed quality presets:
704-
<table>
705-
<tr><th>Level </th> <th> Quality </th></tr>
706-
<tr><td>fastest </td> <td>(equivalent to quality = 0) </td></tr>
707-
<tr><td>fast </td> <td>(equivalent to quality = 10) </td></tr>
708-
<tr><td>medium </td> <td>(equivalent to quality = 60) </td></tr>
709-
<tr><td>thorough </td> <td>(equivalent to quality = 98) </td></tr>
710-
<tr><td>exhaustive </td> <td>(equivalent to quality = 100) </td></tr>
711-
</table>
712-
</dd>
713-
<dt>\--astc-perceptual</dt>
714-
<dd>The codec should optimize for perceptual error, instead of
715-
direct RMS error. This aims to improve perceived image quality,
716-
but typically lowers the measured PSNR score. Perceptual
717-
methods are currently only available for normal maps and RGB
718-
color data.</dd>
719-
</dl>
615+
@snippet{doc} ktx/astc_utils.h command options_encode_astc
720616
<dt>\--1d</dt>
721617
<dd>Create a 1D texture. If not set the texture will be a 2D or 3D texture.</dd>
722618
<dt>\--cubemap</dt>
@@ -768,7 +664,8 @@ Create a KTX2 file from various input files.
768664
With each encoding option the following encoder specific options become valid,
769665
otherwise they are ignored. Case-insensitive.</dd>
770666
771-
@snippet{doc} ktx/encode_utils.h command options_codec
667+
@snippet{doc} ktx/basis_utils.h command options_encode_basis
668+
@snippet{doc} ktx/encode_utils_common.h command options_encode_common
772669
@snippet{doc} ktx/metrics_utils.h command options_metrics
773670
</dl>
774671
<dl>
@@ -813,7 +710,7 @@ Create a KTX2 file from various input files.
813710
<dt>\--warn-on-color-conversions</dt>
814711
<dd>Generates a warning if any of the input images are color converted.</dd>
815712
</dl>
816-
@snippet{doc} ktx/compress_utils.h command options_compress
713+
@snippet{doc} ktx/deflate_utils.h command options_deflate
817714
@snippet{doc} ktx/command.h command options_generic
818715
819716
@section ktx_create_exitstatus EXIT STATUS
@@ -830,7 +727,7 @@ Create a KTX2 file from various input files.
830727
*/
831728
class CommandCreate : public Command {
832729
private:
833-
Combine<OptionsCreate, OptionsASTC, OptionsCodec<false>, OptionsMetrics, OptionsCompress, OptionsMultiInSingleOut, OptionsGeneric> options;
730+
Combine<OptionsCreate, OptionsEncodeASTC, OptionsEncodeBasis<false>, OptionsEncodeCommon, OptionsMetrics, OptionsDeflate, OptionsMultiInSingleOut, OptionsGeneric> options;
834731

835732
uint32_t targetChannelCount = 0; // Derived from VkFormat
836733

@@ -846,9 +743,9 @@ class CommandCreate : public Command {
846743

847744
private:
848745
void executeCreate();
849-
void encode(KTXTexture2& texture, OptionsCodec<false>& opts);
850-
void encodeASTC(KTXTexture2& texture, OptionsASTC& opts);
851-
void compress(KTXTexture2& texture, const OptionsCompress& opts);
746+
void encodeBasis(KTXTexture2& texture, OptionsEncodeBasis<false>& opts);
747+
void encodeASTC(KTXTexture2& texture, OptionsEncodeASTC& opts);
748+
void compress(KTXTexture2& texture, const OptionsDeflate& opts);
852749

853750
private:
854751
template <typename F>
@@ -918,20 +815,24 @@ void CommandCreate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult&
918815
}
919816

920817
if (!isFormatAstc(options.vkFormat)) {
921-
for (const char* astcOption : OptionsASTC::kAstcOptions)
818+
for (const char* astcOption : OptionsEncodeASTC::kAstcOptions)
922819
if (args[astcOption].count())
923820
fatal_usage("--{} can only be used with ASTC formats.", astcOption);
821+
} else {
822+
fillOptionsCodecAstc<decltype(options)>(options);
823+
if (options.OptionsEncodeCommon::noSSE)
824+
fatal_usage("--{} is not allowed with ASTC encode", OptionsEncodeCommon::kNoSse);
924825
}
925826

926-
if (options.codec == EncodeCodec::BasisLZ) {
827+
if (options.codec == BasisCodec::BasisLZ) {
927828
if (options.zstd.has_value())
928829
fatal_usage("Cannot encode to BasisLZ and supercompress with Zstd.");
929830

930831
if (options.zlib.has_value())
931832
fatal_usage("Cannot encode to BasisLZ and supercompress with ZLIB.");
932833
}
933834

934-
if (options.codec != EncodeCodec::NONE) {
835+
if (options.codec != BasisCodec::NONE) {
935836
switch (options.vkFormat) {
936837
case VK_FORMAT_R8_UNORM:
937838
case VK_FORMAT_R8_SRGB:
@@ -950,7 +851,11 @@ void CommandCreate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult&
950851
}
951852
}
952853

953-
const auto canCompare = options.codec == EncodeCodec::BasisLZ || options.codec == EncodeCodec::UASTC;
854+
const auto canCompare = options.codec == BasisCodec::BasisLZ || options.codec == BasisCodec::UASTC;
855+
856+
if (canCompare)
857+
fillOptionsCodecBasis<decltype(options)>(options);
858+
954859
if (options.compare_ssim && !canCompare)
955860
fatal_usage("--compare-ssim can only be used with BasisLZ or UASTC encoding.");
956861
if (options.compare_psnr && !canCompare)
@@ -1258,12 +1163,12 @@ void CommandCreate::executeCreate() {
12581163
}
12591164

12601165
// Encode and apply compression
1261-
encode(texture, options);
1166+
encodeBasis(texture, options);
12621167
encodeASTC(texture, options);
12631168
compress(texture, options);
12641169

12651170
// Add KTXwriterScParams metadata if ASTC encoding, BasisU encoding, or other supercompression was used
1266-
const auto writerScParams = fmt::format("{}{}{}", options.astcOptions, options.codecOptions, options.compressOptions);
1171+
const auto writerScParams = fmt::format("{}{}{}{}", options.astcOptions, options.codecOptions, options.commonOptions, options.compressOptions);
12671172
if (writerScParams.size() > 0) {
12681173
// Options always contain a leading space
12691174
assert(writerScParams[0] == ' ');
@@ -1283,12 +1188,12 @@ void CommandCreate::executeCreate() {
12831188

12841189
// -------------------------------------------------------------------------------------------------
12851190

1286-
void CommandCreate::encode(KTXTexture2& texture, OptionsCodec<false>& opts) {
1191+
void CommandCreate::encodeBasis(KTXTexture2& texture, OptionsEncodeBasis<false>& opts) {
12871192
MetricsCalculator metrics;
12881193
metrics.saveReferenceImages(texture, options, *this);
12891194

1290-
if (opts.codec != EncodeCodec::NONE) {
1291-
auto ret = ktxTexture2_CompressBasisEx(texture, &opts.basisOpts);
1195+
if (opts.codec != BasisCodec::NONE) {
1196+
auto ret = ktxTexture2_CompressBasisEx(texture, &opts);
12921197
if (ret != KTX_SUCCESS)
12931198
fatal(rc::KTX_FAILURE, "Failed to encode KTX2 file with codec \"{}\". KTX Error: {}",
12941199
to_underlying(opts.codec), ktxErrorString(ret));
@@ -1297,15 +1202,15 @@ void CommandCreate::encode(KTXTexture2& texture, OptionsCodec<false>& opts) {
12971202
metrics.decodeAndCalculateMetrics(texture, options, *this);
12981203
}
12991204

1300-
void CommandCreate::encodeASTC(KTXTexture2& texture, OptionsASTC& opts) {
1205+
void CommandCreate::encodeASTC(KTXTexture2& texture, OptionsEncodeASTC& opts) {
13011206
if (opts.encodeASTC) {
13021207
const auto ret = ktxTexture2_CompressAstcEx(texture, &opts);
13031208
if (ret != KTX_SUCCESS)
13041209
fatal(rc::KTX_FAILURE, "Failed to encode KTX2 file with codec ASTC. KTX Error: {}", ktxErrorString(ret));
13051210
}
13061211
}
13071212

1308-
void CommandCreate::compress(KTXTexture2& texture, const OptionsCompress& opts) {
1213+
void CommandCreate::compress(KTXTexture2& texture, const OptionsDeflate& opts) {
13091214
if (opts.zstd) {
13101215
const auto ret = ktxTexture2_DeflateZstd(texture, *opts.zstd);
13111216
if (ret != KTX_SUCCESS)

tools/ktx/command_deflate.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#include "command.h"
66
#include "platform_utils.h"
7-
#include "compress_utils.h"
7+
#include "deflate_utils.h"
88
#include "formats.h"
99
#include "sbufstream.h"
1010
#include "utility.h"
@@ -51,7 +51,7 @@ Deflate (supercompress) a KTX2 file.
5151
supercompressed with BasisLZ.
5252
5353
The following options are available:
54-
@snippet{doc} ktx/compress_utils.h command options_compress
54+
@snippet{doc} ktx/deflate_utils.h command options_deflate
5555
<dl>
5656
<dt>-q, --quiet</dt>
5757
<dd>Silence warning about already supercompressed input fiile..</dd>
@@ -76,7 +76,7 @@ class CommandDeflate : public Command {
7676
all = -1,
7777
};
7878

79-
struct OptionsDeflate {
79+
struct Options {
8080
inline static const char* kQuiet = "quiet";
8181
inline static const char* kWarningsAsErrors = "warnings-as-errors";
8282
bool quiet = false;
@@ -85,7 +85,7 @@ class CommandDeflate : public Command {
8585
void process(cxxopts::Options& opts, cxxopts::ParseResult& args, Reporter& report);
8686
};
8787

88-
Combine<OptionsDeflate, OptionsCompress, OptionsSingleInSingleOut, OptionsGeneric> options;
88+
Combine<Options, OptionsDeflate, OptionsSingleInSingleOut, OptionsGeneric> options;
8989

9090
public:
9191
virtual int main(int argc, char* argv[]) override;
@@ -114,13 +114,13 @@ int CommandDeflate::main(int argc, char* argv[]) {
114114
}
115115
}
116116

117-
void CommandDeflate::OptionsDeflate::init(cxxopts::Options& opts) {
117+
void CommandDeflate::Options::init(cxxopts::Options& opts) {
118118
opts.add_options()
119119
(kQuiet, "Don't print warning when input file is already supercompressed.")
120120
(kWarningsAsErrors, "Exit with error when input file is already supercompressed");
121121
}
122122

123-
void CommandDeflate::OptionsDeflate::process(cxxopts::Options&,
123+
void CommandDeflate::Options::process(cxxopts::Options&,
124124
cxxopts::ParseResult& args,
125125
Reporter& report) {
126126
quiet = args[kQuiet].as<bool>();
@@ -139,7 +139,7 @@ void CommandDeflate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult
139139
options.process(opts, args, *this);
140140
if (!options.zstd && !options.zlib) {
141141
fatal_usage("Must specify --{} or --{}.",
142-
OptionsCompress::kZStd, OptionsCompress::kZLib);
142+
OptionsDeflate::kZStd, OptionsDeflate::kZLib);
143143
}
144144
}
145145

0 commit comments

Comments
 (0)