-
Notifications
You must be signed in to change notification settings - Fork 332
XUBC7 Usage Guide
Copyright (C) 2025-2026 Binomial LLC. All rights reserved except as granted under the Apache 2.0 LICENSE.
- Quick Start
- Intro
- Available Supercompression Modes
- Rate vs. Distortion Control
- All XUBC7 Related Command Line Options
- C++ Encoder API Parameters
- Transcoding
- More Tips and Low-Level System Notes
- Related Pages
See the project's README for information on how to either compile the basisu command line tool, or use our precompiled platform independent .wasm executables (checked into the repository in the bin directory) with a WASM runtime such as Wasmtime.
- For lossless supercompression of the encoded BC7 texture data (the default mode):
basisu -xubc7 input.png
- For lossy compression using Weight Grid DCT (smaller files):
basisu -xubc7 -quality 75 input.png
- For even smaller files, combining DCT with block-level RDO and a higher effort level:
basisu -xubc7 -quality 60 -xubc7_rdo_level 25 -effort 7 input.png
- For the highest quality BC7 base encoding (slower), using the bc7e_scalar base encoder:
basisu -xubc7 -xubc7_bc7e_scalar_level 4 input.png
- For tangent space RGB normal maps or other linear (non-sRGB) content:
basisu -linear -xubc7 input.png
- For the maximum compression ratio (at the cost of decode parallelism):
basisu -xubc7 -xubc7_stripes 1 input.png
- To unpack a .KTX2 file to individual .PNG, .DDS, .KTX, etc. files:
basisu input.ktx2
Add -stats and -debug to see output statistics and debug/development information.
XUBC7, new in Basis Universal v2.50, is a supercompressed BC7 codec: the encoder first packs the input image to BC7 blocks using a real-time BC7 encoder, then losslessly (or lossily) supercompresses that BC7 texture data. On the transcoding side, XUBC7's natural target is BC7 — a fast direct path, since the file contains supercompressed BC7 data — but like the other codecs in the system it can also be transcoded to the other supported LDR texture formats or raster images (see Transcoding below).
The data stored inside the file is always 4x4 BC7 (8 bits/texel before supercompression), with or without alpha. What the output GPU texture is depends on which format you transcode to — the most natural target (least overhead, no additional loss) is naturally BC7 itself. The next most natural target is ASTC LDR 4x4, because most BC7 blocks can be converted using direct latent-to-latent transcoding (converting the block parameters directly, without texel-wise recompression; BC7 2/3 subset blocks whose partition pattern isn't losslessly transcodable to ASTC fall back to real-time repacking).
By default XUBC7 losslessly compresses the encoded BC7 texture data — a default XUBC7 encode is lossless relative to the BC7 encoding. (Like all GPU texture codecs, the BC7 encoding itself is typically lossy relative to the original source image.) Two optional and independent categories of lossy compression are available for smaller files: structured distortion in the frequency domain via Weight Grid DCT, and/or unstructured distortion at the block level via RDO.
Low-level details on the XUBC7 file format (the blob structure inside the supercompressed data) are documented in XUBC7 File Format. XUBC7's KTX2 container details (DFD, seek tables, supercompression scheme) are documented in KTX2 File Format Support Technical Details.
In compression performance, XUBC7 using aggressive RDO/DCT settings competes very well vs. XUASTC LDR 4x4, and in our testing can beat it.
When to choose XUBC7: if your primary GPU target is BC7 (desktop Direct3D/OpenGL/Vulkan, consoles), XUBC7 is the natural choice — transcoding to BC7 is a fast direct path with no block recompression, so there's no transcode-time quality loss on your main target. If your primary target is ASTC hardware (mobile), XUASTC LDR is the better fit for the same reason (and offers larger block sizes for lower bitrates).
Note: Under Direct3D, the first/largest mipmap level's dimensions for BCn compressed textures must be a multiple of 4 texels (unless D3D12_FEATURE_DATA_D3D12_OPTIONS8::UnalignedBlockTexturesSupported is true in D3D 12). This is not a constraint of Basis Universal or WebGPU/Metal/OpenGL/WebGL/Vulkan, but if you're creating mipmapped content that targets BC7 under Direct3D, it's recommended you ensure the texture dimensions are a multiple of 4 before compression. If the texture has no mipmaps, non-multiple-of-4 dimensions are fine: create the D3D texture with the dimensions rounded up to the next multiple of 4 (i.e. ceil() up to the block count, just like the encoder does — it duplicates edge rows/columns as needed), and adjust how you sample it.
With no -quality setting (or -quality 100), and RDO disabled (the default), XUBC7 losslessly supercompresses the encoded BC7 texture data: the transcoded BC7 output decodes identically to the BC7 blocks the base encoder produced. This is the default mode.
-quality X with X in [1,99] enables lossy Weight Grid DCT: perceptually structured distortion in the frequency domain, applied to the BC7 per-texel weights (similar in spirit to the XUASTC LDR codec's Weight Grid DCT — see that guide for background). Lower quality values give smaller files at lower quality. -quality 100 (or leaving it unset) disables DCT.
Note that XUBC7's Weight Grid DCT is stronger than XUASTC's: unlike XUASTC, XUBC7 supports both absolute DCT (transforming the weights directly) and residual DCT (transforming the weights' residuals against a per-block predictor), choosing the best option per block. Additionally, XUBC7's DCT quantization matrix has been heavily tuned vs. XUASTC's (which was essentially JPEG's): XUBC7's is radially symmetric, and the very lowest frequencies are strongly protected. Together these allow XUBC7's lower DCT quality levels to remain more usable at the lowest settings vs. XUASTC.
Like JPEG and XUASTC LDR, DCT shapes distortion in the frequency domain, making pixel-wise error metrics (PSNR, MSE) unreliable for quality evaluation — perceptual metrics like SSIMULACRA 2 are recommended.
-xubc7_rdo_level X, [0,100], enables block-level RDO: perceptually unstructured distortion, permitting bounded per-block quality drops (e.g. reusing nearby block data) in exchange for smaller files. 0 (the default) disables RDO; [1,100] enables it, with 100 the most aggressive setting.
Additionally, when RDO is enabled (and Weight Grid DCT is active), the encoder can truncate a block's AC coefficients if doing so results in a low enough PSNR drop — a simple variant of Trellis quantization.
DCT and RDO are independent — each can be enabled or disabled relative to the other, or combined for the smallest files.
The codec's basic knobs, what they impact, and the distortion type:
| Knob | Affects | Distortion Type |
|---|---|---|
DCT quality (-quality) |
Bitrate (heavily), spectral energy | Structured, perceptual |
RDO level (-xubc7_rdo_level) |
Bitrate, block reuse | Unstructured, blocky |
Effort (-effort) |
Search depth, encode speed | Quality ceiling |
BC7 base encoder (-xubc7_bc7f/-xubc7_bc7e_scalar) |
Base BC7 quality, encode speed | Base encoding quality |
Stripes (-xubc7_stripes) |
Decode parallelism vs. file size | None |
-xubc7
Enables XUBC7 mode. This is the only selector — XUBC7 has no block size options (the output is always 4x4 BC7).
-
-quality X: The primary unified "quality" option.
Enables lossy Weight Grid DCT and sets the DCT quality level, [1,100]. Higher = better quality, but higher bitrate. 100 = lossless (no DCT), which is also the behavior when -quality isn't specified at all — so a plain -xubc7 encode is lossless.
Important: use -quality, not the legacy -q option. For XUBC7, -q prints a warning and is not recommended.
-
-effort X: The primary unified "effort" option, controlling encoding time vs. compression ratio. Must be between [0,10]. Default is 3. Higher values = slower encoding but better compression (the encoder evaluates more weight-grid predictors per block — the dominant encode cost when DCT is enabled). 9 is the usual practical maximum; 10 exists for very high core counts.
The effort level also has side effects at the extremes: effort <= 1 switches the bc7f base packer to its faster default flags, and effort 10 switches it to slower, non-analytical flags for slightly higher base quality. Additionally, effort >= 3 combined with DCT quality >= 90 (which includes the lossless default) enables an extra pass that exhaustively re-optimizes each block's weights for bc7f's endpoints after the base pack.
-
-xubc7_rdo_level X(also-xubc7_rdo): Sets the RDO level, [0,100]. Default is 0 (no RDO). Higher values permit progressively larger per-block quality drops in exchange for smaller files; 100 is the most aggressive setting.
The RDO level maps linearly to the maximum allowed per-block PSNR drops: the general RDO passes (BC7 alternate-pack, endpoint-DPCM, and AC-coefficient truncation) are allowed up to (level/100) * 10 dB per block, and the block-reuse passes (repeat/solid) up to (level/100) * 4 dB. For example, -xubc7_rdo_level 25 allows up to 2.5 dB drops in the general passes and 1 dB for block reuse; level 100 allows up to 10 dB and 4 dB respectively.
-
-xubc7_num_stripes X(also-xubc7_stripes): Sets the desired number of encode stripes, [1,16]. Default is 8.
More stripes = more encode/decode (transcode) parallelism, but slightly larger files. Use -xubc7_stripes 1 for the maximum compression ratio. The stripe count is automatically re-clamped per image based on its size.
Note: the transcoding API does not currently expose XUBC7's transcoder parallelism feature — the stripes are in the files today, so existing content will benefit once the API exposes it.
-
-xubc7_bc7f: Use thebc7freal-time BC7 base encoder (the default) — fast; runs with partially analytical packing flags by default (see the effort side effects above). -
-xubc7_bc7e_scalar(also-xubc7_bc7e): Use thebc7e_scalarbase encoder (based on bc7e.ispc) — slower, but higher base BC7 quality. -
-xubc7_bc7e_scalar_level X: Sets the bc7e_scalar quality level, [0,6]. Default is 2. Higher = slower/better. Note: specifying this option implicitly selects the bc7e_scalar encoder, so you don't also need-xubc7_bc7e_scalar.
-
-weights X Y Z W(also-xuastc_weights,-xuastc_ldr_weights): Set unsigned integer per-channel (RGBA) error weights, each in [1,1024]. Despite the alias names, these weights apply to XUBC7 too — they're used whenever the encoder evaluates block candidates against the original pixels.
The defaults are 9,11,1,11 (Rec. 709-like sRGB/perceptual weights). The -linear and -normal_map presets reset them to 1,1,1,1 — use one of these presets (or -weights 1 1 1 1) for normal maps and other linear content. For textures with important alpha content, setting the alpha (4th) weight above the others can be quite useful.
Note the base encoders differ in weight support: bc7f (the default) supports neither channel weights nor perceptual metrics itself (the weights still steer the supercompression stage); bc7e_scalar supports either — in perceptual mode (the sRGB default) it uses its own perceptual metrics and ignores the weights, in linear mode it honors them.
-
-srgb(the default behavior): sRGB/photographic content preset. -
-linear: linear content preset — sets linear mip filtering, linear channel weights (1,1,1,1), etc. -
-normal_map: normal map preset — like-linearplus additional normal-map-appropriate settings.
-
-ktx2: Write a .KTX2 file (the default). -
-basis: Write a .basis file instead. -
-output_file X/-output_path X: Set the output filename or directory.
Note the KTX2 Zstandard options (-ktx2_zstandard_level, -ktx2_no_zstandard) have no effect on XUBC7 — the codec has its own built-in compression, so its KTX2 files use the KTX2_SS_XUBC7 supercompression scheme instead of Zstd.
-
-mipmap: Enable automatic mipmap generation, along with the standard mipmap options (-mip_filter,-mip_scale,-mip_srgb/-mip_linear,-mip_smallest, etc.), which all work as usual with XUBC7.
- Always supply a numeric value immediately after each value-taking option. A missing value (e.g.
-xubc7_rdo_level -etc1s) will silently consume the next option as its argument. - Don't confuse
-xubc7_bc7e_scalar_levelwith-dds_bc7e_scalar_level— the latter belongs to the separate-dds.DDS export/creation path, not XUBC7 output.
XUBC7 mode is selected via set_format_mode(basist::basis_tex_format::cXUBC7), or (recommended) set_format_mode_and_quality_effort() to set the mode, quality, and effort in one call. The XUBC7-specific basis_compressor_params members (m_xubc7_effort_level, m_xubc7_rdo_level, m_xubc7_num_stripes, m_xubc7_encoder, m_xubc7_bc7e_scalar_level) are fully documented in the Compressor Definitions and Classes reference, which also includes complete, tested lossless and lossy C++ code examples.
The JavaScript (emscripten) API also exposes XUBC7 via cXUBC7 — see webgl/transcoder/basis_wrappers.cpp.
XUBC7's natural transcode target is BC7: the file contains supercompressed BC7 data, so transcoding to BC7 is a fast direct path with no block recompression.
The next most natural target is ASTC LDR 4x4: most BC7 blocks can be converted to ASTC LDR 4x4 using direct latent-to-latent transcoding — the BC7 block parameters are converted directly to ASTC block parameters, without texel-wise recompression. The exception: if a BC7 2/3 subset block uses a partition pattern that isn't losslessly transcodable to ASTC, the transcoder unpacks that BC7 block to texels and packs it to ASTC LDR 4x4 in real-time.
Like the other codecs, XUBC7 files can also be transcoded to the other supported LDR formats: BC1, BC3, BC4, BC5, ETC1, ETC2 RGBA, ETC2 EAC R11/RG11, PVRTC1 RGB/RGBA, and the uncompressed raster pixel formats (RGBA32, RGB565, BGR565, RGBA4444). (These paths decode the BC7 data to texels and re-encode using the transcoder's real-time block encoders, so they're slower than the direct paths and quality is bounded by the intermediate BC7 encoding.)
XUBC7 mipmap levels have seek tables in the KTX2 file (the same ktx2_slice_offset_len_desc_std mechanism as XUASTC LDR), so individual mipmap levels can be transcoded without processing the whole file. See KTX2 File Format Support Technical Details.
-
The default mode is lossless. A plain
basisu -xubc7 input.pnglosslessly supercompresses the BC7 texture data. To trade quality for smaller files, add-quality(DCT),-xubc7_rdo_level(RDO), or both. -
The base BC7 encoding sets the quality ceiling. In lossless mode the output quality is exactly the base encoder's quality — so if quality matters more than encode speed, use
-xubc7_bc7e_scalar_level 4(or higher) to improve the ceiling. -
Stripes trade decode parallelism for size. The default of 8 stripes enables multi-threaded transcoding of each mipmap level (not yet exposed via the transcoding API — but stripes written today will benefit when it is). Content pipelines that only care about the final file size can use
-xubc7_stripes 1. - Deblocking doesn't apply to XUBC7. The adaptive deblocking machinery (CPU and shader) exists for the large ASTC block sizes; XUBC7 is always 4x4 BC7, so there's nothing to deblock.
- Texture arrays, cubemaps, and texture video all work with XUBC7 like the other codecs (
-tex_typeoptions).
- XUBC7 File Format — the blob structure inside the supercompressed data
- KTX2 File Format Support Technical Details — XUBC7's KTX2 DFD, seek tables, and supercompression scheme
- Compressor Definitions and Classes — the C++ API reference, including the XUBC7 parameters and tested code examples
- ASTC and XUASTC LDR Usage Guide — the companion guide for the ASTC-based LDR codecs