Skip to content

UASTC implementation details

Rich Geldreich edited this page Mar 20, 2020 · 3 revisions

.basis files now support both UASTC and ETC1S data. In UASTC mode, there is no extra compression applied apart from UASTC itself, so the raw UASTC .basis file sizes are quite large (8-bpp). However, the encoder supports an optional rate-distortion mode, which reduces the entropy of the output data. 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 6-7 bpp.

Note that the optional RDO encoder function is not super well optimized for perf. yet. That's coming. It can also be greatly improved to achieve better quality per compressed bit. Our highest priority was to ship something that shows that RDO encoding can be accomplished on UASTC texture data, in a simple way.

A previously unused field in .basis files now 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_total_endpoints, 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 be optionally disabled by setting the BASISD_SUPPORT_UASTC preprocessor macro to 0.

There are three ways of accessing the new UASTC functionality:

  1. Use the command line tool to encode UASTC .basis files using the -uastc, -uastc_rdo_q, and -uastc_level options. Then use basisu_transcoder::transcode_image_level() and 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.

  2. 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.

  1. 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.h declares the UASTC transcode functions, and basisu_uastc_enc.h declares 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 basist::basisu_transcoder_init().

The two functions pack_uastc() and 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 basisu_uastc_enc.h are:

transcode_uastc_to_bc1(), transcode_uastc_to_bc3(), transcode_uastc_to_bc4(), transcode_uastc_to_bc5(), transcode_uastc_to_bc7(), transcode_uastc_to_astc(), etc.

Note that we will be optimizing transcode_uastc_to_etc2_eac_r11() and 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.

You can’t perform that action at this time.