Skip to content

UASTC HDR 4x4 Texture Specification v1.0

Rich Geldreich edited this page Jan 23, 2025 · 1 revision

Note: This is a preliminary specification and subject to change. No fundamental changes are planned for though, just fixes.

UASTC HDR 4x4 is an 8-bits/texel 24 mode constrained subset of the Khronos lossy ASTC GPU texture specification. What makes UASTC HDR unique is that it's designed to be rapidly transcodable (i.e. without requiring any expensive per-texel reencoding or recompression steps) to Microsoft's BC6H HDR GPU texture format. This enables positive half-float (FP16, part of IEEE 754-2008) HDR texture and image content encoded to this subset of ASTC HDR to be efficiently deployed and utilized by virtually any modern GPU. The input to the reference encoder is 48-bits/texel (FP16 RGB), resulting in 6:1 compression.

UASTC HDR is 100% standard ASTC HDR texture data. No transcoding or special processing is required to deploy UASTC HDR content to GPU's or API's which support ASTC HDR. UASTC HDR texture data completely follows the ASTC specification, making it compatible with existing GPU's, rendering API's and CPU/compute shader decoders.

Here are some example compressed images.

Like ASTC HDR, UASTC HDR can also be decoded to various uncompressed HDR formats such as half float, float, or the RGB_9E5 texture format. On GPU's not supporting either ASTC HDR or BC6H, UASTC HDR can be decoded to uncompressed formats using the CPU or using a GPU compute shader.

Fundamentally, BC6H and ASTC HDR are based off similar approaches, making it possible to write encoders for either format that output GPU texture data which can be efficiently transcoded to the other. It's possible to modify existing ASTC HDR and BC6H encoders to support UASTC HDR by limiting them to the standardized feature/partition pattern subset described here. For IP reasons, it's also possible to encode UASTC HDR with the encoder not aware of the BC6H texture format at all. Compute shader UASTC HDR->BC6H transcoders are also possible.

Encoders don't need to support all the modes described here. It's likely that real-time encoders will only support a handful of modes, or even just one mode.

Note all following ASTC specification references refer to this specific Khronos ASTC specification document: Khronos Data Format Specification v1.1 rev 9, Chapter 18 - ASTC Compressed Texture Image Formats.

UASTC HDR->BC6H Benchmark vs. GPURealTimeBC6H

FP16 PSNR (higher is better, this is standard RGB average PSNR computed 
directly on the FP16 values interpreted as 16-bit unsigned integers):

            GPURealTimeBC6H HQ  UASTC_HDR->BC6H L4
yucca       53.256              53.794
desk        51.702              51.167
memorial    54.337              54.048
backyard    63.362              63.656
atrium      59.023              58.512
--------------------------------------
Avg.        56.34 dB            56.24 dB

Note GPURealTimeBC6H compares well to Intel's ispc ASTC HDR encoder and DirectXTex's encoder.

Public Domain Declaration

The UASTC HDR specification is explicitly not copyrighted by any entity. It may be used for any purpose whatsoever, including commercial purposes. The author of this work hereby waives all claim of copyright (economic and moral) in this work and immediately places it in the Public Domain; it may be used, deployed, implemented or distributed in any manner whatsoever without further attribution or notice to the creator.

In jurisdictions where this declaration does not apply, the The CC0 Public Domain Dedication applies.

Note it is possible to encode high quality UASTC HDR without using Principle Component Analysis.

Summary of UASTC HDR

UASTC HDR is a simplified ASTC HDR subset designed to be relatively easy to encode and compatible with rapid transcoding directly to BC6H:

  • Only 4x4 texel blocks, so it's always 8-bits texel. (ASTC supports several larger block sizes and lower bitrates, but BC6H doesn't.)
  • Only HDR ASTC blocks. (LDR blocks are permitted in full ASTC HDR textures, but are not permitted in UASTC HDR textures. BC6H is always HDR.)
  • No alpha channel support. (ASTC HDR does support alpha, but BC6H doesn't.)
  • Only 1 or 2 subsets/partitions. (ASTC HDR supports more, but BC6H only supports 1 or 2.)
  • Positive inputs and outputs only. (This is not a limitation of UASTC HDR, but ASTC HDR. BC6H supports a signed variant, but ASTC HDR doesn't.) Transcoding is only supported to DXGI_FORMAT_BC6H_UF16.

ASTC HDR features supported:

  • 24 total ASTC modes (or ASTC CEM (Color Endpoint Mode)+ISE (Integer Sequence Encoding) endpoint/weight configurations): one solid color mode, sixteen 1-subset/partition modes, and seven 2-subset/partition modes.

  • Lossless solid color blocks (ASTC's HDR “void-extent” blocks). LDR void-extent blocks are not supported, only HDR (i.e. the ASTC header's "Dynamic Range" flag must be set to 1, for FP16 values).

  • 1 subset/partition blocks utilizing either ASTC CEM 7 (HDR RGB, base+scale) or 11 (HDR RGB, direct) (only).

  • 2 subset/partition blocks with 27 possible common partition patterns (out of 32 possible for BC6H). Only those patterns in common between both BC6H and ASTC HDR are supported. Each subset can use either CEM 7 or 11 (only). Both subsets must use the same CEM index.

  • For CEM 7, all RGB endpoint encoding modes (or "submodes" in this document) (0-5) are supported. For CEM 11, all submodes (0-7) and the "direct" encoding are supported. (See 18.15 - HDR Endpoint Decoding.)

Forbidden ASTC HDR features:

  • No 3 or 4 partitions, no other CEM modes, no dual plane, and no weight grid upsampling (ASTC weight infill).
  • Any combination of ISE endpoint/weight ranges not listed in this specification (i.e. only ISE endpoint/weight configurations supported by UASTC HDR modes 1-23 are supported).
  • Any ASTC HDR CEM 7/11 encoded endpoint values, when dequantized and decoded by the ASTC HDR CEM 7 or 11 decoder to endpoint RGB vector pairs, would decode to FP16 Inf or NaN half-float values, are forbidden. (BC6H supports floating point denormalization, but it doesn't support Inf (infinity) and NaN (not a number) values.)
  • Only 27 specific ASTC HDR partition pattern seed values are supported. Any other (redundant) seed values are forbidden, even if they would still decode to one of the common UASTC HDR partition patterns. (See the UASTC HDR partition pattern table below.)

Summary of Transcoding to BC6H

To transcode to BC6H, the ASTC block configuration is first decoded from its low-level physical encoding to a higher-level logical representation. This involves examining the ASTC header, decoding the CEM configuration and 10-bit partition pattern seed index, and unpacking the ISE (Integer Sequence Encoding) CEM 7/11 encoded endpoint values and the 16 texel weights.

Void-extent (solid color) blocks are immediately transcoded to solid color BC6H blocks using BC6H mode 14.

Otherwise, the CEM 7 or 11 ISE encoded subset endpoint values are dequantized (see section 18.13 - Endpoint Unquantization of the ASTC spec) and unpacked to ASTC HDR endpoint vectors (see section 18.15). These endpoint vector pairs are then decoded to FP16 values by following the ASTC HDR spec (see section 18.19). Non void-extent blocks will always have 1 or 2 pairs of RGB endpoint vectors.

The BC6H mode (which ranges from 1-14, where 1-10 are 1 subset modes and 11-14 are 2 subsets modes) is determined by finding the highest precision BC6H mode that can delta encode without clamping the ASTC HDR endpoint vector pair(s) decoded to FP16.

The 16 ASTC HDR texel weight indices are directly translated to BC6H's weight indices by using small standardized 1D lookup tables (which are documented below). For 2 subset blocks, the 10-bit ASTC partition pattern seed index is translated to one of the 27 common BC6H patterns using a small standardized 1D lookup table (also below).

UASTC HDR->BC6H is typically lossy, except for solid color blocks which are always lossless. However, with a good encoder, the extra error introduced by transcoding to BC6H is typically a fraction of a dB PSNR (in 16-bit half-float space, with the FP16 values interpreted as uint16_t's). An encoder that simultaneously tracks both UASTC HDR and transcoded BC6H error can minimize any extra error introduced when transcoding to BC6H. Because some BC6H and ASTC HDR weight interpolants slightly differ, an encoder can also choose to not utilize some ASTC weights in a block in order to minimize overall block error after transcoding.

It's possible to encode some blocks to UASTC HDR that, when transcoded to BC6H, actually result in less error vs. the original texture compared to the block's ASTC HDR decoding.

Note the reference BC6H transcoding method described in this specification is only a recommendation and not a requirement. Other potentially higher quality methods may be found and implemented in the future.

UASTC HDR Common Partition Pattern Table

Here's a visualization of the 27 supported UASTC HDR partition patterns (or shapes). These are the partition patterns in common between ASTC HDR and BC6H. Red pixels indicate ASTC partition/subset 0, and green pixels indicate ASTC partition/subset 1:

image

Here's a table of the supported partition patterns:

UASTC HDR Pattern Index ASTC Pattern Seed Index BC6H Partition Index Invert Subsets Flag
0 28 0 0
1 20 1 0
2 16 2 1
3 29 3 0
4 91 4 1
5 9 5 0
6 107 6 1
7 72 7 1
8 149 8 0
9 204 9 1
10 50 10 0
11 114 11 1
12 496 12 1
13 17 13 1
14 78 14 0
15 39 15 1
16 252 17 1
17 828 18 1
18 43 19 0
19 156 20 0
20 116 21 0
21 210 22 1
22 476 23 1
23 273 24 0
24 684 25 1
25 359 26 0
26 246 29 1

Notes:

  • The "Invert Subsets Flag" indicates the BC6H subset index (from the BC6H Partition Set tables) should be inverted to derive the ASTC HDR subset index. The BC6H partition patterns are the same as the first 32 2-subset patterns in Microsoft's BC7 GPU texture format.

  • ASTC's procedural partition pattern generator can output the same pattern shapes given different seed values. Importantly only the above ASTC partition pattern seed values are supported by UASTC HDR. Any other seed values are invalid and not UASTC HDR.

Here are the { ASTC seed index, BC6H partition index, invert flag } entries as a C-style table:

{ 28, 0, 0 }, { 20, 1, 0 }, { 16, 2, 1 }, { 29, 3, 0 }, { 91, 4, 1 }, { 9, 5, 0 }, { 107, 6, 1 }, { 72, 7, 1 },
{ 149, 8, 0 }, { 204, 9, 1 }, { 50, 10, 0 }, { 114, 11, 1 }, { 496, 12, 1 }, { 17, 13, 1 }, { 78, 14, 0 }, { 39, 15, 1 },
{ 252, 17, 1 }, { 828, 18, 1 }, { 43, 19, 0 }, { 156, 20, 0 }, { 116, 21, 0 }, { 210, 22, 1 }, { 476, 23, 1 }, { 273, 24, 0 },
{ 684, 25, 1 }, { 359, 26, 0 }, { 246, 29, 1 }

Here are the UASTC HDR partition pattern shapes as a C-style table (each line contains one 4x4 pattern):

 { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
 { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
 { 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },
 { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
 { 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 },
 { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
 { 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
 { 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0 },
 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
 { 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
 { 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
 { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
 { 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
 { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1 },
 { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
 { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
 { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1 },
 { 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
 { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1 },
 { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
 { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }

Standard ASTC ISE Range Table Reference

For the purposes of this specification and the following UASTC HDR mode tables, here is a table defining all supported ISE encoding ranges supported by the full ASTC specification. Note these are the standard ASTC ISE ranges, presented in a simple table form. UASTC HDR further limits which specific ISE ranges can be utilized by each supported block configuration/CEM mode.

The UASTC HDR specification refers to these ISE ranges by the ISE Index rows in this table.

ISE Index Bits Trits Quints Encodable Range Notes
0 1 0 0 0..1 ASTC min weight ISE index
1 0 1 0 0..2
2 2 0 0 0..3
3 0 0 1 0..4
4 1 1 0 0..5 ASTC min endpoint ISE index
5 3 0 0 0..7
6 1 0 1 0..9
7 2 1 0 0..11
8 4 0 0 0..15
9 2 0 1 0..19
10 3 1 0 0..23
11 5 0 0 0..31 ASTC max weight ISE index
12 3 0 1 0..39
13 4 1 0 0..47
14 6 0 0 0..63
15 4 0 1 0..79
16 5 1 0 0..95
17 7 0 0 0..127
18 5 0 1 0..159
19 6 1 0 0..191
20 8 0 0 0..255 ASTC max endpoint ISE index

In the ASTC specification, weight indices are limited to ISE ranges [0,11], and the CEM encoded ASTC endpoint values are limited to ISE ranges [4, 20].

As a C-style table:

// The total number of ASTC ISE range.
const int TOTAL_ISE_RANGES = 21;

// This array defines, for each possible ISE range [0,20], the number of bits (index 0), trits (index 1), and quints (index 2) in that range.
// [ise_index][bits/trits/quints]
int8_t ise_range_table[TOTAL_ISE_RANGES][3] = 
{
    //b  t  q
    //2  3  5    // range  ise_index    notes

    // Note: These ranges can be utilized by only ASTC weights.
    { 1, 0, 0 }, // 0..1   0            ASTC min weight ISE index
    { 0, 1, 0 }, // 0..2   1
    { 2, 0, 0 }, // 0..3   2
    { 0, 0, 1 }, // 0..4   3

    // Note: These ISE ranges can be utilized by both ASTC weights and endpoints.
    { 1, 1, 0 }, // 0..5   4            ASTC min endpoint ISE index
    { 3, 0, 0 }, // 0..7   5
    { 1, 0, 1 }, // 0..9   6
    { 2, 1, 0 }, // 0..11  7
    { 4, 0, 0 }, // 0..15  8
    { 2, 0, 1 }, // 0..19  9
    { 3, 1, 0 }, // 0..23  10
    { 5, 0, 0 }, // 0..31  11           ASTC max weight ISE index
    
    // Note: These remaining ISE ranges can only be utilized by ASTC endpoints, not weights.
    { 3, 0, 1 }, // 0..39  12
    { 4, 1, 0 }, // 0..47  13
    { 6, 0, 0 }, // 0..63  14
    { 4, 0, 1 }, // 0..79  15
    { 5, 1, 0 }, // 0..95  16
    { 7, 0, 0 }, // 0..127 17
    { 5, 0, 1 }, // 0..159 18
    { 6, 1, 0 }, // 0..191 19
    { 8, 0, 0 }, // 0..255 20           ASTC max endpoint ISE index
};

UASTC HDR Mode 0: ASTC HDR Void-Extent (Solid Color) Blocks

See Section 18.23. Void-Extent blocks must always use the HDR FP16 encoding (i.e. Bit 9, the Dynamic Range flag, must always be 1). The FP16 values cannot be negative, NaN or Inf.

Solid color ASTC HDR blocks are easily transcodable without any loss to BC6H mode 14 blocks (which uses 4-bit weights and "16.4" Color Endpoints). UASTC HDR Void-Extent blocks and the corresponding transcoded BC6H solid color blocks will always decode to the same FP16 values.

When transcoding HDR Void-Extent blocks to BC6H mode 14, the block's weight indices should all be set to 0, and the Color Endpoints should be set to the nearest BC6H "blog16" values (see Appendix A below) that represent the FP16 values stored in the ASTC HDR void-extent blocks.

UASTC HDR Modes 1-16: 1-Subset ASTC HDR CEM's and ISE Endpoint/Weight Configurations

Here are the single subset ASTC CEM's and corresponding weight/endpoint ISE ranges supported by UASTC HDR:

UASTC HDR Mode CEM Weights ISE Range Endpoints ISE Range
1 7 1 (3 levels) 20 (256 levels)
2 7 2 (4 levels) 20 (256 levels)
3 7 3 (5 levels) 20 (256 levels)
4 7 4 (6 levels) 20 (256 levels)
5 7 5 (8 levels) 20 (256 levels)
6 7 6 (10 levels) 20 (256 levels)
7 7 7 (12 levels) 20 (256 levels)
8 7 8 (16 levels) 20 (256 levels)
9 11 1 (3 levels) 20 (256 levels)
10 11 2 (4 levels) 20 (256 levels)
11 11 3 (5 levels) 20 (256 levels)
12 11 4 (6 levels) 20 (256 levels)
13 11 5 (8 levels) 20 (256 levels)
14 11 6 (10 levels) 20 (256 levels)
15 11 7 (12 levels) 20 (256 levels)
16 11 8 (16 levels) 19 (192 levels)

Note: Because one of these configurations (mode 16) uses quantized (less than 256) CEM 7/11 encoded endpoint values, it's possible for endpoint value quantization error to cause the decoded CEM 11 endpoint vector pairs to be invalid (Inf/Nan) values. These encodings are forbidden in UASTC HDR.

UASTC HDR Modes 17-23: 2-Subset ASTC HDR CEM's and ISE Endpoint/Weight Configurations

Here are the 2-subset ASTC CEM's and corresponding weight/endpoint ISE ranges supported by UASTC HDR. Note in UASTC HDR, both subset's CEM indices must be equal (i.e. either both 7 or both 11).

UASTC HDR Mode CEM Weights ISE Range Endpoints ISE Range
17 7 1 (3 levels) 20 (256 levels)
18 7 2 (4 levels) 20 (256 levels)
19 7 3 (5 levels) 19 (192 levels)
20 7 4 (6 levels) 17 (128 levels)
21 7 5 (8 levels) 15 (80 levels)
22 11 1 (3 levels) 14 (64 levels)
23 11 2 (4 levels) 12 (40 levels)

Note: Because some of these configurations (modes 19-23) use quantized (less than 256) CEM 7/11 encoded endpoint values, it's possible for endpoint value quantization error to cause the decoded CEM 7/11 endpoint vector pairs to be invalid (Inf/Nan) values. These encodings are forbidden in UASTC HDR.

1-Subset UASTC HDR->BC6H Transcode Weight Index Translation Tables

The rows in this table specify how to convert ASTC HDR weight indices (which are encoded and do not always correspond to monotonically increasing interpolant weights, see Section 18.16 - Weight Decoding) to 3 or 4-bit BC6H weight indices (which do always correspond to monotonically increasing interpolant values).

ISE Weight Range ASTC HDR Weight Index to BC6H Weight Index Conversion Table/Notes
1 (3 levels) [ 0, 8, 15 ]
2 (4 levels) [ 0, 5, 10, 15 ]
3 (5 levels) [ 0, 4, 7, 11, 15 ]
4 (6 levels) [ 0, 15, 3, 12, 6, 9 ]
5 (8 levels) No change, select a 2-subset BC6H mode and encode the ASTC endpoints to two equal BC6H subsets (which use 3-bit weights)
6 (10 levels) [ 0, 15, 2, 13, 3, 12, 5, 10, 6, 9 ]
7 (12 levels) [ 0, 15, 4, 11, 1, 14, 5, 10, 2, 13, 6, 9 ]
8 (16 levels) No change

Nearly all supported 1-subset ISE weight ranges can be transcoded to 1-subset 4-bit weight index BC6H modes, except for blocks using ISE weight range 5 (8 levels), which is transcoded to a 2-subset 3-bit weight index BC6H mode (with the endpoint pairs of both BC6H subsets set to equal vectors, effectively converting the BC6H 2-subset block into a single subset block).

2-Subset UASTC HDR->BC6H Transcode Weight Index Translation Tables

The rows in this table specify how to convert ASTC HDR weight indices (which are encoded and do not always correspond to monotonically increasing interpolant weights, see Section 18.16 - Weight Decoding) to 3-bit BC6H weight indices (which do always correspond to monotonically increasing interpolant values).

ISE Weight Range ASTC HDR Weight Index to BC6H Weight Index Conversion Table/Notes
1 (3 levels) [ 0, 4, 7 ]
2 (4 levels) [ 0, 2, 5, 7 ]
3 (5 levels) [ 0, 2, 4, 5, 7 ]
4 (6 levels) [ 0, 7, 1, 6, 3, 4 ]
5 (8 levels) No change

Suggested UASTC HDR->BC6H Transcoding Process

  • Unpack the ASTC block header, CEM configuration and CEM indices, partition seed index, determine the ISE endpoint range, and ISE decode the endpoint and weight values. As UASTC HDR is only a subset of full ASTC, this process can be optimized to only handle the subset of ASTC configurations UASTC HDR supports.

The exact way ASTC blocks are encoded is complex and outlined in the ASTC specification. Alternatively, the reference transcoder library contains a single source file stand-alone C++ header library which can be used as a reference, in transcoder/basisu_astc_helpers.h. See function unpack_block(), which unpacks physical ASTC blocks to a high-level logical ASTC block description structure.

  • If the block is a void-extent block, decode the FP16 block color. Then encode this solid color block to BC6H mode 14 (4-bit weights, 16.4 endpoints). Set the weights to 0. This is always a lossless operation.

  • Otherwise, for 1 or 2 subset blocks, dequantize the block's ISE encoded endpoint values, then decode the CEM 7 or 11 endpoints to half-float endpoint pair RGB vector(s).

  • 1 subset blocks typically transcode to BC6H modes 11-14, which use 4-bit weights. Translate the ASTC weight indices to BC6H weight indices using the "1-Subset UASTC HDR->BC6H Transcode Weight Tables" table above. The one exception are 1-subset ASTC HDR blocks which utilize 8 weight levels, which transcode to 2-subset BC6H modes 1-10, with the 3-bit weights translated to BC6H weights unchanged, and with both BC6H subsets set to the same endpoint pair vectors (effectively turning the 2-subset BC6H block into a single subset block).

  • 2 subset blocks transcode to BC6H modes 1-10. Translate the ASTC weight indices to BC6H weight indices using the "2-Subset UASTC HDR->BC6H Transcode Weight Tables" table above. Some partition patterns require the subsets to be swapped when transcoded to BC6H - see the "Invert Subsets Flag" in the partition pattern table above. (This is a lossless transformation.)

  • For 2-subset blocks, the 10-bit ASTC partition seed pattern is converted to a 5-bit BC6H partition pattern using the "UASTC HDR Partition Pattern Table" above. A 10-bit 1D lookup table can be used to accelerate this conversion. Only those specific ASTC partition pattern seed values specified in this document are valid UASTC HDR, even if other values would result in the same partition pattern.

  • Each BC6H mode supports a different base quantization level and number of "delta" bits (see the "Transform Inversion for Endpoint Values" section in the BC6H spec). The reference transcoder chooses the highest precision BC6H mode that can delta encode the ASTC endpoints (which have been fully decoded to FP16 values) with no clamping required.

If a BC6H mode would require clamping, the next lowest precision mode is tried. In the worse case, the transcoder falls back to BC6H mode 10 (for 2-subsets) or mode 11 (for 1-subsets), which do not use endpoint value delta encoding.

  • In BC6H, the first texel's weight index value is encoded to the 128-bit output block using 1 less output bit. For 2-subset BC6H blocks, one of the second subset's weight indices is also encoded to 1 less bit. (Which one depends on the block's partition pattern.) It may be necessary to invert a subset's endpoints and weight indices if the MSB of the corresponding weight is set to encode to BC6H. (This is always lossless.)

Appendix A: Notes on "qlog16" (ASTC HDR) and "blog16" (BC6H) Endpoint Values

This document, as well as the reference encoder and transcoder, uses two custom terms derived from the ASTC and BC6H specifications:

  • ASTC HDR "qlog16" values: This is ASTC HDR's internal 16-bit pseudo-logarithmic endpoint representation. During ASTC HDR decoding, these internal values (which are 12-bits after CEM decoding) are dequantized to 16-bits, linearly interpolated, and then these 16-bit results are converted to FP16 output values ("Cf" in the ASTC specification) using a standard function to determine the FP16 exponent and mantissa values. See the "C0" and "C1" values in Section 18.19. Weight Application.

During transcoding to BC6H, the ASTC HDR endpoint vector pairs must be converted from qlog16 values to FP16 values in the same way a ASTC HDR decoder does, so they can be converted to BC6H "blog16" values (and then potentially further quantized as needed by the chosen BC6H mode).

  • BC6H "blog16" values: These are 16-bit endpoint values which have been dequantized (using function unquantize() in the BC6H documentation), then interpolated (using function generate_palette_unquantized()). These values can then be converted to FP16 output values using function finish_unquantize().

The BC6H spec defines how to convert internal blog16 values to FP16, but importantly it does not specify how to convert FP16 values to blog16 (the inverse). This is necessary during transcoding from UASTC HDR to BC6H. The following inverse function is utilized by the reference transcoder:

typedef uint16_t half_float;
uint32_t bc6h_half_to_blog(half_float h, uint32_t num_bits)
{
    return (h * 64 + 30) / (31 * (1 << (16 - num_bits)));
}

num_bits may range from 6 to 16, depending on the BC6H mode. half_float is uint16_t, which is the half float value's bits reinterpreted as an unsigned short integer.

  • Note the way BC6H and ASTC HDR internally interpolate blog16 vs. qlog16 values slightly differ. ASTC HDR's interpolation "is a considerably closer approximation to a logarithmic space than simple 16-bit interpolation" vs. BC6H's. Also, the interpolant values (derived from the block texel weight indices) used by each format can slightly differ. UASTC HDR encoders can work around these differences to minimize the overall ASTC HDR+transcoded BC6H error.

Appendix B: Example UASTC HDR Encoded and Transcoded BC6H Blocks

This appendix has, for each of the 24 supported ASTC HDR configurations (or UASTC HDR modes), 2 encoded example ASTC HDR and corresponding transcoded BC6H blocks. Each block is 16 bytes, or 128-bits, and each is encoded according to the ASTC and BC6H specifications.

See example/example.cpp, function block_unpack_and_transcode_example() in the Basis Universal library for a simple C++ example of how to unpack these physical ASTC HDR blocks to logical blocks, and how to use the built-in BC6H transcoder to transcode these blocks.

Solid color mode:

UASTC HDR mode 0:
  HDR void-extent
  Example block bytes:
    - UASTC HDR: { 252, 255, 255, 255, 255, 255, 255, 255, 118, 19, 118, 19, 118, 19, 0, 60 }
    - BC6H: { 207, 5, 23, 92, 0, 10, 40, 160, 0, 0, 0, 0, 0, 0, 0, 0 }
    - UASTC HDR: { 252, 255, 255, 255, 255, 255, 255, 255, 0, 60, 0, 60, 0, 60, 0, 60 }
    - BC6H: { 239, 251, 239, 191, 7, 15, 60, 240, 0, 0, 0, 0, 0, 0, 0, 0 }

1-subset modes:

UASTC HDR mode 1:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 1 (3 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 81, 224, 44, 65, 64, 144, 1, 0, 0, 0, 0, 0, 0, 196, 0, 0 }
    - BC6H: { 3, 18, 72, 32, 241, 202, 43, 175, 0, 0, 0, 0, 0, 0, 143, 0 }
    - UASTC HDR: { 81, 224, 30, 1, 192, 158, 1, 0, 0, 0, 0, 0, 64, 126, 126, 6 }
    - BC6H: { 3, 0, 0, 0, 152, 102, 154, 105, 0, 0, 255, 255, 255, 255, 255, 255 }
UASTC HDR mode 2:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 2 (4 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 66, 224, 12, 85, 210, 123, 1, 0, 0, 0, 0, 0, 39, 39, 39, 39 }
    - BC6H: { 3, 33, 131, 30, 82, 46, 185, 233, 80, 250, 80, 250, 80, 250, 80, 250 }
    - UASTC HDR: { 66, 224, 58, 1, 128, 58, 1, 0, 0, 0, 0, 0, 208, 65, 0, 65 }
    - BC6H: { 35, 148, 80, 66, 1, 0, 0, 0, 250, 95, 255, 255, 245, 95, 80, 255 }
UASTC HDR mode 3:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 3 (5 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 82, 224, 152, 37, 166, 3, 1, 0, 0, 0, 0, 176, 80, 50, 166, 219 }
    - BC6H: { 235, 189, 251, 24, 197, 23, 95, 124, 73, 72, 139, 139, 139, 136, 143, 184 }
    - UASTC HDR: { 82, 224, 166, 45, 176, 3, 1, 0, 0, 0, 0, 40, 76, 72, 19, 0 }
    - BC6H: { 235, 62, 4, 133, 77, 80, 65, 3, 1, 0, 7, 75, 7, 7, 11, 119 }
UASTC HDR mode 4:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 4 (6 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 67, 224, 46, 65, 64, 244, 1, 0, 0, 0, 128, 84, 33, 130, 75, 74 }
    - BC6H: { 227, 139, 47, 190, 0, 11, 44, 176, 54, 63, 3, 111, 3, 111, 51, 63 }
    - UASTC HDR: { 67, 224, 88, 196, 10, 48, 0, 0, 0, 0, 64, 216, 11, 111, 113, 173 }
    - BC6H: { 139, 80, 64, 243, 116, 214, 217, 103, 157, 153, 150, 153, 150, 153, 150, 153 }
UASTC HDR mode 5:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 5 (8 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 83, 224, 2, 128, 128, 40, 1, 0, 0, 0, 118, 163, 46, 204, 20, 183 }
    - BC6H: { 108, 173, 181, 214, 162, 136, 2, 138, 40, 0, 168, 177, 97, 150, 106, 218 }
    - UASTC HDR: { 83, 224, 120, 64, 0, 48, 1, 0, 0, 0, 36, 73, 146, 35, 57, 146 }
    - BC6H: { 160, 150, 90, 106, 113, 192, 113, 23, 64, 23, 148, 56, 137, 147, 36, 73 }
UASTC HDR mode 6:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 6 (10 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 65, 226, 76, 64, 128, 38, 1, 0, 0, 248, 239, 191, 255, 254, 251, 111 }
    - BC6H: { 107, 247, 221, 119, 71, 1, 5, 20, 170, 170, 170, 170, 170, 170, 170, 170 }
    - UASTC HDR: { 65, 226, 76, 64, 128, 38, 1, 0, 0, 248, 239, 191, 255, 254, 219, 239 }
    - BC6H: { 107, 252, 241, 199, 199, 6, 27, 108, 90, 165, 85, 85, 85, 85, 85, 85 }
UASTC HDR mode 7:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 7 (12 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 81, 226, 92, 67, 132, 166, 1, 0, 128, 150, 161, 218, 172, 106, 165, 186 }
    - BC6H: { 35, 55, 220, 110, 3, 231, 27, 111, 18, 226, 17, 17, 18, 17, 79, 17 }
    - UASTC HDR: { 81, 226, 90, 64, 128, 172, 1, 0, 128, 116, 171, 219, 229, 106, 223, 154 }
    - BC6H: { 7, 63, 252, 240, 67, 13, 53, 212, 20, 84, 18, 34, 33, 17, 18, 226 }
UASTC HDR mode 8:
  Num partitions: 1
  CEM index: 7
  Weight ISE range: 8 (16 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 66, 226, 100, 1, 128, 152, 0, 0, 216, 238, 190, 222, 216, 222, 216, 222 }
    - BC6H: { 103, 173, 181, 214, 34, 139, 44, 178, 136, 228, 132, 228, 132, 130, 136, 228 }
    - UASTC HDR: { 66, 226, 36, 1, 128, 44, 1, 0, 125, 221, 0, 13, 215, 125, 221, 0 }
    - BC6H: { 3, 0, 0, 0, 160, 132, 18, 74, 0, 187, 190, 235, 176, 0, 187, 190 }
UASTC HDR mode 9:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 1 (3 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 81, 96, 199, 142, 204, 34, 92, 47, 1, 0, 0, 0, 64, 86, 115, 126 }
    - BC6H: { 131, 164, 34, 118, 177, 108, 180, 188, 0, 0, 0, 0, 112, 0, 255, 0 }
    - UASTC HDR: { 81, 96, 47, 9, 124, 112, 126, 254, 0, 0, 0, 0, 64, 122, 134, 129 }
    - BC6H: { 163, 166, 90, 134, 105, 105, 133, 93, 254, 255, 119, 255, 15, 0, 15, 0 }
UASTC HDR mode 10:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 2 (4 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 66, 96, 247, 184, 16, 185, 130, 83, 1, 0, 0, 0, 0, 85, 255, 255 }
    - BC6H: { 35, 175, 188, 160, 202, 47, 70, 11, 1, 0, 0, 0, 85, 85, 255, 255 }
    - UASTC HDR: { 66, 96, 1, 201, 28, 213, 136, 99, 1, 0, 0, 0, 255, 170, 0, 0 }
    - BC6H: { 3, 66, 36, 99, 212, 108, 54, 201, 0, 0, 0, 0, 85, 85, 255, 255 }
  UASTC HDR mode 11:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 3 (5 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 82, 96, 9, 211, 16, 199, 126, 81, 1, 0, 0, 100, 167, 135, 73, 118 }
    - BC6H: { 195, 195, 24, 13, 132, 205, 50, 165, 64, 255, 64, 255, 64, 255, 64, 255 }
    - UASTC HDR: { 82, 96, 191, 138, 41, 202, 122, 120, 0, 0, 0, 248, 243, 26, 253, 219 }
    - BC6H: { 11, 234, 82, 17, 136, 238, 61, 252, 72, 184, 4, 248, 132, 68, 64, 68 }
UASTC HDR mode 12:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 4 (6 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 67, 96, 193, 134, 37, 188, 0, 8, 0, 0, 64, 230, 249, 209, 109, 164 }
    - BC6H: { 75, 107, 97, 157, 8, 111, 60, 225, 156, 207, 105, 3, 57, 198, 6, 147 }
    - UASTC HDR: { 67, 96, 245, 43, 102, 246, 107, 32, 0, 0, 64, 170, 2, 15, 85, 148 }
    - BC6H: { 75, 68, 220, 76, 122, 182, 221, 121, 97, 207, 96, 207, 144, 207, 96, 156 }
UASTC HDR mode 13:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 5 (8 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 83, 96, 39, 144, 13, 174, 126, 122, 0, 0, 59, 245, 171, 166, 2, 8 }
    - BC6H: { 78, 162, 134, 118, 73, 238, 0, 195, 18, 0, 160, 159, 50, 43, 64, 65 }
    - UASTC HDR: { 83, 96, 251, 132, 172, 38, 1, 85, 0, 0, 159, 228, 212, 139, 251, 80 }
    - BC6H: { 106, 41, 211, 12, 147, 102, 2, 150, 5, 0, 152, 161, 91, 214, 81, 10 }
UASTC HDR mode 14:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 6 (10 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 65, 98, 91, 63, 178, 78, 59, 69, 0, 228, 51, 44, 243, 217, 170, 203 }
    - BC6H: { 235, 156, 207, 166, 82, 46, 184, 219, 52, 50, 51, 86, 32, 3, 207, 102 }
    - UASTC HDR: { 65, 98, 229, 178, 100, 164, 81, 180, 0, 96, 5, 44, 129, 46, 232, 51 }
    - BC6H: { 43, 220, 52, 123, 162, 145, 73, 19, 49, 201, 32, 250, 32, 252, 32, 252 }
UASTC HDR mode 15:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 7 (12 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 81, 98, 247, 16, 234, 94, 61, 125, 128, 59, 245, 206, 170, 72, 122, 66 }
    - BC6H: { 75, 8, 148, 158, 73, 168, 162, 132, 24, 149, 17, 225, 246, 154, 214, 171 }
    - UASTC HDR: { 81, 98, 79, 241, 45, 197, 14, 98, 128, 11, 208, 6, 112, 1, 112, 0 }
    - BC6H: { 39, 222, 90, 145, 164, 67, 16, 42, 0, 245, 0, 182, 0, 149, 0, 164 }
UASTC HDR mode 16:
  Num partitions: 1
  CEM index: 11
  Weight ISE range: 8 (16 levels)
  Endpoint ISE range: 19 (192 levels)
  Example block bytes:
    - UASTC HDR: { 66, 98, 89, 167, 60, 234, 94, 65, 123, 119, 247, 183, 255, 219, 234, 12 }
    - BC6H: { 39, 165, 26, 90, 63, 179, 76, 66, 48, 87, 219, 255, 237, 239, 238, 222 }
    - UASTC HDR: { 66, 98, 77, 232, 12, 46, 2, 95, 242, 238, 122, 110, 25, 106, 5, 82 }
    - BC6H: { 199, 170, 148, 188, 199, 122, 232, 173, 186, 95, 169, 103, 137, 161, 136, 176 }

2-subset modes (both subset CEM's are equal):

UASTC HDR mode 17:
  Num partitions: 2
  CEM index: 7
  Weight ISE range: 1 (3 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 81, 40, 2, 78, 90, 161, 75, 48, 58, 97, 43, 16, 0, 195, 3, 97 }
    - BC6H: { 170, 235, 154, 215, 109, 145, 1, 174, 90, 186, 177, 127, 255, 79, 224, 39 }
    - UASTC HDR: { 81, 8, 2, 46, 93, 129, 76, 241, 95, 193, 236, 16, 128, 202, 121, 21 }
    - BC6H: { 242, 111, 189, 217, 36, 112, 152, 33, 241, 89, 128, 143, 248, 142, 239, 248 }
UASTC HDR mode 18:
  Num partitions: 2
  CEM index: 7
  Weight ISE range: 2 (4 levels)
  Endpoint ISE range: 20 (256 levels)
  Example block bytes:
    - UASTC HDR: { 66, 232, 4, 174, 190, 161, 173, 48, 251, 160, 203, 16, 216, 255, 170, 0 }
    - BC6H: { 146, 13, 52, 186, 26, 152, 252, 225, 158, 232, 1, 64, 146, 254, 255, 21 }
    - UASTC HDR: { 66, 104, 13, 174, 130, 80, 21, 41, 66, 176, 20, 9, 32, 8, 165, 127 }
    - BC6H: { 178, 210, 201, 221, 198, 21, 23, 252, 120, 194, 8, 188, 109, 15, 1, 2 }
UASTC HDR mode 19:
  Num partitions: 2
  CEM index: 7
  Weight ISE range: 3 (5 levels)
  Endpoint ISE range: 19 (192 levels)
  Example block bytes:
    - UASTC HDR: { 82, 232, 4, 46, 216, 200, 214, 83, 40, 79, 5, 128, 243, 158, 1, 0 }
    - BC6H: { 193, 54, 154, 92, 16, 80, 80, 161, 146, 229, 1, 0, 0, 222, 246, 5 }
    - UASTC HDR: { 82, 200, 9, 206, 97, 38, 77, 110, 141, 73, 21, 229, 237, 31, 22, 104 }
    - BC6H: { 1, 10, 33, 112, 217, 111, 175, 93, 147, 195, 129, 125, 235, 37, 64, 18 }
UASTC HDR mode 20:
  Num partitions: 2
  CEM index: 7
  Weight ISE range: 4 (6 levels)
  Endpoint ISE range: 17 (128 levels)
  Example block bytes:
    - UASTC HDR: { 67, 136, 85, 238, 154, 126, 225, 184, 235, 87, 132, 97, 75, 229, 150, 178 }
    - BC6H: { 221, 218, 108, 171, 230, 159, 15, 254, 129, 56, 15, 0, 25, 55, 255, 49 }
    - UASTC HDR: { 67, 40, 2, 110, 61, 154, 128, 205, 39, 140, 70, 191, 16, 239, 182, 190 }
    - BC6H: { 161, 216, 160, 113, 144, 107, 174, 217, 38, 161, 189, 13, 25, 71, 31, 217 }
UASTC HDR mode 21:
  Num partitions: 2
  CEM index: 7
  Weight ISE range: 5 (8 levels)
  Endpoint ISE range: 15 (80 levels)
  Example block bytes:
    - UASTC HDR: { 83, 136, 3, 78, 242, 175, 250, 9, 242, 245, 156, 170, 177, 10, 107, 115 }
    - BC6H: { 117, 153, 228, 108, 190, 209, 238, 251, 211, 23, 228, 77, 166, 100, 75, 117 }
    - UASTC HDR: { 83, 200, 9, 110, 6, 104, 61, 242, 111, 61, 255, 103, 203, 18, 221, 214 }
    - BC6H: { 189, 198, 90, 97, 54, 216, 40, 3, 255, 219, 221, 150, 110, 89, 50, 0 }
UASTC HDR mode 22:
  Num partitions: 2
  CEM index: 11
  Weight ISE range: 1 (3 levels)
  Endpoint ISE range: 14 (64 levels)
  Example block bytes:
    - UASTC HDR: { 81, 40, 2, 150, 184, 130, 106, 248, 236, 2, 64, 134, 65, 248, 0, 114 }
    - BC6H: { 1, 23, 28, 96, 223, 25, 151, 27, 28, 163, 1, 224, 255, 255, 31, 0 }
    - UASTC HDR: { 81, 136, 2, 22, 131, 211, 10, 0, 96, 65, 98, 31, 74, 35, 184, 166 }
    - BC6H: { 2, 219, 67, 75, 204, 42, 129, 4, 3, 44, 188, 31, 251, 129, 239, 24 }
UASTC HDR mode 23:
  Num partitions: 2
  CEM index: 11
  Weight ISE range: 2 (4 levels)
  Endpoint ISE range: 12 (40 levels)
  Example block bytes:
    - UASTC HDR: { 66, 40, 2, 22, 229, 136, 130, 104, 69, 64, 136, 8, 247, 130, 0, 95 }
    - BC6H: { 225, 182, 27, 94, 239, 61, 159, 123, 30, 164, 41, 224, 255, 251, 23, 16 }
    - UASTC HDR: { 66, 136, 31, 118, 66, 50, 19, 104, 66, 58, 214, 16, 229, 93, 222, 252 }
    - BC6H: { 162, 220, 87, 223, 220, 206, 8, 208, 128, 61, 2, 14, 161, 18, 132, 74 }

External References

Khronos Data Format Specification v1.1 rev 9 - Section 18: ASTC Compressed Texture Image Formats

Khronos Data Format Specification v1.2 rev 1 - See Chapter 23

Khronos OES_texture_compression_astc

Microsoft BC6H Texture Format

Tools/Libraries

AMD Compressonator github repo

ARM astc-encoder github repo

Intel ispc Texture Compressor github repo

Microsoft DirectXTex github repo

Khronos KTX-Software github repo

bcdec github repo - Small header-only C library to decompress any BC compressed image

GPURealTimeBC6H github repo - Real-time BC6H compressor which runs on a GPU

RenderDoc - Has a quite capable .DDS texture viewer

Papers/Further Reading

astc-encoder's ASTC Format Overview

"Adaptive Scalable Texture Compression" by Nystad et al.

"ASTC: The Future of Texture Compression" by Tom Olson

"Understanding BCn Texture Compression Formats" by Nathan Reed

"Compressed GPU texture formats – a review and compute shader decoders – part 3/3"

"High Dynamic Range Image Encodings" by Greg Ward


This non-copyrighted, Public Domain document was written by Richard Geldreich Jr., Binomial LLC, on Aug. 2024. See the "Public Domain Declaration" above.

Clone this wiki locally