UASTC implementation details
Clone this wiki locally
.basis/.KTX2 files support both UASTC and ETC1S texture data. In UASTC mode, there is no extra lossless compression applied apart from UASTC itself in .basis files, so the raw UASTC .basis file sizes are quite large (8-bpp). This is not true for .KTX2 files, which support additional lossless Zstandard supercompression layered on top of the lossy UASTC texture data.
The encoder supports an optional Rate-Distortion Optimization (RDO) mode, which reduces the entropy of the output lossy UASTC texture data by conditioning it for better lossless LZ compression. This trades off quality for fewer LZ compressed bits, in an intelligent way that tries to increase the probability/density of close (low distance) LZ matches. In our experiences, we've seen bitrates (using Deflate) ranging between 2-7bpp, with the typical usable bitrate being around 5-7bpp. With the current RDO encoder, the sweet spot is around 5-6 bpp.
A previously unused field in .basis files indicates the internal universal texture format (ETC1S or UASTC). See
basis_file_header::m_tex_format. UASTC files reuse all the existing ETC1S file structures. There are no codebooks in UASTC mode, so a bunch of header fields (like
m_endpoint_cb_file_ofs, etc.) are zero. The helper method
basisu_transcoder::get_tex_format() can be used to determine the texture format of a .basis file.
The transcoder API transparently supports both ETC1S and UASTC files. The UASTC code was added to the transcoder in
transcoder/basisu_transcoder.cpp. It can optionally be disabled by setting the
BASISD_SUPPORT_UASTC preprocessor macro to 0.
There are three ways of accessing the new UASTC functionality:
Use the command line tool to encode UASTC .basis files using the -uastc, -uastc_rdo_l, and -uastc_level options. Then use
transcode_slice()which transparently support both ETC1S and UASTC files. This is the way web developers use the system, by compiling the transcoder's .cpp file to WebAssembly.
A lowlevel class,
basisu_lowlevel_uastc_transcoder, was added with a single method that transcodes UASTC data to GPU texture data in any format:
basisu_lowlevel_uastc_transcoder::transcode_slice(). Internally, this is what
basisu_transcoder::transcode_image_level()uses on UASTC .basis files.
You could roll your own file format and just call this helper to transcode the UASTC data.
- For even lower level access to the UASTC functionality, developers can ignore .basis and our high/low level helpers completely and just use the very lowest level UASTC block functions directly.
transcoder/basisu_transcoder_uastc.hdeclares the UASTC transcode functions, and
basisu_uastc_enc.hdeclares the UASTC encode functions.
Note that before using any encoder functions you must call
basisu_encoder_init(). Similarly, before calling any transcoder functions you must call
The two functions
uastc_rdo() are used for encoding individual blocks (with no RDO), or groups of blocks with RDO. They are very simple to use. You call them with a pointer to 4x4 RGBA pixel blocks, and flags/options, and you get back packed 128-bit UASTC blocks.
The key lowest-level block transcoder functions defined in
Note that we will be optimizing
transcode_uastc_to_etc2_eac_rg11() to be roughly 2-2.5x faster. We targeted too high a quality for EAC R11/RG11. We will also be further optimizing UASTC->ASTC and UASTC->BC7. I would expect ~2x faster without using any SIMD.