Compressor-Definitions-and-Classes

This content was automatically converted from the project's wiki Markdown to HTML. See the Basis Universal GitHub wiki for the latest content.

This documentation is based off Basis Universal v2.10.

Table of Contents


Intro

The compression library, located in the encoder subdirectory, defines the types and classes needed to compress .KTX2 or .basis files, given one or more LDR/SDR or HDR images. This document describes the key classes and types needed to directly call the C++ compressor, bypassing our higher level (but less capable) C compression API. The tradeoff: the C++ API has sharper edges, and is a bit more tricky to use correctly because of all the codecs and file formats we've added to the system over time while also preventing older code from breaking.

Originally, when Basis Universal was released, the compressor wasn't a library but a command line tool with some internal classes (which also happened to be directly callable by others). Over time the compressor has evolved into a separate C++ encoder library (with a C API), and the API has grown organically as we've added new codecs and capabilities, but we've kept backwards API compatibility with existing C++ code as much as possible.

The JavaScript emscripten wrapper functions, and the C API (which is used by WASM WASI modules and Python) are both layered on top of this C++ API.

Compression functionality lives in the basisu namespace, and transcoder functionality lives in the basist namespace. The transcoder module also has some low-level functionality in the basisu namespace. The compression library depends on functionality provided by the transcoder module.

Also see the C++ transcoder module API reference. The compression C API may also be a useful reference, as it's layered directly on top of this C++ API.

The transcoder module also includes numerous other useful features, such as a number of fast real-time analytical GPU texture block encoders.

For LDR content, XUASTC LDR (particularly with larger block sizes such as 8x8 or 12x12) generally produces the smallest files overall. ETC1S can still be competitive for simpler texture video content, but even then XUASTC LDR 12x12 can beat it — even without skip blocks or conditional replenishment.


Valid HDR Inputs

The minimum HDR input value is 0, and the maximum HDR input value is basist::ASTC_HDR_MAX_VAL (65216.0), which is slightly less than MAX_HALF (65504.0). Both are ASTC HDR limitations, ignoring void-extent block ASTC spec loopholes which we don't exploit.

Signed inputs will be clamped to 0, with a warning printed to stdout.

If an input HDR image has any RGB color components larger than ASTC_HDR_MAX_VAL, each RGB texel in the input image will be rescaled linearly, with a warning printed to stdout. The output .KTX2 file's ktx_map_range key-value entry will contain the proper scale to apply in the pixel shader (or while decoding) to recover the original linear range.

Currently, the code that enforces the HDR input limits is very simplistic, so it's recommended that all input image(s) or custom mipmap levels be in the ASTC HDR encodable [0, ASTC_HDR_MAX_VAL] range before compressing them. The HDR input clamp code applies the clamping to each input image individually, which works fine if there's only a single input image (the most common case), but not with texture array inputs or if custom HDR mipmap chains are supplied. (This will be improved in the next major release.)


Debug Output

The function basisu::enable_debug_printf(bool enabled), defined in transcoder/basisu.h, globally enables or disabled debug printing to stdout. You can then set the m_debug member of the basis_compressor_params compression parameter struct to true (see below) to see verbose debug output.

Enabling debug output can be very useful for verifying that you've properly initialized the compressor and each codec as expected. This corresponds to the command line tool's -debug parameter.


Compressor Global Initialization

The function basisu::basisu_encoder_init() in encoder/basisu_enc.h MUST be called before using any other functions or classes inside the compression library or the transcoder module (transcoder/basisu_transcoder.cpp). It must be allowed to complete and return before calling anything else inside the library or the transcoder module.

This function will also initialize the transcoder by calling basist::basisu_transcoder_init();.

This function is globally mutexed (with std::mutex).


Compressor Library Functionality


Global Macros

These macros, located in encoder/basisu_comp.h, define the library's version:

#define BASISU_LIB_VERSION 210
#define BASISU_LIB_VERSION_STRING "2.10"

Constants

The following constants, referenced throughout the basis_compressor_params documentation, define default values, ranges, and limits used by the compressor. They are located in various encoder headers.

General

Constant Value Description
BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION 16384 Maximum supported texture dimension in texels
BASISU_MAX_IMAGE_DIMENSION 16384 Maximum image dimension in texels
BASISU_MAX_SLICES 0xFFFFFF Maximum number of slices

ETC1S

Constant Value Description
BASISU_QUALITY_MIN 1 Minimum ETC1S quality level (note: 0 is also technically valid but nearly identical to 1)
BASISU_QUALITY_MAX 255 Maximum ETC1S quality level
BASISU_DEFAULT_QUALITY 128 Default ETC1S quality level
BASISU_DEFAULT_ETC1S_COMPRESSION_LEVEL 2 Default ETC1S compression effort level (library default is 2, command line default is 1)
BASISU_MAX_ETC1S_COMPRESSION_LEVEL 6 Maximum ETC1S compression effort level
BASISU_MAX_ENDPOINT_CLUSTERS 16128 Maximum endpoint codebook size (basisu_frontend::cMaxEndpointClusters)
BASISU_MAX_SELECTOR_CLUSTERS 16128 Maximum selector codebook size (basisu_frontend::cMaxSelectorClusters)
BASISU_DEFAULT_ENDPOINT_RDO_THRESH 1.5 Default endpoint RDO threshold (allows block color distance to increase by 1.5 while searching for an alternative nearby endpoint)
BASISU_DEFAULT_SELECTOR_RDO_THRESH 1.25 Default selector RDO threshold (allows block color distance to increase by 1.25 while searching the selector history buffer)
BASISU_DEFAULT_HYBRID_SEL_CB_QUALITY_THRESH 2.0 Default hybrid selector codebook quality threshold

XUASTC LDR

Constant Value Description
BASISU_XUASTC_QUALITY_MIN 1 Minimum XUASTC LDR quality level (in basisu namespace)
BASISU_XUASTC_QUALITY_MAX 100 Maximum XUASTC LDR quality level (in basisu namespace)
astc_ldr::EFFORT_LEVEL_DEF 3 Default XUASTC LDR effort level (in basisu::astc_ldr namespace)
astc_ldr::EFFORT_LEVEL_MIN 0 Minimum XUASTC LDR effort level (in basisu::astc_ldr namespace)
astc_ldr::EFFORT_LEVEL_MAX 10 Maximum XUASTC LDR effort level (in basisu::astc_ldr namespace)

UASTC LDR 4x4 RDO

These constants are defined in encoder/basisu_uastc_enc.h, in the basisu namespace.

Constant Value Description
BASISU_RDO_UASTC_DICT_SIZE_DEFAULT 4096 Default RDO dictionary size
BASISU_RDO_UASTC_DICT_SIZE_MIN 64 Minimum RDO dictionary size
BASISU_RDO_UASTC_DICT_SIZE_MAX 65536 Maximum RDO dictionary size
UASTC_RDO_DEFAULT_SMOOTH_BLOCK_MAX_ERROR_SCALE 10.0 Default smooth block max error scale. The encoder boosts the error of smooth blocks to suppress distortion on smooth areas; larger values protect smooth blocks more. Set to 1.0 to disable.
UASTC_RDO_DEFAULT_MAX_SMOOTH_BLOCK_STD_DEV 18.0 Default smooth block max std deviation. The encoder computes a smoothness factor [0,1] per block by dividing the block's max component variance by this value (then clamping). Larger values protect more blocks.
UASTC_RDO_DEFAULT_MAX_ALLOWED_RMS_INCREASE_RATIO 10.0 Default max allowed RMS increase ratio. How much a block's RMS error may increase before a trial is rejected.
UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH 8.0 Default skip block RMS threshold. Blocks with this much RMS error or more are completely skipped by the RDO encoder.

UASTC LDR 4x4 Packing Level Flags (cPackUASTC*)

These flags are defined in encoder/basisu_uastc_enc.h, in the basisu namespace. They are passed via m_pack_uastc_ldr_4x4_flags. The level values occupy the low 4 bits (cPackUASTCLevelMask = 0xF) and can be OR'd with the optional flags.

Constant Value Description
cPackUASTCLevelFastest 0 Lowest quality, ~1x speed. 5 modes. No BC1 hints. Avg. 43.45 dB
cPackUASTCLevelFaster 1 ~3x slower than fastest. 9 modes. Avg. 46.49 dB
cPackUASTCLevelDefault 2 ~5.5x slower than fastest. 14 modes. Avg. 47.47 dB
cPackUASTCLevelSlower 3 ~14.5x slower than fastest. All 18 modes. Avg. 48.01 dB
cPackUASTCLevelVerySlow 4 ~200x slower than fastest. Best quality. Avg. 48.24 dB
cPackUASTCLevelMask 0xF Mask for the level bits
cPackUASTCFavorUASTCError 8 Favor lowest UASTC error over BC7
cPackUASTCFavorBC7Error 16 Favor lowest BC7 error over UASTC
cPackUASTCETC1FasterHints 64 Use faster ETC1 hint generation
cPackUASTCETC1FastestHints 128 Use fastest ETC1 hint generation
cPackUASTCETC1DisableFlipAndIndividual 256 Disable ETC1 flip and individual mode
cPackUASTCFavorSimplerModes 512 Favor UASTC modes 0 and 10 (experimental, useful for RDO)

XUASTC LDR DCT Quality

These constants are in the basisu::astc_ldr namespace.

Constant Value Description
astc_ldr::DCT_QUALITY_MIN 1 Minimum DCT quality level
astc_ldr::DCT_QUALITY_MAX 100 Maximum DCT quality level

LDR→HDR Upconversion

Constant Value Description
LDR_TO_HDR_NITS 100.0 Default luminance in nits for LDR→HDR upconversion

enum class hdr_modes

Controls the HDR sub-mode when m_hdr is true. Used by m_hdr_mode. Located in encoder/basisu_comp.h.

Value Description
cUASTC_HDR_4X4 Standard but constrained ASTC HDR 4x4 texture data that can be rapidly transcoded to BC6H
cASTC_HDR_6X6 Standard RDO-optimized or non-RDO (highest quality) ASTC HDR 6x6 texture data that can be rapidly re-encoded to BC6H
cUASTC_HDR_6X6_INTERMEDIATE A custom intermediate format based on ASTC HDR 6x6 that can be rapidly decoded straight to ASTC HDR 6x6 or re-encoded to BC6H

enum basist::ktx2_supercompression

Controls KTX2 supercompression via m_ktx2_uastc_supercompression. Located in the transcoder module.

Value Int Description
KTX2_SS_NONE 0 No supercompression
KTX2_SS_BASISLZ 1 BasisLZ (ETC1S) supercompression
KTX2_SS_ZSTANDARD 2 Zstandard supercompression
KTX2_SS_DEFLATE 3 Deflate (currently unsupported)
KTX2_SS_UASTC_HDR_6x6I 4 UASTC HDR 6x6i (assigned by Khronos, in KTX-Software as of 2/19/2026)
KTX2_SS_XUASTC_LDR 5 XUASTC LDR 4x4–12x12 (coordinated with Khronos, not yet in KTX-Software as of 2/19/2026)

enum class basist::astc_ldr_t::xuastc_ldr_syntax

Controls the XUASTC LDR syntax mode via m_xuastc_ldr_syntax. Trades decompression/transcoding speed against compression ratio.

Value Int Description
cFullArith 0 Full arithmetic coding (best ratio, slowest transcoding)
cHybridArithZStd 1 Hybrid arithmetic + Zstandard
cFullZStd 2 Full Zstandard (fastest transcoding, lower ratio) — default

Parameter Helper Types

The compressor uses two small template wrappers — bool_param<def> and param<T> — instead of raw types for most member variables. These wrappers track whether a value has been explicitly changed by the caller (via was_changed()), which lets the compressor distinguish "the user set this to X" from "this is still the default." Both types implicitly convert to their underlying type, so they can be used like plain bool / int / float values in most contexts.

bool_param<def> wraps a bool with a compile-time default. param<T> wraps a value of type T and additionally stores a default, min, and max — assignments are automatically clamped to [min, max]. Both are reset to their defaults (and marked unchanged) by clear().


struct basis_compressor_params

This structure holds all the parameters the compressor and each codec uses. It's located in encoder/basisu_comp.h.

This structure is directly manipulated by the command line tool (basisu_tool.cpp) while parsing the command line. There's usually a 1:1 correspondence between command line parameters and members of this structure. However, note the command line tool's defaults for some codec parameter may differ from the basis_compressor_params member variables.

Importantly, the m_pJob_pool member variable (defined in encoder/basisu_enc.h MUST be set to a pointer to an initialized job_pool object, like this:

// num_total_threads is the number of TOTAL threads in the pool, so 1=no extra threads, 2=1 extra thread etc.
job_pool compressor_jpool(num_total_threads); 
comp_params.m_pJob_pool = &compressor_jpool;

The compressor will distribute parallel tasks to the supplied job pool object. Most codecs will utilize threading if the job pool has more than one thread, regardless of the m_multithreading flag. The m_multithreading member variable (which defaults to true) is currently only checked by the ETC1S codec. To fully disable multithreading across all codecs, create the job pool with 1 thread and set m_multithreading to false.


Quick Reference

Methods

Name Description
clear() Resets all members to construction-time state
set_format_mode() Sets desired codec and block size
set_format_mode_and_effort() Sets codec format + effort level
set_format_mode_and_quality_effort() Sets codec format + quality + effort
set_srgb_options() Sets sRGB-related options as a group
is_etc1s() Returns true if format is ETC1S
is_uastc_ldr_4x4() Returns true if format is UASTC LDR 4x4
is_uastc_hdr_4x4() Returns true if format is UASTC HDR 4x4
get_format_mode() Returns current basis_tex_format

Codec Format & Quality

Name Type Default Description
m_tex_type basist::basis_texture_type basist::cBASISTexType2D Texture type (2D, array, cubemap, video)
m_quality_level int -1 Unified quality level for ETC1S / XUASTC LDR
m_perceptual bool_param<true> true Perceptual sRGB colorspace metrics vs. linear
m_uastc bool_param<false> false (legacy) true for any non-ETC1S format
m_hdr bool_param<false> false (legacy) true for HDR modes
m_hdr_mode hdr_modes cUASTC_HDR_4X4 (legacy) Selects HDR sub-mode
m_xuastc_or_astc_ldr_basis_tex_format param<int> -1 (legacy) XUASTC/ASTC LDR format selector

ETC1S Specific

Name Type Default Description
m_etc1s_max_endpoint_clusters uint32_t 0 Endpoint codebook size
m_etc1s_max_selector_clusters uint32_t 0 Selector codebook size
m_etc1s_compression_level param<int> 2 Compression effort level (0–6)
m_no_selector_rdo bool_param<false> false Disable selector RDO
m_selector_rdo_thresh param<float> 1.25 Selector RDO threshold
m_no_endpoint_rdo bool_param<false> false Disable endpoint RDO
m_endpoint_rdo_thresh param<float> 1.5 Endpoint RDO threshold
m_disable_hierarchical_endpoint_codebooks bool_param<false> false Disable 2-level endpoint codebook searching
m_use_opencl bool_param<false> false Enables OpenCL in ETC1S mode
m_pGlobal_codebooks const basist::basisu_lowlevel_etc1s_transcoder* nullptr Global codebook pointer

UASTC LDR 4x4 Specific

Name Type Default Description
m_pack_uastc_ldr_4x4_flags uint32_t 2 Packing flags (see cPackUASTC*)
m_rdo_uastc_ldr_4x4 bool_param<false> false Enable RDO post-process
m_rdo_uastc_ldr_4x4_quality_scalar param<float> 1.0 RDO quality/lambda scalar
m_rdo_uastc_ldr_4x4_dict_size param<int> 4096 RDO dictionary size
m_rdo_uastc_ldr_4x4_max_smooth_block_error_scale param<float> 10.0 Smooth block max error scale
m_rdo_uastc_ldr_4x4_smooth_block_max_std_dev param<float> 18.0 Smooth block max std dev
m_rdo_uastc_ldr_4x4_max_allowed_rms_increase_ratio param<float> 10.0 Max allowed RMS increase ratio
m_rdo_uastc_ldr_4x4_skip_block_rms_thresh param<float> 8.0 Skip block RMS threshold
m_rdo_uastc_ldr_4x4_favor_simpler_modes_in_rdo_mode bool_param<true> true Favor simpler modes during RDO
m_rdo_uastc_ldr_4x4_multithreading bool_param<true> true Enable multithreading for RDO

UASTC HDR / ASTC HDR Specific

Name Type Default Description
m_uastc_hdr_4x4_options uastc_hdr_4x4_codec_options (initialized) UASTC HDR 4x4 codec options
m_astc_hdr_6x6_options astc_6x6_hdr::astc_hdr_6x6_global_config (cleared) ASTC HDR 6x6 / UASTC HDR 6x6i options
m_hdr_favor_astc bool_param<false> false Favor ASTC HDR quality over BC6H

XUASTC / ASTC LDR Specific

Name Type Default Description
m_xuastc_ldr_effort_level param<int> 3 Effort level (0–10)
m_xuastc_ldr_use_dct bool_param<false> false Enable Weight Grid DCT
m_xuastc_ldr_use_lossy_supercompression bool_param<false> false Allow bounded distortion for smaller files
m_xuastc_ldr_force_disable_subsets bool_param<false> false Disable 2-3 subset usage
m_xuastc_ldr_force_disable_rgb_dual_plane bool_param<false> false Disable RGB dual plane
m_xuastc_ldr_syntax param<int> cFullZStd (2) Syntax mode (speed vs. ratio)
m_xuastc_ldr_channel_weights[4] uint32_t[4] {1,1,1,1} Per-channel error weights
m_xuastc_ldr_blurring bool_param<false> false Experimental blurring (very slow)
m_ls_min_psnr param<float> 35.0 Lossy supercompression min PSNR
m_ls_min_alpha_psnr param<float> 38.0 Lossy supercompression min alpha PSNR
m_ls_thresh_psnr param<float> 1.5 Lossy supercompression threshold PSNR
m_ls_thresh_alpha_psnr param<float> 0.75 Lossy supercompression threshold alpha PSNR
m_ls_thresh_edge_psnr param<float> 1.0 Lossy supercompression edge threshold PSNR
m_ls_thresh_edge_alpha_psnr param<float> 0.5 Lossy supercompression edge threshold alpha PSNR

LDR to HDR Upconversion

Name Type Default Description
m_ldr_hdr_upconversion_srgb_to_linear bool_param<true> true Apply sRGB→linear during upconversion
m_ldr_hdr_upconversion_nit_multiplier param<float> 0.0 Luminance multiplier (0 = default 100 nits)
m_ldr_hdr_upconversion_black_bias param<float> 0.0 sRGB-space black bias

Input Sources

Name Type Default Description
m_read_source_images bool_param<false> false Read inputs from filenames vs. memory
m_source_filenames basisu::vector<std::string> Input filenames
m_source_alpha_filenames basisu::vector<std::string> Input alpha-channel filenames
m_source_images basisu::vector<image> LDR source images in memory
m_source_images_hdr basisu::vector<imagef> HDR source images in memory
m_source_mipmap_images basisu::vector<basisu::vector<image>> Optional LDR mipmap chain
m_source_mipmap_images_hdr basisu::vector<basisu::vector<imagef>> Optional HDR mipmap chain

Resampling

Name Type Default Description
m_resample_width param<int> 0 Target resample width in texels
m_resample_height param<int> 0 Target resample height in texels
m_resample_factor param<float> 0.0 Resample scaling factor

Mipmap Generation

Name Type Default Description
m_mip_gen bool_param<false> false Enable automatic mipmap generation
m_mip_scale param<float> 1.0 Filter kernel scale (<1.0 sharpens, >1.0 blurs)
m_mip_filter std::string "kaiser" Mipmap filter name
m_mip_srgb bool_param<false> false Convert sRGB→linear before filtering, then back (use set_srgb_options())
m_mip_premultiplied bool_param<true> true Premultiplied alpha mips (not currently supported)
m_mip_renormalize bool_param<false> false Renormalize mip texels to unit length (for tangent space normal maps)
m_mip_wrapping bool_param<true> true Assume wrap UV addressing; if false, clamp
m_mip_fast bool_param<true> true Generate each mip from previous level (faster but less accurate)
m_mip_smallest_dimension param<int> 1 Smallest mip dimension in texels

Output & KTX2

Name Type Default Description
m_out_filename std::string Output filename
m_write_output_basis_or_ktx2_files bool_param<false> false Write output file(s) to disk
m_create_ktx2_file bool_param<false> false Also generate KTX2 output
m_ktx2_uastc_supercompression basist::ktx2_supercompression KTX2_SS_NONE KTX2 supercompression type
m_ktx2_key_values basist::ktx2_transcoder::key_value_vec Custom KTX2 key-value entries
m_ktx2_zstd_supercompression_level param<int> 6 Zstd supercompression level
m_ktx2_and_basis_srgb_transfer_function bool_param<true> true sRGB vs. linear transfer function in output DFD

Debug, Status & Validation

Name Type Default Description
m_status_output bool_param<true> true Print codec status to stdout
m_debug bool_param<false> false Print low-level debug info to stdout
m_debug_images bool_param<false> false Write debug images to disk
m_validate_etc1s bool_param<false> false Low-level ETC1S data validation (slower)
m_compute_stats bool_param<false> false Compute codec statistics
m_print_stats bool_param<true> true Print codec statistics (if computed)
m_validate_output_data bool_param<false> false Try transcoding output after compression
m_transcode_flags param<uint32_t> 0 Flags for validation transcoding

Miscellaneous

Name Type Default Description
m_multithreading bool_param<true> true Enable multithreaded encoding
m_y_flip bool_param<false> false Flip source images on Y axis
m_check_for_alpha bool_param<true> true Auto-detect alpha in source images
m_force_alpha bool_param<false> false Force alpha channel on
m_swizzle[4] uint8_t[4] {0,1,2,3} Input channel swizzle (0=R, 1=G, 2=B, 3=A)
m_renormalize bool_param<false> false Renormalize normal-map texels
m_userdata0 uint32_t 0 User data written to .basis header
m_userdata1 uint32_t 0 User data written to .basis header
m_us_per_frame uint32_t 0 Frame timing written to .basis header
m_pJob_pool job_pool* nullptr MUST be set to a valid job pool

Methods

clear()

Resets all member variables to their initial (construction time) state.


void set_format_mode(basist::basis_tex_format m)

This method sets the desired codec and block size: ETC1S, UASTC LDR 4x4, XUASTC LDR 4x4-12x12, etc. It's the preferred way of setting the desired codec. The default is the library's original format, ETC1S.

basis_tex_format is documented here. Use get_format_mode() to retrieve the format mode that was set.


bool set_format_mode_and_effort(basist::basis_tex_format mode, int effort = -1, bool set_defaults = true)

bool set_format_mode_and_quality_effort(basist::basis_tex_format mode, int quality = -1, int effort = -1, bool set_defaults = true)

These methods call set_format_mode() to set the desired codec format, then optionally set the unified effort [0,10] or quality [1,100] level parameters specific to that codec. They return true on success. (Note the quality level can also be set to 0 via this API, which is essentially the same as 1, but it's recommended to only use quality levels [1,100].)

A value of -1 for quality or effort results in not changing the specified parameter, unless set_defaults is true. If effort and/or quality are -1 and set_defaults is true, the default (construction-time) effort and/or quality level parameters set.

Note the interpretation of the default setting for quality is codec dependent. For example, for ETC1S it causes the m_quality_level member variable to be set to -1, which causes the codec to use manually specified codebook sizes. For other formats it results in no DCT, or no RDO, etc.

These methods are the recommended way to set the codec quality and effort levels, however there are lower level methods available to directly set various codec specific configuration parameters, such as "lambda", directly. This can be particularly useful in HDR, because it's tricky for us to compute a RDO lambda setting useable across a wide range of HDR content.


void set_srgb_options(bool srgb_flag)

This method sets three key member variables related to sRGB vs. linear sampling as a group:

m_perceptual = srgb_flag;
m_mip_srgb = srgb_flag;
m_ktx2_and_basis_srgb_transfer_function = srgb_flag;

Note: m_ktx2_and_basis_srgb_transfer_function used to be named m_ktx2_srgb_transfer_func in previous (pre-v2.0) library versions. We changed the default setting to true to match m_perceptual, so we renamed the member variable.

This is the recommended way to tell the compressor that the input is sRGB (photographic) or linear content.

Details on m_perceptual

m_perceptual is interpreted in a codec specific manner. It should be set to true if the input is photographic or sRGB content (like a typical image or albedo map), or false if the input is not photographic (linear light, such as a normal map) content. This setting defaults to true.

m_perceptual is used to control sRGB vs. linear resampling when the m_resample_factor is not 0.

ETC1S will use a simple perceptual colorspace error metric if m_perceptual is true. For ETC1S, which setting is best to use may need some experimentation for content which isn't a typical photo or albedo map.

Some codecs, such as UASTC LDR 4x4, ASTC LDR 4x4-12, and XUASTC LDR 4x4-12x12, always internally use plain linear SSE/MSE/PSNR metrics, ignoring this setting.

For UASTC HDR 4x4: If m_perceptual is true the RGB channel weights are set to (2,3,1), otherwise they are set to (1,1,1). If m_perceptual is true, it is possible to customize the channel weights directly by setting m_uastc_hdr_4x4_options.m_r_err_scale and m_uastc_hdr_4x4_options.m_g_err_scale member variables to the desired RG weights (B is always 1.0).

Details on m_ktx2_and_basis_srgb_transfer_function

m_ktx2_and_basis_srgb_transfer_function controls the transfer function value written into the DFD of the generated .KTX2 file. It defaults to true. It most likely should match m_perceptual.

In HDR mode this member variable is ignored and the LINEAR transfer function is always written to the KTX2's DFD. A warning message will be printed if m_ktx2_and_basis_srgb_transfer_function is true in HDR mode.

The ASTC LDR 4x4-12x12 and XUASTC LDR 4x4-12x12 codecs use m_ktx2_and_basis_srgb_transfer_function to control how candidate ASTC blocks are decoded (linear vs. sRGB) during compression. For maximum quality, it's important to match this setting against how the ASTC texture will be decoded by the GPU. The transcoder also uses this value — either from the KTX2 DFD or from the XUASTC per-mipmap header (which this setting controls) — to ensure consistent decode behavior at transcode time.

Details on m_mip_srgb

m_mip_srgb controls whether the automatic mipmap generator converts the input from sRGB to linear space before filtering (and then back to sRGB). Note this parameter defaults to false unless set by the developer. This default exists for backwards API compatibility with older code that uses the C++ API directly — changing it to true would alter the output of existing programs that don't explicitly set it. It's recommended m_mip_srgb match m_perceptual (which is why set_srgb_options() exists). The command line tool does this automatically unless -mip_linear or -mip_srgb were specified.


bool is_etc1s() const, bool is_uastc_ldr_4x4() const, bool is_uastc_hdr_4x4() const

Simple helper methods that determine which codec mode is active by querying the legacy member variables. is_etc1s() checks m_uastc only. is_uastc_ldr_4x4() checks m_uastc, m_hdr, and m_xuastc_or_astc_ldr_basis_tex_format. is_uastc_hdr_4x4() checks m_uastc, m_hdr, and m_hdr_mode. These exist because the legacy member variable combinations are easy to get wrong.


basist::basis_tex_format get_format_mode() const

Returns the current format mode as a basist::basis_tex_format, as set by set_format_mode(). Because of backwards API compatibility the compressor doesn't use this value directly yet; it's here to aid the transition to the new API.


Member Variables — Codec Format & Quality

basist::basis_texture_type m_tex_type

Sets the texture type: 2D, 2D texture array, cubemap array, or texture video frames. See the documentation of this enum here.

This setting impacts the number of source images expected by the compressor. For example, cubemaps require a multiple of 6 images (one for each face), etc.


int m_quality_level

This member variable was previously named m_etc1s_quality_level. It was renamed because it's no longer ETC1S specific.

The m_quality_level member variable allows the developer to directly set the ETC1S or XUASTC LDR quality levels. It defaults to -1. It's recommended to use the method set_format_mode_and_quality_effort() (see above) to set the codec quality level, instead of directly manipulating this member variable.

ETC1S: this parameter ranges from [1,255] or [BASISU_QUALITY_MIN, BASISU_QUALITY_MAX]. (Note 0 is also a valid ETC1S quality level setting, but for all practical purposes it's the same as 1.) If m_quality_level is -1, manually set codebook sizes (controlled by the m_etc1s_max_endpoint_clusters and m_etc1s_max_selector_clusters member variables, which both default to 0 after construction) will be used instead.

XUASTC LDR: this parameter, which controls the Weight Grid DCT's quantization table, ranges from [1,100] or [BASISU_XUASTC_QUALITY_MIN, BASISU_XUASTC_QUALITY_MAX]. (Note 0 is also a valid setting, but it'll be the same quality as 1.) If m_quality_level is -1, Weight Grid DCT will be disabled, otherwise it'll be enabled if m_xuastc_ldr_use_dct is also enabled. This parameter is a libjpeg-style DCT quality setting, where values 90 or above are very high quality, values 75 or higher are average quality, and lower values are progressively worse quality. Values below ~30 (depending on the content and XUASTC LDR block size) may be unusable without some sort of deblocking.


bool_param<true> m_perceptual

Use perceptual sRGB colorspace metrics instead of linear. Defaults to true. See set_srgb_options() above for details on how this interacts with other sRGB-related settings.


m_uastc, m_hdr, m_hdr_mode, and m_xuastc_or_astc_ldr_basis_tex_format (legacy)

These legacy member variables control which codec the format uses. It's highly recommended to call set_format_mode() (or set_format_mode_and_quality_effort(), etc.) instead of directly manipulating these member variables, which takes care of setting them correctly for you.

They exist for backwards API compatibility with older code, which manipulates them directly.

Legacy codec selection rules

By default the library generates LDR ETC1S data. The rules are:


Member Variables — ETC1S Specific

uint32_t m_etc1s_max_endpoint_clusters and uint32_t m_etc1s_max_selector_clusters

ETC1S: These settings directly control the codebook sizes. They are only used when m_quality_level is set to -1. The larger the codebook sizes, the higher the overall quality, but the higher the bitrate. Larger codebooks also take longer to unpack before transcoding.


param<int> m_etc1s_compression_level

ETC1S compression effort level, ranging from 0 to BASISU_MAX_ETC1S_COMPRESSION_LEVEL (higher is slower). This parameter controls numerous internal encoding speed vs. compression efficiency/performance tradeoffs. Defaults to BASISU_DEFAULT_ETC1S_COMPRESSION_LEVEL (note: the library default is 2, which differs from the command line tool's default of 1).

This is not the same as the ETC1S quality level (m_quality_level), and most users shouldn't need to change this. It's recommended to use set_format_mode_and_effort() or set_format_mode_and_quality_effort() to set the effort level in a unified way across all codecs, rather than setting this member variable directly.


bool_param<false> m_no_selector_rdo and param<float> m_selector_rdo_thresh

Controls selector Rate-Distortion Optimization. If m_no_selector_rdo is true, selector RDO is disabled, resulting in faster compression but larger files. m_selector_rdo_thresh sets the RDO threshold (defaults to BASISU_DEFAULT_SELECTOR_RDO_THRESH).


bool_param<false> m_no_endpoint_rdo and param<float> m_endpoint_rdo_thresh

Controls endpoint Rate-Distortion Optimization. If m_no_endpoint_rdo is true, endpoint RDO is disabled. m_endpoint_rdo_thresh sets the RDO threshold (defaults to BASISU_DEFAULT_ENDPOINT_RDO_THRESH).


bool_param<false> m_disable_hierarchical_endpoint_codebooks

If true the front end will not use 2-level endpoint codebook searching, for slightly higher quality but much slower execution. Note some m_etc1s_compression_level settings disable this automatically.


bool_param<false> m_use_opencl

Enables OpenCL usage in ETC1S mode. The compressor will fall back to CPU encoding if something goes wrong.

OpenCL usage is only available if the BASISU_SUPPORT_OPENCL macro was set to 1 at compile time, and if a OpenCL v1.2 driver is available.


const basist::basisu_lowlevel_etc1s_transcoder *m_pGlobal_codebooks

Pointer to an ETC1S global codebook object. Defaults to nullptr.


Member Variables — UASTC LDR 4x4 Specific

uint32_t m_pack_uastc_ldr_4x4_flags

UASTC LDR 4x4 packing/quality flags. Defaults to cPackUASTCLevelDefault (2). See UASTC LDR 4x4 Packing Level Flags (cPackUASTC*) for all available values.

The lowest nibble (masked by cPackUASTCLevelMask, 0xF) selects the effort/quality level (cPackUASTCLevelFastest through cPackUASTCLevelVerySlow). The remaining bits are optional flags that can be logically OR'd together with the level, for example: cPackUASTCLevelSlower | cPackUASTCFavorBC7Error.

It's recommended to use set_format_mode_and_effort() or set_format_mode_and_quality_effort() to set the effort level rather than manipulating this member variable directly. If you need to set additional flags beyond the effort level, you can OR them in afterward.


bool_param<false> m_rdo_uastc_ldr_4x4

Enables UASTC LDR 4x4 Rate-Distortion Optimization post-processing. Defaults to false. This variable and m_rdo_uastc_ldr_4x4_quality_scalar will be set automatically if you use set_format_mode_and_effort() or set_format_mode_and_quality_effort().


param<float> m_rdo_uastc_ldr_4x4_quality_scalar

RDO quality/lambda scalar for UASTC LDR 4x4. Defaults to 1.0. The higher this value, the lower the quality, but the more compressible the output data will be. It's recommended to use set_format_mode_and_quality_effort() to set this rather than manipulating it directly.


param<int> m_rdo_uastc_ldr_4x4_dict_size

RDO dictionary size. Defaults to BASISU_RDO_UASTC_DICT_SIZE_DEFAULT, range [BASISU_RDO_UASTC_DICT_SIZE_MIN, BASISU_RDO_UASTC_DICT_SIZE_MAX].


m_rdo_uastc_ldr_4x4_max_smooth_block_error_scale, m_rdo_uastc_ldr_4x4_smooth_block_max_std_dev, m_rdo_uastc_ldr_4x4_max_allowed_rms_increase_ratio, m_rdo_uastc_ldr_4x4_skip_block_rms_thresh

Advanced UASTC LDR 4x4 RDO tuning parameters (param<float>). They control how aggressively RDO optimizes smooth blocks and how much quality degradation is allowed. They default to their respective UASTC_RDO_DEFAULT_* constants.

Smooth areas of a texture are less resilient to distortion than detailed/noisy areas because of the texture masking effect — the human visual system readily perceives artifacts in smooth gradients but tends to mask them in complex regions. The smooth block parameters (m_rdo_uastc_ldr_4x4_max_smooth_block_error_scale and m_rdo_uastc_ldr_4x4_smooth_block_max_std_dev) exist to protect these perceptually sensitive areas from excessive RDO degradation.


bool_param<true> m_rdo_uastc_ldr_4x4_favor_simpler_modes_in_rdo_mode

If true (the default), the RDO post-processor favors simpler UASTC modes.


bool_param<true> m_rdo_uastc_ldr_4x4_multithreading

Enables multithreading for the UASTC LDR 4x4 RDO post-processor. Defaults to true.


Member Variables — UASTC HDR / ASTC HDR Specific

uastc_hdr_4x4_codec_options m_uastc_hdr_4x4_options

UASTC HDR 4x4 codec options structure. Initialized via its init() method on clear().

If m_perceptual is true, you can customize the channel weights directly by setting m_uastc_hdr_4x4_options.m_r_err_scale and m_uastc_hdr_4x4_options.m_g_err_scale to the desired RG weights (B is always 1.0).

struct uastc_hdr_4x4_codec_options

It's recommended to use set_format_mode_and_effort() or set_format_mode_and_quality_effort() to configure the UASTC HDR 4x4 codec. However, if you need lower-level control, you can manipulate this struct directly.

struct uastc_hdr_4x4_codec_options : astc_hdr_codec_base_options
{
    uastc_hdr_4x4_codec_options();
    void init();

    static const int cMinLevel = 0;
    static const int cMaxLevel = 4;
    static const int cDefaultLevel = 1;

    void set_quality_level(int level); // sets internal codec parameters for the given level [0,4]
};

set_quality_level() configures the codec's internal parameters for a given quality level from cMinLevel (0) to cMaxLevel (4). Higher levels produce better quality but are slower. The default level is cDefaultLevel (1).

Note that calling set_format_mode_and_quality_effort() will set this quality level for you via the unified effort mapping. If you call set_quality_level() directly afterward, it will override the unified effort level that was set previously.


astc_6x6_hdr::astc_hdr_6x6_global_config m_astc_hdr_6x6_options

ASTC HDR 6x6 and UASTC HDR 6x6i codec options structure. Cleared via its clear() method.

It's recommended to use set_format_mode_and_effort() or set_format_mode_and_quality_effort() to configure this codec. However, directly setting m_lambda may be necessary for advanced use, because it's quite difficult to map an integer [1,100] quality level to a usable RDO lambda across the wide range of HDR content this codec handles.

Important: m_astc_hdr_6x6_options.m_rec2020_bt2100_color_gamut is also used to set the KTX2 DFD's color primaries field for all codecs, not just ASTC HDR 6x6 / UASTC HDR 6x6i. Set this to true if your input uses the REC 2020/BT.2100 gamut. By default (false), REC 709 is assumed. This is a known misplacement — in a future release, this option will be moved into the main basis_compressor_params structure.

The ASTC HDR 6x6 and UASTC HDR 6x6i's encoder uses different formulas to convert the input HDR linear RGB pixels to ICtCp/Delta E ITP space if the input is known to be REC 2020/BT 2100 vs. the default REC 709. It's important this flag is set correctly, otherwise the encoder will be internally computing distortions in the wrong color space.

struct astc_hdr_6x6_global_config

The "user comp level" is the codec's effort level, ranging from 0 to ASTC_HDR_6X6_MAX_USER_COMP_LEVEL (12). The default is ASTC_HDR_6X6_DEF_USER_COMP_LEVEL (2). This is translated internally into m_master_comp_level and m_highest_comp_level.

// Constants
const uint32_t ASTC_HDR_6X6_DEF_USER_COMP_LEVEL = 2;
const uint32_t ASTC_HDR_6X6_MAX_USER_COMP_LEVEL = 12;

struct astc_hdr_6x6_global_config
{
    // --- Input colorspace ---

    // If true, input is treated as REC 2020/BT.2100 gamut (wider than REC 709).
    // By default (false), input is assumed to be REC 709 linear light in absolute nits.
    bool m_rec2020_bt2100_color_gamut = false;

    // --- Compression levels ---
    // These are set automatically by set_user_level(). Levels 0-3 are normal, 4 is exhaustive.
    uint32_t m_master_comp_level = 0;
    uint32_t m_highest_comp_level = 1;

    // --- RDO lambda ---
    // Controls rate-distortion optimization. 0.0 = no RDO.
    // Directly setting this may be necessary for advanced use cases.
    float m_lambda = 0.0f;

    // --- Encoding options ---
    bool m_extra_patterns_flag = false;         // works in comp levels [1,4]
    bool m_brute_force_partition_matching = false;
    bool m_force_one_strip = false;
    bool m_disable_delta_endpoint_usage = false; // may give slight increase in RDO efficiency, also faster

    // --- JND (Just Noticeable Difference) optimization ---
    // Defaults to false for HDR inputs. For SDR upconverted images, can default to enabled.
    bool m_jnd_optimization = false;
    float m_jnd_delta_itp_thresh = 0.75f;

    // --- Gaussian fallback filters ---
    bool m_gaussian1_fallback = true;           // if disabled, m_gaussian2_fallback should be disabled too
    float m_gaussian1_strength = 1.45f;
    bool m_gaussian2_fallback = true;
    float m_gaussian2_strength = 1.83f;

    // --- Dark pixel adjustment ---
    // Scale up Delta ITP errors for very dark pixels, assuming they may be brightly exposed.
    bool m_delta_itp_dark_adjustment = true;

    // --- Compatibility ---
    // Write v1.6 compatible UASTC HDR 6x6i files for KTX-Software compatibility.
    // The transcoder supports both variants.
    bool m_write_basisu_1_6_compatible_files = true;

    void clear();
    // Max level is ASTC_HDR_6X6_MAX_USER_COMP_LEVEL (12).
    void set_user_level(int level);
};

Key members:

m_lambda controls the RDO strength. A value of 0.0 disables RDO entirely. Higher values produce smaller files at the cost of quality. Because Delta ITP colorspace error metrics are used internally, finding a good lambda value depends heavily on the input content's luminance range, which is why the unified quality mapping can be difficult to apply universally to HDR content.

m_rec2020_bt2100_color_gamut controls the assumed input color gamut for the ASTC HDR 6x6 encoder's Delta E ITP error metric. By default (false), the encoder assumes REC 709 linear light RGB in absolute luminance (nits). If true, the wider REC 2020/BT.2100 gamut is assumed. For SDR/LDR→HDR upconverted content, the sRGB input should be converted to linear light and scaled by 80–100 nits (typical SDR monitor luminance). Upconversion to normalized [0,1] luminances (i.e. non-absolute) is not supported because ITP errors will not be predicted correctly.

m_jnd_optimization enables Just Noticeable Difference optimization, which allows the encoder to use cheaper encodings when the resulting error is modeled to be invisible or nearly invisible (m_jnd_delta_itp_thresh controls the threshold). This defaults to false. In practice, JND mode works well for upconverted SDR/LDR content but can be fragile with native HDR content.

set_user_level() configures the internal compression levels for a given user effort level [0, 12]. Calling set_format_mode_and_effort() or set_format_mode_and_quality_effort() will call this for you via the unified effort mapping.


bool_param<false> m_hdr_favor_astc

If true, ASTC HDR quality is favored more than BC6H quality by the UASTC HDR 4x4 dual-target encoder. Otherwise it's a rough balance. Defaults to false.


Member Variables — XUASTC / ASTC LDR Specific

param<int> m_xuastc_ldr_effort_level

XUASTC LDR effort level. Defaults to astc_ldr::EFFORT_LEVEL_DEF, range [astc_ldr::EFFORT_LEVEL_MIN, astc_ldr::EFFORT_LEVEL_MAX]. It's recommended to use set_format_mode_and_quality_effort() to set this rather than manipulating it directly.


bool_param<false> m_xuastc_ldr_use_dct

Enables Weight Grid DCT for XUASTC LDR. The DCT quality is controlled by m_quality_level [1,100]. Defaults to false.


bool_param<false> m_xuastc_ldr_use_lossy_supercompression

Allows the compressor to introduce a bounded amount of distortion if doing so would produce smaller ASTC or XUASTC files. Defaults to false.


bool_param<false> m_xuastc_ldr_force_disable_subsets

Disables 2-3 subset usage in all effort levels. Results in faster encoding, faster transcoding to BC7, but lower quality. Defaults to false.


bool_param<false> m_xuastc_ldr_force_disable_rgb_dual_plane

Disables RGB dual plane usage (dual plane on alpha blocks is still allowed). Results in faster transcoding to BC7 but lower quality. Defaults to false.


param<int> m_xuastc_ldr_syntax

Controls the XUASTC LDR syntax mode, which trades decompression speed against compression ratio. Defaults to basist::astc_ldr_t::xuastc_ldr_syntax::cFullZStd (fastest transcoding but lower ratio).


uint32_t m_xuastc_ldr_channel_weights[4]

Per-channel error weights for XUASTC LDR. Defaults to {1,1,1,1}.


bool_param<false> m_xuastc_ldr_blurring

Experimental blurring option. Not recommended, very slow. Defaults to false.


Lossy Supercompression PSNR Threshold Parameters

These param<float> variables control the XUASTC lossy supercompression (also known as windowed or bounded RDO) quality thresholds:

param<float> m_ls_min_psnr;                 // default 35.0
param<float> m_ls_min_alpha_psnr;           // default 38.0
param<float> m_ls_thresh_psnr;              // default 1.5
param<float> m_ls_thresh_alpha_psnr;        // default 0.75
param<float> m_ls_thresh_edge_psnr;         // default 1.0
param<float> m_ls_thresh_edge_alpha_psnr;   // default 0.5

Member Variables — LDR→HDR Upconversion

These parameters control how LDR/SDR input images are converted to HDR when compressing to an HDR output format.

Important: LDR/SDR→HDR upconversion is currently only supported when reading source images from files (m_read_source_images = true). It is not applied when providing images directly in memory via m_source_images. If you need to provide LDR images in memory and compress to an HDR format, you must perform the upconversion yourself and place the results in m_source_images_hdr.

bool_param<true> m_ldr_hdr_upconversion_srgb_to_linear

If true (the default), LDR images (such as PNG) will be converted from sRGB to linear light via the sRGB→linear transfer function. If false, LDR images are assumed to already be in linear light (i.e. they don't use the sRGB transfer function). After this step, m_ldr_hdr_upconversion_nit_multiplier and m_ldr_hdr_upconversion_black_bias are applied, and the result is then processed as HDR.


param<float> m_ldr_hdr_upconversion_nit_multiplier

Luminance multiplier used when loading SDR/LDR images and compressing to an HDR output format. Defaults to 0.0, which means use the default of 100.0 nits (LDR_TO_HDR_NITS). This value is an override for the default.

UASTC HDR 4x4: The default multiplier of 1.0 was previously used in this codec's original release. Note this encoder isn't dependent on absolute nits, unlike the ASTC HDR 6x6 encoder.

ASTC HDR 6x6 / UASTC HDR 6x6i: These encoders expect inputs in absolute nits, so the LDR upconversion luminance multiplier default is 100 nits. (Most SDR monitors are/were 80–100 nits.)


param<float> m_ldr_hdr_upconversion_black_bias

Optional sRGB-space bias applied during LDR→HDR upconversion. Should be between [0, ~0.49]. Only applied to black (0.0) color components. Defaults to 0.0 (no bias).


Member Variables — Input Sources

m_read_source_images (bool_param<false>, default: false)

If true, input image files (in any of the supported image file or .DDS format) will be read using filenames in the m_source_filenames and m_source_alpha_filenames arrays.

For .DDS source files: the library uses a forked version of TinyDDS (with some fixes) to read .DDS images. Plain 2D textures are supported, with or without mipmaps, but cubemaps and texture arrays are not currently supported. The supported .DDS pixel formats are: R8G8B8A8_UNORM, R8G8B8A8_SRGB, B8G8R8A8_UNORM, B8G8R8A8_SRGB (LDR), R16G16B16A16_SFLOAT (half float HDR), and R32G32B32A32_SFLOAT (float HDR). DDS loading has been tested against the format AMD Compressonator supports. Using mipmapped .DDS files allows the developer to control exactly what each mipmap level contains, bypassing the automatic mipmap generator. Note: if any input filename is .DDS, all input filenames must be .DDS, and either all must be LDR .DDS or all must be HDR .DDS.

For .EXR source files: the TinyEXR library is used to read .EXR images. This small library does not support all .EXR compression methods. For unsupported images, you can use a tool like ImageMagick to convert them to uncompressed .EXR.

Otherwise, the inputs are assumed to be directly in the m_source_images, m_source_images_hdr, m_source_mipmap_images, and m_source_mipmap_images_hdr arrays.


basisu::vector<std::string> m_source_filenames and basisu::vector<std::string> m_source_alpha_filenames

The input filenames to process. m_read_source_images must be true to read images from files.


basisu::vector<image> m_source_images and basisu::vector<imagef> m_source_images_hdr

The source images to process. Note the compressor only accepts all-LDR or all-HDR input images (i.e. you can't mix LDR and HDR inputs).

Source images do not need to be a multiple of the codec's block size. Before compression, the compressor will automatically enlarge each image to block boundaries by duplicating edge pixels (rows and/or columns), which avoids introducing extra colors into border blocks.


basisu::vector< basisu::vector<image> > m_source_mipmap_images and basisu::vector< basisu::vector<imagef> > m_source_mipmap_images_hdr

The optional source mipmaps to process. These member variables allow the developer to bypass the automatic mipmap generator.

Stores mipmaps starting from level 1 (level 0 is still in m_source_images). If m_source_mipmap_images (or m_source_mipmap_images_hdr for HDR inputs) isn't empty, automatic mipmap generation is skipped. Its size must equal m_source_images.size() (or m_source_images_hdr.size()) or the compressor returns an error. The compressor applies the user-provided swizzling (in m_swizzle) to these images.


Source Image Count Rules

The number of source images the compressor expects depends on m_tex_type:

cBASISTexType2D: N images = N slices (typically N=1 for a single texture). cBASISTexType2DArray: N images = N array layers. cBASISTexTypeCubemapArray: N must be a multiple of 6 (6 faces per cubemap). For cubemap arrays, faces are grouped in sets of 6: [cube0 faces 0..5][cube1 faces 0..5].... The expected face order is +X, -X, +Y, -Y, +Z, -Z. KTX2 cubemap faces must be square. cBASISTexTypeVideoFrames: N images = N video frames.

Dimension constraints differ between .basis and .KTX2:

For .basis files in 2D mode (cBASISTexType2D), the format supports non-uniform collections of texture slices — each input image can have a different resolution. In array mode (cBASISTexType2DArray) and texture video mode (cBASISTexTypeVideoFrames), each slice must be the same resolution.

For .KTX2 files, the KTX2 standard is more constrained: all base (mip 0) images must have the same dimensions, and each slice must have the same number of mipmap levels.

For .basis files in array, texture video, cubemap, and cubemap array modes, each slice must also have the same resolution and the same number of mipmap levels. In plain 2D mode, .basis is more flexible — each slice can have a different resolution and a different number of mipmap levels.

These constraints are validated before compression.

All source images must be the same type (all LDR or all HDR — you cannot mix them).

Custom Mipmap Rules

When providing custom mipmaps via m_source_mipmap_images (or m_source_mipmap_images_hdr):

What you provide Where it goes
Mip level 0 (base) m_source_images[i] or m_source_images_hdr[i]
Mip levels 1..N m_source_mipmap_images[i][0..N-1] or m_source_mipmap_images_hdr[i][0..N-1]

The outer vector size must equal the number of source images (slices/faces/frames). Each slice must provide a contiguous mipmap chain starting from level 1 — you cannot skip levels in the middle. However, the chain can stop at any dimension you want (i.e. you don't have to go all the way down to 1x1). If custom mipmaps are present, automatic mipmap generation (m_mip_gen) is skipped entirely. The same dimension and mipmap count constraints described in Source Image Count Rules above apply.

The expected dimensions for each mipmap level follow the standard GPU convention (OpenGL, WebGL, D3D, Vulkan, Metal):

mip_width  = max(1, base_width  >> mip_index)
mip_height = max(1, base_height >> mip_index)

Where mip_index is 0 for the base level (in m_source_images), 1 for the first mip (in m_source_mipmap_images[i][0]), and so on.

See the UASTC HDR 6x6i Texture Array with Custom Mipmaps example for a working demonstration.


Member Variables — Resampling

m_resample_width, m_resample_height, and m_resample_factor

These settings control how the input images are resampled prior to compression. By default there is no resampling.

param<int> m_resample_width;
param<int> m_resample_height;
param<float> m_resample_factor;

If m_resample_width and m_resample_height are both > 0, the input images will be resampled to the specified dimensions in texels. If m_resample_factor is not 0.0, the input images will be resampled by the specified scaling factor using a box filter.

In both cases, for LDR/SDR inputs, the m_perceptual member variable will control whether or not sRGB to linear conversion will be applied before filtering, and linear to sRGB conversion after filtering.


Member Variables — Mipmap Generation

Mipmap generation is controlled by the m_mip_gen bool_param<false> member variable.

The following parameters control the automatic mipmap generator:

// mipmap generation parameters
bool_param<false> m_mip_gen;
param<float> m_mip_scale; // scales the filter kernel: <1.0 sharpens, >1.0 blurs. Slightly sharpening (e.g. ~0.9) can be useful for textures.
std::string m_mip_filter;
bool_param<false> m_mip_srgb; // if true, LDR images are converted sRGB→linear before filtering, then back to sRGB. Recommended to use set_srgb_options() instead.
bool_param<true> m_mip_premultiplied; // not currently supported, but you can filter the mipmaps yourself and pass them in as .DDS or into member variables
bool_param<false> m_mip_renormalize; // if true, each mip texel is renormalized to approximately unit length (for tangent space normal maps)
bool_param<true> m_mip_wrapping; // if true, assumes wrap UV addressing; if false, assumes clamp
bool_param<true> m_mip_fast; // if true, generates each mip from the previous level (faster); if false, always from the top level (more accurate)
param<int> m_mip_smallest_dimension;

If m_mip_gen is true the automatic mipmap generator is enabled, and the other "mip" related settings control its behavior. It defaults to false.

m_mip_scale defaults to 1.0. m_mip_filter defaults to "kaiser". m_mip_smallest_dimension defaults to 1 texel.

Available m_mip_filter names: "box", "tent", "bell", "b-spline", "mitchell", "blackman", "lanczos3", "lanczos4", "lanczos6", "lanczos12", "kaiser", "gaussian", "catmullrom", "quadratic_interp", "quadratic_approx", "quadratic_mix".

Note for HDR mode: the HDR resample filter applied is currently always "box" (independent of the selected filter in m_mip_filter). This is done to avoid introducing negative pixel values, caused by negative filter kernel weights. We will be improving this in a future release to use range compression filtering (or log-domain filtering).

The automatic mipmap generator computes mipmap level sizes as follows:

w = base_width
h = base_height
total_levels = 1

while max(w, h) > m_mip_smallest_dimension:
    w = max(w >> 1, 1)    // integer (flooring) division by 2
    h = max(h >> 1, 1)    // integer (flooring) division by 2
    total_levels++

Each dimension is halved per level (with a minimum of 1), and generation stops once the largest dimension reaches m_mip_smallest_dimension.


Member Variables — Output & KTX2

std::string m_out_filename

The output filename. m_write_output_basis_or_ktx2_files must be set to true to have the compressor write output files to disk.


m_write_output_basis_or_ktx2_files (bool_param<false>, default: false)

The output filename is controlled by m_out_filename.

If true an output file will be written to disk.


bool_param<false> m_create_ktx2_file

If true, the compressor will also generate a KTX2 file in addition to the .basis file. Internally, the compressor always creates a .basis file first, then converts it losslessly to KTX2. Defaults to false.


basist::ktx2_supercompression m_ktx2_uastc_supercompression

Sets the type of KTX2 supercompression to apply for those codecs which support it: UASTC LDR 4x4, UASTC HDR 4x4, ASTC HDR 6x6, and ASTC LDR 4x4-12x12.

Set to basist::KTX2_SS_ZSTANDARD or basist::KTX2_SS_NONE (the default).


basist::ktx2_transcoder::key_value_vec m_ktx2_key_values

This member variable allows the developer to insert custom key-value entries into the output KTX2 file.


param<int> m_ktx2_zstd_supercompression_level

Sets the KTX2 Zstd supercompression level. The default Zstd level is 6. (See the Zstd documentation for more information.)


bool_param<true> m_ktx2_and_basis_srgb_transfer_function

Controls the transfer function value written into the DFD of the generated .KTX2 file (and also used for .basis files). Defaults to true (sRGB transfer function). Set to false for linear transfer function.

For ASTC LDR and XUASTC LDR, this setting also controls which ASTC decode profile (sRGB vs. linear) is used when unpacking ASTC block data to texels during compression. For maximum quality, it's important to match this setting against how the ASTC texture will be decoded by the GPU.

See set_srgb_options() for the recommended way to set this along with related parameters.


Member Variables — Debug, Status & Validation

m_status_output (bool_param<true>, default: true)

If true, codec status output will be printed to stdout.


m_debug (bool_param<false>, default: false)

If true, low-level codec debug information will be printed to stdout. You must also call basisu::enable_debug_printf(true) to enable debug output at the library level. See Debug Output for details.


m_debug_images (bool_param<false>, default: false)

If true, low-level codec specific debug images will be written to disk, typically as .PNG or .EXR files. (This slows compression.)


m_validate_etc1s (bool_param<false>, default: false)

Low-level ETC1S data validation during encoding. This is slower and primarily useful during development.


m_compute_stats (bool_param<false>, default: false) and m_print_stats (bool_param<true>, default: true)

These member variables control codec statistic computation and display. m_print_stats only has an effect if m_compute_stats is true. Enabling m_compute_stats slows compression.


m_validate_output_data (bool_param<false>, default: false)

If true, the compressor will try transcoding the generated output after compression to a few formats, to verify the output is valid.


param<uint32_t> m_transcode_flags (default: 0)

The flags to use while transcoding if m_validate_output_data is true.


Member Variables — Miscellaneous

m_multithreading (bool_param<true>, default: true)

If true, the ETC1S codec will use multiple threads. The other codecs always distribute their work into the job pool as tasks regardless of this flag — they will utilize threading if the job pool has more than one thread. The job pool always has at least one thread (the calling thread).

The recommended way to control threading is to initialize the job pool to the desired number of threads and set m_multithreading accordingly. To fully disable multithreading, create the job pool with 1 thread (the calling thread only) and set m_multithreading to false.


m_y_flip (bool_param<false>, default: false)

If true each source image will be flipped on the Y axis, which is useful for API's such as WebGL/OpenGL.


m_check_for_alpha (bool_param<true>, default: true) and m_force_alpha (bool_param<false>, default: false)

These parameters control how the compressor decides if the input image(s) have alpha channels or not. For ETC1S, if the input is determined (or forced) to have alpha, the output will contain alpha slices.

If m_check_for_alpha is true, the alpha channels of each source image are checked for any values < 255, and if so the input is assumed to have alpha.

If m_force_alpha is true, it's assumed the input always has alpha. It defaults to false.


uint8_t m_swizzle[4]

This array remaps input channels before compression. Each element is a source channel index (0=R, 1=G, 2=B, 3=A). The default {0,1,2,3} is identity (no swizzle). For example, setting {0,0,0,1} copies R to RGB and G to alpha, which is useful for compressing two-channel data (such as a normal map's XY stored in RG) into a basis/KTX2 file with alpha slices.


m_renormalize (bool_param<false>, default: false)

Treats the input LDR image as a tangent space normal map. If true the input texels of all input images will be renormalized to approximately unit length. See the image::renormalize_normal_map() method for details on exactly how this is done.


uint32_t m_userdata0, uint32_t m_userdata1, and uint32_t m_us_per_frame

These fields go directly into the .basis file header. m_userdata0 and m_userdata1 default to 0. m_us_per_frame (microseconds per frame, for texture video) defaults to 0.


job_pool *m_pJob_pool

Pointer to the job pool used for multithreaded work distribution. MUST not be nullptr — see the initialization example at the top of this section.


class basis_compressor

This class compresses one or more source images (specified via filenames or directly as 32-bpp RGBA or float images in memory) to a .basis or .KTX2 file. It's located in encoder/basisu_comp.h.

The compressor is thread safe — multiple basis_compressor instances can run concurrently. However, each compressor instance must be given its own individual (unique) job_pool object.

Here are the primary methods used for compression:


bool init(const basis_compressor_params &params)

Initializes the compressor with the specified parameter structure. Returns true on success, or false on failure.

Note it should be possible to call init() multiple times with different inputs, but this scenario isn't well tested yet. Ideally, create one basis_compressor object, compress, then delete it.


error_code process()

Valid to call after a successful call to init(). Compresses the input to .basis and optionally .KTX2.

Returns cECSuccess, one of these error codes:

enum error_code
{
  cECSuccess = 0,
  cECFailedInitializing,
  cECFailedReadingSourceImages,
  cECFailedValidating,
  cECFailedEncodeUASTC,
  cECFailedFrontEnd,
  cECFailedFrontendExtract,
  cECFailedBackend,
  cECFailedCreateBasisFile,
  cECFailedWritingOutput,
  cECFailedUASTCRDOPostProcess,
  cECFailedCreateKTX2File,
  cECFailedInvalidParameters
};

const uint8_vec &get_output_basis_file()

Returns a reference to a uint8_t dynamic array containing the output .basis file data, which is always valid if process() succeeds.


const uint8_vec& get_output_ktx2_file()

Returns a reference to a uint8_t dynamic array containing the output .KTX2 file data, which is valid if process() succeeds and KTX2 output file generation was enabled by setting the m_create_ktx2_file parameter to true.


Code Examples

ETC1S

This example compresses an LDR image to an ETC1S .KTX2 file using the C++ API directly.

#include "../encoder/basisu_comp.h"

static bool encode_etc1s()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t W = 256, H = 256;

    image img(W, H);
    for (uint32_t y = 0; y < H; y++)
        for (uint32_t x = 0; x < W; x++)
            img(x, y).set(((x ^ y) & 1) ? 255 : 0);

    basis_compressor_params params;

    // Set the format to ETC1S using the recommended unified method.
    // Quality [1,255], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cETC1S, 75, 3);

    // Use perceptual colorspace error metrics.
    params.set_srgb_options(true);

    // Provide the LDR source image.
    params.m_source_images.push_back(img);

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_etc1s.ktx2";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

UASTC LDR 4x4

This example compresses an LDR image to a UASTC LDR 4x4 .KTX2 file using the C++ API directly.

#include "../encoder/basisu_comp.h"

static bool encode_uastc_ldr_4x4()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t W = 256, H = 256;

    image img(W, H);
    for (uint32_t y = 0; y < H; y++)
        for (uint32_t x = 0; x < W; x++)
            img(x, y).set(((x ^ y) & 1) ? 255 : 0);

    basis_compressor_params params;

    // Set the format to UASTC LDR 4x4 using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cUASTC_LDR_4x4, 75, 3);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Provide the LDR source image.
    params.m_source_images.push_back(img);

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_uastc_ldr_4x4.ktx2";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

UASTC HDR 4x4

This example compresses an HDR image to a UASTC HDR 4x4 .KTX2 file using the C++ API directly.

#include "../encoder/basisu_comp.h"

static bool encode_uastc_hdr_4x4()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t W = 256, H = 256;

    imagef img(W, H);
    for (uint32_t y = 0; y < H; y++)
        for (uint32_t x = 0; x < W; x++)
            img(x, y).set(((x ^ y) & 1) ? basist::ASTC_HDR_MAX_VAL : 1000.0f);

    basis_compressor_params params;

    // Set the format to UASTC HDR 4x4 using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cUASTC_HDR_4x4, 100, 8);

    // This sets the low-level UASTC HDR 4x4 codec quality level directly
    // (overriding set_format_mode_and_quality_effort()'s unified effort level set previously).
    //params.m_uastc_hdr_4x4_options.set_quality_level(3);

    // Use perceptual channel weights (2,3,1) for RGB error metrics instead of uniform (1,1,1).
    params.set_srgb_options(true);

    // Provide the HDR source image.
    params.m_source_images_hdr.push_back(img);

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_uastc_hdr_4x4.ktx2";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

ASTC HDR 6x6

This example compresses an HDR image to an ASTC HDR 6x6 .KTX2 file using the C++ API directly.

#include "../encoder/basisu_comp.h"

static bool encode_astc_hdr_6x6()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t W = 256, H = 256;

    imagef img(W, H);
    for (uint32_t y = 0; y < H; y++)
        for (uint32_t x = 0; x < W; x++)
            img(x, y).set(((x ^ y) & 1) ? basist::ASTC_HDR_MAX_VAL : 1000.0f);

    basis_compressor_params params;

    // Set the format to ASTC HDR 6x6 using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cASTC_HDR_6x6, 100, 8);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Provide the HDR source image.
    params.m_source_images_hdr.push_back(img);

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_astc_hdr_6x6.ktx2";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

UASTC HDR 6x6i

This example compresses an HDR image to a UASTC HDR 6x6 intermediate .KTX2 file using the C++ API directly.

#include "../encoder/basisu_comp.h"

static bool encode_uastc_hdr_6x6i()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t W = 256, H = 256;

    imagef img(W, H);
    for (uint32_t y = 0; y < H; y++)
        for (uint32_t x = 0; x < W; x++)
            img(x, y).set(((x ^ y) & 1) ? basist::ASTC_HDR_MAX_VAL : 1000.0f);

    basis_compressor_params params;

    // Set the format to UASTC HDR 6x6i using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cUASTC_HDR_6x6_INTERMEDIATE, 75, 8);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Provide the HDR source image.
    params.m_source_images_hdr.push_back(img);

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_uastc_hdr_6x6i.ktx2";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

ASTC LDR 4x4-12x12

This example compresses an LDR image to an ASTC LDR 6x6 .KTX2 file (with Zstd supercompression and automatic mipmap generation) using the C++ API directly. Any of the standard ASTC block sizes from 4x4 to 12x12 can be used by changing the basis_tex_format value.

#include "../encoder/basisu_comp.h"

static bool encode_astc_ldr_6x6()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t W = 256, H = 256;

    image img(W, H);
    for (uint32_t y = 0; y < H; y++)
        for (uint32_t x = 0; x < W; x++)
            img(x, y).set(((x ^ y) & 1) ? 255 : 0);

    basis_compressor_params params;

    // Set the format to ASTC LDR 6x6 using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cASTC_LDR_6x6, 75, 3);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Provide the LDR source image.
    params.m_source_images.push_back(img);

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_astc_ldr_6x6.ktx2";

    // Enable Zstd supercompression.
    params.m_ktx2_uastc_supercompression = basist::KTX2_SS_ZSTANDARD;

    // Enable automatic mipmap generation.
    params.m_mip_gen = true;

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

XUASTC LDR 4x4-12x12

This example compresses an LDR image to a XUASTC LDR 6x6 .KTX2 file (with automatic mipmap generation) using the C++ API directly. Any of the standard ASTC block sizes from 4x4 to 12x12 can be used by changing the basis_tex_format value.

#include "../encoder/basisu_comp.h"

static bool encode_xuastc_ldr_6x6()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t W = 256, H = 256;

    image img(W, H);
    for (uint32_t y = 0; y < H; y++)
        for (uint32_t x = 0; x < W; x++)
            img(x, y).set(((x ^ y) & 1) ? 255 : 0);

    basis_compressor_params params;

    // Set the format to XUASTC LDR 6x6 using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cXUASTC_LDR_6x6, 75, 3);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Provide the LDR source image.
    params.m_source_images.push_back(img);

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_xuastc_ldr_6x6.ktx2";

    // Enable automatic mipmap generation.
    params.m_mip_gen = true;

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

ETC1S Texture Video

This example compresses a sequence of LDR frames to an ETC1S .basis texture video file. The resulting file can be viewed using the webgl/video_test WebGL sample. For more information about the best settings to use for encoding texture video, see Encoding ETC1S and XUASTC LDR Texture Video.

.KTX2 texture video texture files can also be viewed using our ktx2_encode_test WebGL sample.

#include "../encoder/basisu_comp.h"

// View the resulting texture video .basis file using the webgl/video_test WebGL sample:
// https://github.com/BinomialLLC/basis_universal/tree/master/webgl/video_test
static bool encode_etc1s_texture_video()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t NUM_FRAMES = 50;
    const uint32_t W = 384, H = 256;

    basis_compressor_params params;

    // Set the format to ETC1S using the recommended unified method.
    // Quality [1,255], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cETC1S, 100, 3);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Create the frames to compress.
    for (uint32_t frame_index = 0; frame_index < NUM_FRAMES; frame_index++)
    {
        image img(W, H);
        img.debug_text(frame_index, 20, 1, 1, g_white_color, &g_black_color, false, fmt_string("Frame {}", frame_index).c_str());
        params.m_source_images.push_back(img);
    }

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Set the texture type to video frames, which causes the compressor to treat the
    // images as a texture video sequence (using skip blocks).
    params.m_tex_type = basist::basis_texture_type::cBASISTexTypeVideoFrames;

    // Write a .basis file to disk.
    // (.KTX2 supports texture video too, but our current texture video WebGL sample only supports .basis.)
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_etc1s_texture_video.basis";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

XUASTC LDR Texture Video

This example compresses a sequence of LDR frames to a XUASTC LDR 8x8 .basis texture video file. The resulting file can be viewed using the webgl/video_test WebGL sample. For more information about the best settings to use for encoding texture video, see Encoding ETC1S and XUASTC LDR Texture Video.

.KTX2 texture video texture files can also be viewed using our ktx2_encode_test WebGL sample.

#include "../encoder/basisu_comp.h"

// View the resulting texture video .basis file using the webgl/video_test WebGL sample:
// https://github.com/BinomialLLC/basis_universal/tree/master/webgl/video_test
static bool encode_xuastc_ldr_texture_video()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t NUM_FRAMES = 50;
    const uint32_t W = 384, H = 256;

    basis_compressor_params params;

    // Set the format to XUASTC LDR 8x8 using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cXUASTC_LDR_8x8, 75, 3);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Create the frames to compress.
    for (uint32_t frame_index = 0; frame_index < NUM_FRAMES; frame_index++)
    {
        image img(W, H);
        img.debug_text(frame_index, 20, 1, 1, g_white_color, &g_black_color, false, fmt_string("Frame {}", frame_index).c_str());
        params.m_source_images.push_back(img);
    }

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Set the texture type to video frames, which causes the compressor to treat the
    // images as a texture video sequence.
    params.m_tex_type = basist::basis_texture_type::cBASISTexTypeVideoFrames;

    // Write a .basis file to disk.
    // (.KTX2 supports texture video too, but our current texture video WebGL sample only supports .basis.)
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_xuastc_ldr_texture_video.basis";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

UASTC HDR 6x6i Texture Array with Custom Mipmaps

This example creates a 2D texture array with custom mipmap levels, performing manual LDR→HDR upconversion in memory, and outputs a UASTC HDR 6x6i .KTX2 file. It demonstrates how to use m_source_mipmap_images_hdr to provide your own mipmap chain and how to use convert_ldr_to_hdr_image() for manual upconversion.

.KTX2 texture array files can also be viewed using our ktx2_encode_test WebGL sample.

#include "../encoder/basisu_comp.h"

static bool encode_uastc_hdr_6x6i_array_custom_mipmap()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    const uint32_t ARRAY_SIZE = 2;
    const uint32_t W = 384, H = 256;

    basis_compressor_params params;

    // Set the format to UASTC HDR 6x6i using the recommended unified method.
    // Unified quality [1,100], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cUASTC_HDR_6x6_INTERMEDIATE, 75, 3);

    // Input is linear.
    params.set_srgb_options(false);

    // Create the array slices, each with a full custom mipmap chain.
    for (uint32_t array_index = 0; array_index < ARRAY_SIZE; array_index++)
    {
        int cur_w = W, cur_h = H;
        int mip_index = 0;

        params.m_source_images_hdr.enlarge(1);
        params.m_source_mipmap_images_hdr.enlarge(1);

        do
        {
            image img(cur_w, cur_h);
            img.debug_text(0, 10, 1, 1, g_white_color, &g_black_color, false,
                fmt_string("{} {} {}x{}", array_index, mip_index, cur_w, cur_h).c_str());

            // Manually upconvert LDR to HDR (sRGB→linear, 100 nits, no black bias).
            imagef hdr_img;
            convert_ldr_to_hdr_image(hdr_img, img, true, 100.0f, 0.0f);

            // The first mip level (0) goes in m_source_images_hdr,
            // and the remaining mip levels go in m_source_mipmap_images_hdr.
            if (!mip_index)
                params.m_source_images_hdr[array_index] = hdr_img;
            else
                params.m_source_mipmap_images_hdr[array_index].push_back(hdr_img);

            ++mip_index;
            cur_w = maximum(1, cur_w / 2);
            cur_h = maximum(1, cur_h / 2);
        } while ((cur_w > 1) || (cur_h > 1));
    }

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Set the texture type to 2D array.
    params.m_tex_type = basist::basis_texture_type::cBASISTexType2DArray;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_uastc_hdr_6x6i_array_custom_mips.ktx2";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

ETC1S Cubemap

This example creates a KTX2 ETC1S cubemap texture file with automatic mipmap generation. In KTX2, cubemap faces must be square. For cubemap arrays, provide 6×N faces.

#include "../encoder/basisu_comp.h"

static bool encode_etc1s_cubemap()
{
    // basisu_encoder_init() MUST have been called before this point.
    basisu_encoder_init();

    // In KTX2, cubemap faces must be square.
    const uint32_t W = 256, H = 256;

    basis_compressor_params params;

    // Set the format to ETC1S using the recommended unified method.
    // Quality [1,255], unified effort [0,10].
    params.set_format_mode_and_quality_effort(basist::basis_tex_format::cETC1S, 75, 3);

    // Input is sRGB.
    params.set_srgb_options(true);

    // Standard cubemap face order: +X, -X, +Y, -Y, +Z, -Z.
    static const char* s_pFace_names[6] = { "+X", "-X", "+Y", "-Y", "+Z", "-Z" };

    // Create the 6 faces to compress (for cubemap arrays, provide 6*N faces).
    for (uint32_t face_index = 0; face_index < 6; face_index++)
    {
        image img(W, H);
        img.debug_text(0, 10, 1, 1, g_white_color, &g_black_color, false,
            fmt_string("Face {} {}", face_index, s_pFace_names[face_index]).c_str());
        params.m_source_images.push_back(img);
    }

    // Enable debug/status output and statistics.
    params.m_debug = true;
    params.m_status_output = true;
    params.m_compute_stats = true;

    // Set the texture type to cubemap/cubemap array.
    params.m_tex_type = basist::basis_texture_type::cBASISTexTypeCubemapArray;

    // Enable automatic mipmap generation.
    params.m_mip_gen = true;

    // Write a .KTX2 file to disk.
    params.m_create_ktx2_file = true;
    params.m_write_output_basis_or_ktx2_files = true;
    params.m_out_filename = "test_etc1s_cubemap.ktx2";

    // Create a job pool. A job pool MUST always be created, even if threading is disabled.
    // num_total_threads is the TOTAL thread count: 1 = calling thread only, 7 = calling thread + 6 extra.
    const uint32_t NUM_THREADS = 7;
    job_pool jp(NUM_THREADS);
    params.m_pJob_pool = &jp;
    params.m_multithreading = true; // only affects ETC1S; other codecs use the job pool directly

    // Initialize and run the compressor.
    basis_compressor comp;
    if (!comp.init(params))
        return false;

    basisu::basis_compressor::error_code ec = comp.process();
    if (ec != basisu::basis_compressor::cECSuccess)
        return false;

    return true;
}

See Also