Skip to content

How to Use and Configure the Transcoder

Rich Geldreich edited this page Apr 13, 2021 · 3 revisions

Transcoder Details

The transcoder unpacks .basis or .KTX2 files directly to various GPU texture formats, almost always without needing to decompress and recompress each block at the texel level (which would be too slow and energy intensive in JavaScript/WebAssembly). Small precomputed lookup tables (for ETC1S) or per-block hint bits (UASTC) are used to accelerate the direct conversion of the internal ETC1S or UASTC format texture data to the desired output texture data. This new approach to GPU texture compression bypasses the need to recompress each block's texels to the desired output format using Principle Component Anaylsis (PCA), or spend cycles determining the output selectors for each individual texel.

To use .basis or .KTX2 files in an application, you need the source files in the "transcoder" directory. In addition, because KTX2 support is enabled by default, which uses Zstandard, so you'll also need to compile and link with the single source file decompressor zstd/zstddeclib.c. (To avoid needing this file, you can either disable KTX2 support entirely, just disable Zstandard support, or link in Zstandard yourself in some other way. See below. We only use a single function in this library to decompress Zstandard compressed memory blocks.)

The entire transcoder lives in a single .cpp file: transcoder/basisu_transcoder.cpp and has no dependencies other than the C/C++ runtime and possibly zstddeclib.c (if KTX2+Zstandard is enabled at compilation time). If compiling with gcc/clang, be sure strict aliasing is disabled (-fno-strict-aliasing) when compiling this file. We have not tested either the encoder or transcoder with strict aliasing enabled. (The Linux kernel is also compiled with this option.) The transcoder can also be cross compiled using emscripten (emcc), for web use. See the webgl/transcoder and webgl/encoder directories for instructions.

To use the transcoder, #include "transcoder/basisu_transcoder.h". Call basist::basisu_transcoder_init() a single time (probably at startup). Also, ideally once at startup, you need to create a single instance of the basist::etc1_global_selector_codebook class, like this:

basist::etc1_global_selector_codebook sel_codebook(basist::g_global_selector_cb_size, basist::g_global_selector_cb);

Now you can use the transcoder, which is implemented in the basisu_transcoder and ktx2_transcoder classes. The key methods for .basis files are start_transcoding(), get_total_images(), get_image_info(), get_image_level_info(), and transcode_image_level(). The KTX2 class has a very similar (but not exact) API.

Note: We will be simplifying the transcoder so the caller doesn't need to deal with etc1_global_selector_codebook's soon. Global selector codebooks aren't actually supported in the ETC1S standard.

To get an idea how to use the transcoding API, you can check out the JavaScript wrappers in webgl/basis_wrappers.cpp, or the command line tool's unpack functions in basisu_tool.cpp.

To get development error messages printed to stdout when something goes wrong inside the transcoder, set the BASISU_DEVEL_MESSAGES macro to 1 in basisu_transcoder.h and recompile.

Using Custom File Formats, Container Independent Transcoding

There are API's to directly utilize the low level transcoder, which is fully supported. This requires rolling your own file format instead of .basis/.KTX2. The key classes are basisu_lowlevel_etc1s_transcoder and basisu_lowlevel_uastc_transcoder. These classes fully expose both transcoders and do not parse any .basis or .KTX2 file headers at all.

To do this, you would need to encode to .basis files either using the command line tool or by directly calling the basis_compressor class, then extract the global codebook and compressed image data from the .basis file and copy this data into your custom file format. There are numerous transcoder methods to help crack open and retrieve file offset/length information from .basis files, such as get_file_info(), etc.

Big Endian and Unaligned Reads Support

On big endian platforms you'll need to set the BASISD_IS_BIG_ENDIAN macro to 1 at compilation time. This is unfortunately something you must currently do manually.

If the platform supports efficient unaligned dword/qword reads (x86/x64 does), you can set BASISD_USE_UNALIGNED_WORD_READS to 1 at compilation time for slightly faster UASTC transcoding. By default this should get enabled automatically when compiling on x86/x64 platforms.

Disabling KTX2 or Zstandard Usage

Set BASISD_SUPPORT_KTX2 to 0 at compilation time to completely disable KTX2 support (and Zstandard, because we only use it for decompressing supercompressed UASTC files, not .basis files).

Set BASISD_SUPPORT_KTX2_ZSTD to 0 at compilation time to only disable Zstandard usage, which removes the dependency on zstd/zstddeclib.c. Apart from supercompressed UASTC files, KTX2 files will still be readable.

Shrinking the Transcoder's Compiled Size

These transcoder macros control which formats are supported by the transcoder at compile-time:


Each format requires its own set of precomputed ETC1S conversion tables. Disabling a format that you know will never be utilized will reduce the compiled size of the transcoder.

If you know your platform doesn't support BC7 or it's not necessary, be sure to set BASISD_SUPPORT_BC7=0. The tables for the mode 6 transcoder are very large (they bloat the compiled WebAssembly transcoder by around 400-500k). We'll probably be removing the mode 6 transcoder in a future update.

The ATC format (which achieves nearly the same quality as BC1/BC3) is for Adreno mobile devices only, and most of these devices probably support one of the newer texture formats. On many platforms/devices/API's you can disable it.