skia / external / github.com / KhronosGroup / OpenGL-Registry / 98ac1c85c9f4f0b102980ee7bea4a2ea3e2b04b3 / . / extensions / KHR / KHR_texture_compression_astc_hdr.txt

Name | |

KHR_texture_compression_astc_hdr | |

Name Strings | |

GL_KHR_texture_compression_astc_hdr | |

GL_KHR_texture_compression_astc_ldr | |

Contact | |

Sean Ellis (sean.ellis 'at' arm.com) | |

Jon Leech (oddhack 'at' sonic.net) | |

Contributors | |

Sean Ellis, ARM | |

Jorn Nystad, ARM | |

Tom Olson, ARM | |

Andy Pomianowski, AMD | |

Cass Everitt, NVIDIA | |

Walter Donovan, NVIDIA | |

Robert Simpson, Qualcomm | |

Maurice Ribble, Qualcomm | |

Larry Seiler, Intel | |

Daniel Koch, NVIDIA | |

Anthony Wood, Imagination Technologies | |

Jon Leech | |

Andrew Garrard, Samsung | |

IP Status | |

No known issues. | |

Notice | |

Copyright (c) 2012-2016 The Khronos Group Inc. Copyright terms at | |

http://www.khronos.org/registry/speccopyright.html | |

Specification Update Policy | |

Khronos-approved extension specifications are updated in response to | |

issues and bugs prioritized by the Khronos OpenGL and OpenGL ES Working Groups. For | |

extensions which have been promoted to a core Specification, fixes will | |

first appear in the latest version of that core Specification, and will | |

eventually be backported to the extension document. This policy is | |

described in more detail at | |

https://www.khronos.org/registry/OpenGL/docs/update_policy.php | |

Status | |

Complete. | |

Approved by the ARB on 2012/06/18. | |

Approved by the OpenGL ES WG on 2012/06/15. | |

Ratified by the Khronos Board of Promoters on 2012/07/27 (LDR profile). | |

Ratified by the Khronos Board of Promoters on 2013/09/27 (HDR profile). | |

Version | |

Version 8, June 8, 2017 | |

Number | |

ARB Extension #118 | |

OpenGL ES Extension #117 | |

Dependencies | |

Written based on the wording of the OpenGL ES 3.1 (April 29, 2015) | |

Specification | |

May be implemented against any version of OpenGL or OpenGL ES supporting | |

compressed textures. | |

Some of the functionality of these extensions is not supported if the | |

underlying implementation does not support cube map array textures. | |

Overview | |

Adaptive Scalable Texture Compression (ASTC) is a new texture | |

compression technology that offers unprecendented flexibility, while | |

producing better or comparable results than existing texture | |

compressions at all bit rates. It includes support for 2D and | |

slice-based 3D textures, with low and high dynamic range, at bitrates | |

from below 1 bit/pixel up to 8 bits/pixel in fine steps. | |

The goal of these extensions is to support the full 2D profile of the | |

ASTC texture compression specification, and allow construction of 3D | |

textures from multiple compressed 2D slices. | |

ASTC-compressed textures are handled in OpenGL ES and OpenGL by adding | |

new supported formats to the existing commands for defining and updating | |

compressed textures, and defining the interaction of the ASTC formats | |

with each texture target. | |

New Procedures and Functions | |

None | |

New Tokens | |

Accepted by the <format> parameter of CompressedTexSubImage2D and | |

CompressedTexSubImage3D, and by the <internalformat> parameter of | |

CompressedTexImage2D, CompressedTexImage3D, TexStorage2D, | |

TextureStorage2D, TexStorage3D, and TextureStorage3D: | |

COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 | |

COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 | |

COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 | |

COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 | |

COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 | |

COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 | |

COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 | |

COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 | |

COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 | |

COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 | |

COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA | |

COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB | |

COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC | |

COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD | |

COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 | |

COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA | |

COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB | |

COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC | |

COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD | |

If extension "EXT_texture_storage" is supported, these tokens are also | |

accepted by TexStorage2DEXT, TextureStorage2DEXT, TexStorage3DEXT and | |

TextureStorage3DEXT. | |

Additions to Chapter 8 of the OpenGL ES 3.1 Specification (Textures and Samplers) | |

Add to Section 8.7 Compressed Texture Images: | |

Modify table 8.19 (Compressed internal formats) to add all the ASTC | |

format tokens in the New Tokens section. The "Base Internal Format" | |

column is RGBA for all ASTC formats. | |

Add a new column "Block Width x Height", which is 4x4 for all non-ASTC | |

formats in the table, and matches the size in the token name for ASTC | |

formats (e.g. COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR has a block size of | |

10 x 8). | |

Add a second new column "3D Tex." which is empty for all non-ASTC | |

formats. If only the LDR profile is supported by the implementation, | |

this column is also empty for all ASTC formats. If both the LDR and HDR | |

profiles are supported, this column is checked for all ASTC formats. | |

Add a third new column "Cube Map Array Tex." which is empty for all | |

non-ASTC formats, and checked for all ASTC formats. | |

Append to the table caption: | |

"The "Block Size" column specifies the compressed block size of the | |

format. Modifying compressed images along aligned block boundaries is | |

possible, as described in this section. The "3D Tex." and "Cube Map | |

Array Tex." columns determine if 3D images composed of compressed 2D | |

slices, and cube map array textures respectively can be specified using | |

CompressedTexImage3D." | |

Append to the paragraph at the bottom of p. 168: | |

"If <internalformat> is one of the specific ... supports only | |

two-dimensional images. However, if the "3D Tex." column of table 8.19 | |

is checked, CompressedTexImage3D will accept a three-dimensional image | |

specified as an array of compressed data consisting of multiple rows of | |

compressed blocks laid out as described in section 8.5." | |

Modify the second and third errors in the Errors section for | |

CompressedTexImage[2d]D on p. 169, and add a new error: | |

"An INVALID_VALUE error is generated by | |

* CompressedTexImage2D if <target> is | |

one of the cube map face targets from table 8.21, and | |

* CompressedTexImage3D if <target> is TEXTURE_CUBE_MAP_ARRAY, | |

and <width> and <height> are not equal. | |

An INVALID_OPERATION error is generated by CompressedTexImage3D if | |

<internalformat> is one of the the formats in table 8.19 and <target> is | |

not TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, or TEXTURE_3D. | |

An INVALID_OPERATION error is generated by CompressedTexImage3D if | |

<target> is TEXTURE_CUBE_MAP_ARRAY and the "Cube Map Array" | |

column of table 8.19 is *not* checked, or if <target> is | |

TEXTURE_3D and the "3D Tex." column of table 8.19 is *not* checked" | |

Modify the fifth and sixth paragraphs on p. 170: | |

"Since these specific compressed formats are easily edited along texel | |

block boundaries, the limitations on subimage location and size are | |

relaxed for CompressedTexSubImage2D and CompressedTexSubImage3D. | |

The block width and height varies for different formats, as described in | |

table 8.19. The contents of any block of texels of a compressed texture | |

image in these specific compressed formats that does not intersect the | |

area being modified are preserved during CompressedTexSubImage* calls." | |

Modify the second error in the Errors section for | |

CompressedTexSubImage[23]D on p. 170, and add a new error: | |

"An INVALID_OPERATION error is generated by CompressedTexSubImage3D if | |

<format> is one of the formats in table 8.19 and <target> is not | |

TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, or TEXTURE_3D. | |

An INVALID_OPERATION error is generated by CompressedTexSubImage3D if | |

<target> is TEXTURE_CUBE_MAP_ARRAY and the "Cube Map Array" column of | |

table 8.19 is *not* checked, or if <target> is TEXTURE_3D and the "3D | |

Tex." column of table 8.19 is *not* checked" | |

Modify the final error in the same section, on p. 171: | |

"An INVALID_OPERATION error is generated if format is one of the formats | |

in table 8.19 and any of the following conditions occurs. The block | |

width and height refer to the values in the corresponding column of the | |

table. | |

* <width> is not a multiple of the format's block width, and <width> + | |

<xoffset> is not equal to the value of TEXTURE_WIDTH. | |

* height is not a multiple of the format's block height, and <height> | |

+ <yoffset> is not equal to the value of TEXTURE_HEIGHT. | |

* <xoffset> or <yoffset> is not a multiple of the block width or | |

height, respectively." | |

Modify table 8.24 (sRGB texture internal formats) to add all of the | |

COMPRESSED_SRGB8_ALPHA8_ASTC_*_KHR formats defined above. | |

Additions to Appendix C of the OpenGL ES 3.1 Specification (Compressed | |

Texture Image Formats) | |

Add a new sub-section on ASTC image formats, as follows: | |

"C.2 ASTC Compressed Texture Image Formats | |

========================================= | |

C.2.1 What is ASTC? | |

--------------------- | |

ASTC stands for Adaptive Scalable Texture Compression. | |

The ASTC formats form a family of related compressed texture image | |

formats. They are all derived from a common set of definitions. | |

ASTC textures may be encoded using either high or low dynamic range, | |

corresponding to the "HDR profile" and "LDR profile". Support for the | |

HDR profile is indicated by the "GL_KHR_texture_compression_astc_hdr" | |

extension string, and support for the LDR profile is indicated by the | |

"GL_KHR_texture_compression_astc_ldr" extension string. | |

The LDR profile supports two-dimensional images for texture targets | |

TEXTURE_2D. TEXTURE_2D_ARRAY, the six texture cube map face targets, and | |

TEXTURE_CUBE_MAP_ARRAY. These images may optionally be specified using | |

the sRGB color space for the RGB channels. | |

The HDR profile is a superset of the LDR profile, and also supports | |

texture target TEXTURE_3D for images made up of multiple two-dimensional | |

slices of compressed data. HDR images may be a mix of low and high | |

dynamic range data. If the HDR profile is supported, the LDR profile and | |

its extension string must also be supported. | |

ASTC textures may be encoded as 1, 2, 3 or 4 components, but they are | |

all decoded into RGBA. | |

Different ASTC formats have different block sizes, specified as part of | |

the name of the format token passed to CompressedImage2D and its related | |

functions, and in table 8.19. | |

Additional ASTC formats (the "Full profile") exist which support 3D data | |

specified as compressed 3D blocks. However, such formats are not defined | |

by either the LDR or HDR profiles, and are not described in this | |

specification. | |

C.2.2 Design Goals | |

-------------------- | |

The design goals for the format are as follows: | |

* Random access. This is a must for any texture compression format. | |

* Bit exact decode. This is a must for conformance testing and | |

reproducibility. | |

* Suitable for mobile use. The format should be suitable for both | |

desktop and mobile GPU environments. It should be low bandwidth | |

and low in area. | |

* Flexible choice of bit rate. Current formats only offer a few bit | |

rates, leaving content developers with only coarse control over | |

the size/quality tradeoff. | |

* Scalable and long-lived. The format should support existing R, RG, | |

RGB and RGBA image types, and also have high "headroom", allowing | |

continuing use for several years and the ability to innovate in | |

encoders. Part of this is the choice to include HDR and 3D. | |

* Feature orthogonality. The choices for the various features of the | |

format are all orthogonal to each other. This has three effects: | |

first, it allows a large, flexible configuration space; second, | |

it makes that space easier to understand; and third, it makes | |

verification easier. | |

* Best in class at given bit rate. It should beat or match the current | |

best in class for peak signal-to-noise ratio (PSNR) at all bit rates. | |

* Fast decode. Texel throughput for a cached texture should be one | |

texel decode per clock cycle per decoder. Parallel decoding of several | |

texels from the same block should be possible at incremental cost. | |

* Low bandwidth. The encoding scheme should ensure that memory access | |

is kept to a minimum, cache reuse is high and memory bandwidth for | |

the format is low. | |

* Low area. It must occupy comparable die size to competing formats. | |

C.2.3 Basic Concepts | |

---------------------- | |

ASTC is a block-based lossy compression format. The compressed image | |

is divided into a number of blocks of uniform size, which makes it | |

possible to quickly determine which block a given texel resides in. | |

Each block has a fixed memory footprint of 128 bits, but these bits | |

can represent varying numbers of texels (the block "footprint"). | |

Block footprint sizes are not confined to powers-of-two, and are | |

also not confined to be square. They may be 2D, in which case the | |

block dimensions range from 4 to 12 texels, or 3D, in which case | |

the block dimensions range from 3 to 6 texels. | |

Decoding one texel requires only the data from a single block. This | |

simplifies cache design, reduces bandwidth and improves encoder throughput. | |

C.2.4 Block Encoding | |

---------------------- | |

To understand how the blocks are stored and decoded, it is useful to start | |

with a simple example, and then introduce additional features. | |

The simplest block encoding starts by defining two color "endpoints". The | |

endpoints define two colors, and a number of additional colors are generated | |

by interpolating between them. We can define these colors using 1, 2, 3, | |

or 4 components (usually corresponding to R, RG, RGB and RGBA textures), | |

and using low or high dynamic range. | |

We then store a color interpolant weight for each texel in the image, which | |

specifies how to calculate the color to use. From this, a weighted average | |

of the two endpoint colors is used to generate the intermediate color, | |

which is the returned color for this texel. | |

There are several different ways of specifying the endpoint colors, and the | |

weights, but once they have been defined, calculation of the texel colors | |

proceeds identically for all of them. Each block is free to choose whichever | |

encoding scheme best represents its color endpoints, within the constraint | |

that all the data fits within the 128 bit block. | |

For blocks which have a large number of texels (e.g. a 12x12 block), there is | |

not enough space to explicitly store a weight for every texel. In this case, | |

a sparser grid with fewer weights is stored, and interpolation is used to | |

determine the effective weight to be used for each texel position. This allows | |

very low bit rates to be used with acceptable quality. This can also be used | |

to more efficiently encode blocks with low detail, or with strong vertical | |

or horizontal features. | |

For blocks which have a mixture of disparate colors, a single line in the | |

color space is not a good fit to the colors of the pixels in the original | |

image. It is therefore possible to partition the texels into multiple sets, | |

the pixels within each set having similar colors. For each of these | |

"partitions", we specify separate endpoint pairs, and choose which pair of | |

endpoints to use for a particular texel by looking up the partition index | |

from a partitioning pattern table. In ASTC, this partition table is actually | |

implemented as a function. | |

The endpoint encoding for each partition is independent. | |

For blocks which have uncorrelated channels - for example an image with a | |

transparency mask, or an image used as a normal map - it may be necessary | |

to specify two weights for each texel. Interpolation between the components | |

of the endpoint colors can then proceed independently for each "plane" of | |

the image. The assignment of channels to planes is selectable. | |

Since each of the above options is independent, it is possible to specify any | |

combination of channels, endpoint color encoding, weight encoding, | |

interpolation, multiple partitions and single or dual planes. | |

Since these values are specified per block, it is important that they are | |

represented with the minimum possible number of bits. As a result, these | |

values are packed together in ways which can be difficult to read, but | |

which are nevertheless highly amenable to hardware decode. | |

All of the values used as weights and color endpoint values can be specified | |

with a variable number of bits. The encoding scheme used allows a fine- | |

grained tradeoff between weight bits and color endpoint bits using "integer | |

sequence encoding". This can pack adjacent values together, allowing us to | |

use fractional numbers of bits per value. | |

Finally, a block may be just a single color. This is a so-called "void | |

extent block" and has a special coding which also allows it to identify | |

nearby regions of single color. This may be used to short-circuit fetching of | |

what would be identical blocks, and further reduce memory bandwidth. | |

C.2.5 LDR and HDR Modes | |

------------------------- | |

The decoding process for LDR content can be simplified if it is known in | |

advance that sRGB output is required. This selection is therefore included | |

as part of the global configuration. | |

The two modes differ in various ways. | |

----------------------------------------------------------------------------- | |

Operation LDR Mode HDR Mode | |

----------------------------------------------------------------------------- | |

Returned value Vector of FP16 values, Vector of FP16 values | |

or Vector of UNORM8 values. | |

sRGB compatible Yes No | |

LDR endpoint 16 bits, or 16 bits | |

decoding precision 8 bits for sRGB | |

HDR endpoint mode Error color As decoded | |

results | |

Error results Error color Vector of NaNs (0xFFFF) | |

----------------------------------------------------------------------------- | |

Table C.2.1 - Differences Between LDR and HDR Modes | |

The error color is opaque fully-saturated magenta | |

(R,G,B,A = 0xFF, 0x00, 0xFF, 0xFF). This has been chosen as it is much more | |

noticeable than black or white, and occurs far less often in valid images. | |

For linear RGB decode, the error color may be either opaque fully-saturated | |

magenta (R,G,B,A = 1.0, 0.0, 1.0, 1.0) or a vector of four NaNs | |

(R,G,B,A = NaN, NaN, NaN, NaN). In the latter case, the recommended NaN | |

value returned is 0xFFFF. | |

The error color is returned as an informative response to invalid | |

conditions, including invalid block encodings or use of reserved endpoint | |

modes. | |

Future, forward-compatible extensions to KHR_texture_compression_astc | |

may define valid interpretations of these conditions, which will decode to | |

some other color. Therefore, encoders and applications must not rely on | |

invalid encodings as a way of generating the error color. | |

C.2.6 Configuration Summary | |

----------------------------- | |

The global configuration data for the format is as follows: | |

* Block dimension (always 2D for both LDR and HDR profiles) | |

* Block footprint size | |

* sRGB output enabled or not | |

The data specified per block is as follows: | |

* Texel weight grid size | |

* Texel weight range | |

* Texel weight values | |

* Number of partitions | |

* Partition pattern index | |

* Color endpoint modes (includes LDR or HDR selection) | |

* Color endpoint data | |

* Number of planes | |

* Plane-to-channel assignment | |

C.2.7 Decode Procedure | |

------------------------ | |

To decode one texel: | |

Find block containing texel | |

Read block mode | |

If void-extent block, store void extent and immediately return single | |

color (optimization) | |

For each plane in image | |

If block mode requires infill | |

Find and decode stored weights adjacent to texel, unquantize and | |

interpolate | |

Else | |

Find and decode weight for texel, and unquantize | |

Read number of partitions | |

If number of partitions > 1 | |

Read partition table pattern index | |

Look up partition number from pattern | |

Read color endpoint mode and endpoint data for selected partition | |

Unquantize color endpoints | |

Interpolate color endpoints using weight (or weights in dual-plane mode) | |

Return interpolated color | |

C.2.8 Block Determination and Bit Rates | |

The block footprint is a global setting for any given texture, and is | |

therefore not encoded in the individual blocks. | |

For 2D textures, the block footprint's width and height are selectable | |

from a number of predefined sizes, namely 4, 5, 6, 8, 10 and 12 pixels. | |

For square and nearly-square blocks, this gives the following bit rates: | |

------------------------------------- | |

Footprint | |

Width Height Bit Rate Increment | |

------------------------------------- | |

4 4 8.00 125% | |

5 4 6.40 125% | |

5 5 5.12 120% | |

6 5 4.27 120% | |

6 6 3.56 114% | |

8 5 3.20 120% | |

8 6 2.67 105% | |

10 5 2.56 120% | |

10 6 2.13 107% | |

8 8 2.00 125% | |

10 8 1.60 125% | |

10 10 1.28 120% | |

12 10 1.07 120% | |

12 12 0.89 | |

------------------------------------- | |

Table C.2.2 - 2D Footprint and Bit Rates | |

The block footprint is shown as <width>x<height> in the format name. For | |

example, the format COMPRESSED_RGBA_ASTC_8x6_KHR specifies an image with | |

a block width of 8 texels, and a block height of 6 texels. | |

The "Increment" column indicates the ratio of bit rate against the next | |

lower available rate. A consistent value in this column indicates an even | |

spread of bit rates. | |

The HDR profile supports only those block footprints listed in Table | |

C.2.2. Other block sizes are not supported. | |

For images which are not an integer multiple of the block size, additional | |

texels are added to the edges with maximum X and Y. These texels may be | |

any color, as they will not be accessed. | |

Although these are not all powers of two, it is possible to calculate block | |

addresses and pixel addresses within the block, for legal image sizes, | |

without undue complexity. | |

Given a 2D image which is W x H pixels in size, with block size | |

w x h, the size of the image in blocks is: | |

Bw = ceiling(W/w) | |

Bh = ceiling(H/h) | |

For a 3D image, each 2D slice is a single texel thick, so that for an | |

image which is W x H x D pixels in size, with block size w x h, the size | |

of the image in blocks is: | |

Bw = ceiling(W/w) | |

Bh = ceiling(H/h) | |

Bd = D | |

C.2.9 Block Layout | |

-------------------- | |

Each block in the image is stored as a single 128-bit block in memory. These | |

blocks are laid out in raster order, starting with the block at (0,0,0), then | |

ordered sequentially by X, Y and finally Z (if present). They are aligned to | |

128-bit boundaries in memory. | |

The bits in the block are labeled in little-endian order - the byte at the | |

lowest address contains bits 0..7. Bit 0 is the least significant bit in the | |

byte. | |

Each block has the same basic layout, as shown in figure C.1. | |

127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 | |

-------------------------------------------------------------- | |

| Texel Weight Data (variable width) Fill direction -> | |

-------------------------------------------------------------- | |

111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 | |

-------------------------------------------------------------- | |

Texel Weight Data | |

-------------------------------------------------------------- | |

95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 | |

-------------------------------------------------------------- | |

Texel Weight Data | |

-------------------------------------------------------------- | |

79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 | |

-------------------------------------------------------------- | |

Texel Weight Data | |

-------------------------------------------------------------- | |

63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 | |

-------------------------------------------------------------- | |

: More config data : | |

-------------------------------------------------------------- | |

47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 | |

-------------------------------------------------------------- | |

<-Fill direction Color Endpoint Data | |

-------------------------------------------------------------- | |

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 | |

-------------------------------------------------------------- | |

: Extra configuration data | |

-------------------------------------------------------------- | |

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |

-------------------------------------------------------------- | |

Extra | Part | Block mode | | |

-------------------------------------------------------------- | |

Figure C.1 - Block Layout Overview | |

Dotted partition lines indicate that the split position is not fixed. | |

The "Block mode" field specifies how the Texel Weight Data is encoded. | |

The "Part" field specifies the number of partitions, minus one. If dual | |

plane mode is enabled, the number of partitions must be 3 or fewer. | |

If 4 partitions are specified, the error value is returned for all | |

texels in the block. | |

The size and layout of the extra configuration data depends on the | |

number of partitions, and the number of planes in the image, as shown in | |

figures C.2 and C.3 (only the bottom 32 bits are shown): | |

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 | |

-------------------------------------------------------------- | |

<- Color endpoint data |CEM | |

-------------------------------------------------------------- | |

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |

-------------------------------------------------------------- | |

CEM | 0 0 | Block Mode | | |

-------------------------------------------------------------- | |

Figure C.2 - Single-partition Block Layout | |

CEM is the color endpoint mode field, which determines how the Color | |

Endpoint Data is encoded. | |

If dual-plane mode is active, the color component selector bits appear | |

directly below the weight bits. | |

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 | |

-------------------------------------------------------------- | |

| CEM | Partition Index | |

-------------------------------------------------------------- | |

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |

-------------------------------------------------------------- | |

Partition Index | Block Mode | | |

-------------------------------------------------------------- | |

Figure C.3 - Multi-partition Block Layout | |

The Partition Index field specifies which partition layout to use. CEM is | |

the first 6 bits of color endpoint mode information for the various | |

partitions. For modes which require more than 6 bits of CEM data, the | |

additional bits appear at a variable position directly beneath the texel | |

weight data. | |

If dual-plane mode is active, the color component selector bits then appear | |

directly below the additional CEM bits. | |

The final special case is that if bits [8:0] of the block are "111111100", | |

then the block is a void-extent block, which has a separate encoding | |

described in section C.2.22. | |

C.2.10 Block Mode | |

------------------ | |

The Block Mode field specifies the width, height and depth of the grid of | |

weights, what range of values they use, and whether dual weight planes are | |

present. Since some these are not represented using powers of two (there | |

are 12 possible weight widths, for example), and not all combinations are | |

allowed, this is not a simple bit packing. However, it can be unpacked | |

quickly in hardware. | |

The weight ranges are encoded using a 3 bit value R, which is interpreted | |

together with a precision bit H, as follows: | |

Low Precision Range (H=0) High Precision Range (H=1) | |

R Weight Range Trits Quints Bits Weight Range Trits Quints Bits | |

------------------------------------------------------------------------- | |

000 Invalid Invalid | |

001 Invalid Invalid | |

010 0..1 1 0..9 1 1 | |

011 0..2 1 0..11 1 2 | |

100 0..3 2 0..15 4 | |

101 0..4 1 0..19 1 2 | |

110 0..5 1 1 0..23 1 3 | |

111 0..7 3 0..31 5 | |

------------------------------------------------------------------------- | |

Table C.2.7 - Weight Range Encodings | |

Each weight value is encoded using the specified number of Trits, Quints | |

and Bits. The details of this encoding can be found in Section C.3.12 - | |

Integer Sequence Encoding. | |

For 2D blocks, the Block Mode field is laid out as follows: | |

------------------------------------------------------------------------- | |

10 9 8 7 6 5 4 3 2 1 0 Width Height Notes | |

------------------------------------------------------------------------- | |

D H B A R0 0 0 R2 R1 B+4 A+2 | |

D H B A R0 0 1 R2 R1 B+8 A+2 | |

D H B A R0 1 0 R2 R1 A+2 B+8 | |

D H 0 B A R0 1 1 R2 R1 A+2 B+6 | |

D H 1 B A R0 1 1 R2 R1 B+2 A+2 | |

D H 0 0 A R0 R2 R1 0 0 12 A+2 | |

D H 0 1 A R0 R2 R1 0 0 A+2 12 | |

D H 1 1 0 0 R0 R2 R1 0 0 6 10 | |

D H 1 1 0 1 R0 R2 R1 0 0 10 6 | |

B 1 0 A R0 R2 R1 0 0 A+6 B+6 D=0, H=0 | |

x x 1 1 1 1 1 1 1 0 0 - - Void-extent | |

x x 1 1 1 x x x x 0 0 - - Reserved* | |

x x x x x x x 0 0 0 0 - - Reserved | |

------------------------------------------------------------------------- | |

Table C.2.8 - 2D Block Mode Layout | |

Note that, due to the encoding of the R field, as described in the | |

previous page, bits R2 and R1 cannot both be zero, which disambiguates | |

the first five rows from the rest of the table. | |

Bit positions with a value of x are ignored for purposes of determining | |

if a block is a void-extent block or reserved, but may have defined | |

encodings for specific void-extent blocks. | |

The penultimate row of the table is reserved only if bits [5:2] are not | |

all 1, in which case it encodes a void-extent block (as shown in the | |

previous row). | |

The D bit is set to indicate dual-plane mode. In this mode, the maximum | |

allowed number of partitions is 3. | |

The penultimate row of the table is reserved only if bits [4:2] are not | |

all 1, in which case it encodes a void-extent block (as shown in the | |

previous row). | |

The size of the grid in each dimension must be less than or equal to | |

the corresponding dimension of the block footprint. If the grid size | |

is greater than the footprint dimension in any axis, then this is an | |

illegal block encoding and all texels will decode to the error color. | |

C.2.11 Color Endpoint Mode | |

--------------------------- | |

In single-partition mode, the Color Endpoint Mode (CEM) field stores one | |

of 16 possible values. Each of these specifies how many raw data values | |

are encoded, and how to convert these raw values into two RGBA color | |

endpoints. They can be summarized as follows: | |

--------------------------------------------- | |

CEM Description Class | |

--------------------------------------------- | |

0 LDR Luminance, direct 0 | |

1 LDR Luminance, base+offset 0 | |

2 HDR Luminance, large range 0 | |

3 HDR Luminance, small range 0 | |

4 LDR Luminance+Alpha, direct 1 | |

5 LDR Luminance+Alpha, base+offset 1 | |

6 LDR RGB, base+scale 1 | |

7 HDR RGB, base+scale 1 | |

8 LDR RGB, direct 2 | |

9 LDR RGB, base+offset 2 | |

10 LDR RGB, base+scale plus two A 2 | |

11 HDR RGB, direct 2 | |

12 LDR RGBA, direct 3 | |

13 LDR RGBA, base+offset 3 | |

14 HDR RGB, direct + LDR Alpha 3 | |

15 HDR RGB, direct + HDR Alpha 3 | |

--------------------------------------------- | |

Table C.2.10 - Color Endpoint Modes. | |

[[ If the HDR profile is not implemented, remove from table C.2.10 | |

all rows whose description starts with "HDR", and add to the | |

caption: ]] | |

Modes not described in the CEM column are reserved for HDR modes, and | |

will generate errors in an unextended OpenGL ES implementation. | |

In multi-partition mode, the CEM field is of variable width, from 6 to 14 | |

bits. The lowest 2 bits of the CEM field specify how the endpoint mode | |

for each partition is calculated: | |

---------------------------------------------------- | |

Value Meaning | |

---------------------------------------------------- | |

00 All color endpoint pairs are of the same type. | |

A full 4-bit CEM is stored in block bits [28:25] | |

and is used for all partitions. | |

01 All endpoint pairs are of class 0 or 1. | |

10 All endpoint pairs are of class 1 or 2. | |

11 All endpoint pairs are of class 2 or 3. | |

---------------------------------------------------- | |

Table C.2.11 - Multi-Partition Color Endpoint Modes | |

If the CEM selector value in bits [24:23] is not 00, | |

then data layout is as follows: | |

--------------------------------------------------- | |

Part n m l k j i h g | |

------------------------------------------ | |

2 ... Weight : M1 : ... | |

------------------------------------------ | |

3 ... Weight : M2 : M1 :M0 : ... | |

------------------------------------------ | |

4 ... Weight : M3 : M2 : M1 : M0 : ... | |

------------------------------------------ | |

Part 28 27 26 25 24 23 | |

---------------------- | |

2 | M0 |C1 |C0 | CEM | | |

---------------------- | |

3 |M0 |C2 |C1 |C0 | CEM | | |

---------------------- | |

4 |C3 |C2 |C1 |C0 | CEM | | |

---------------------- | |

--------------------------------------------------- | |

Figure C.4 - Multi-Partition Color Endpoint Modes | |

In this view, each partition i has two fields. C<i> is the class | |

selector bit, choosing between the two possible CEM classes (0 indicates | |

the lower of the two classes), and M<i> is a two-bit field specifying | |

the low bits of the color endpoint mode within that class. The | |

additional bits appear at a variable bit position, immediately below the | |

texel weight data. | |

The ranges used for the data values are not explicitly specified. | |

Instead, they are derived from the number of available bits remaining | |

after the configuration data and weight data have been specified. | |

Details of the decoding procedure for Color Endpoints can be found in | |

section C.2.13. | |

C.2.12 Integer Sequence Encoding | |

--------------------------------- | |

Both the weight data and the endpoint color data are variable width, and | |

are specified using a sequence of integer values. The range of each | |

value in a sequence (e.g. a color weight) is constrained. | |

Since it is often the case that the most efficient range for these | |

values is not a power of two, each value sequence is encoded using a | |

technique known as "integer sequence encoding". This allows efficient, | |

hardware-friendly packing and unpacking of values with non-power-of-two | |

ranges. | |

In a sequence, each value has an identical range. The range is specified | |

in one of the following forms: | |

Value range MSB encoding LSB encoding Value Block Packed | |

block size | |

----------- ------------ ------------ ----------- ----- ---------- | |

0 .. 2^n-1 - n bit value m 1 n | |

m (n <= 8) | |

0 .. (3 * 2^n)-1 Base-3 "trit" n bit value t * 2^n + m 5 8 + 5*n | |

value t m (n <= 6) | |

0 .. (5 * 2^n)-1 Base-5 "quint" n bit value q * 2^n + m 3 7 + 3*n | |

value q m (n <= 5) | |

------------------------------------------- | |

Table C.2.13 -Encoding for Different Ranges | |

Since 3^5 is 243, it is possible to pack five trits into 8 bits(which has | |

256 possible values), so a trit can effectively be encoded as 1.6 bits. | |

Similarly, since 5^3 is 125, it is possible to pack three quints into | |

7 bits (which has 128 possible values), so a quint can be encoded as | |

2.33 bits. | |

The encoding scheme packs the trits or quints, and then interleaves the n | |

additional bits in positions that satisfy the requirements of an | |

arbitrary length stream. This makes it possible to correctly specify | |

lists of values whose length is not an integer multiple of 3 or 5 values. | |

It also makes it possible to easily select a value at random within the stream. | |

If there are insufficient bits in the stream to fill the final block, then | |

unused (higher order) bits are assumed to be 0 when decoding. | |

To decode the bits for value number i in a sequence of bits b, both | |

indexed from 0, perform the following: | |

If the range is encoded as n bits per value, then the value is bits | |

b[i*n+n-1:i*n] - a simple multiplexing operation. | |

If the range is encoded using a trit, then each block contains 5 values | |

(v0 to v4), each of which contains a trit (t0 to t4) and a corresponding | |

LSB value (m0 to m4). The first bit of the packed block is bit | |

floor(i/5)*(8+5*n). The bits in the block are packed as follows | |

(in this example, n is 4): | |

27 26 25 24 23 22 21 20 19 18 17 16 | |

----------------------------------------------- | |

|T7 | m4 |T6 T5 | m3 |T4 | | |

----------------------------------------------- | |

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |

-------------------------------------------------------------- | |

| m2 |T3 T2 | m1 |T1 T0 | m0 | | |

-------------------------------------------------------------- | |

Figure C.5 - Trit-based Packing | |

The five trits t0 to t4 are obtained by bit manipulations of the 8 bits | |

T[7:0] as follows: | |

if T[4:2] = 111 | |

C = { T[7:5], T[1:0] }; t4 = t3 = 2 | |

else | |

C = T[4:0] | |

if T[6:5] = 11 | |

t4 = 2; t3 = T[7] | |

else | |

t4 = T[7]; t3 = T[6:5] | |

if C[1:0] = 11 | |

t2 = 2; t1 = C[4]; t0 = { C[3], C[2]&~C[3] } | |

else if C[3:2] = 11 | |

t2 = 2; t1 = 2; t0 = C[1:0] | |

else | |

t2 = C[4]; t1 = C[3:2]; t0 = { C[1], C[0]&~C[1] } | |

If the range is encoded using a quint, then each block contains 3 values | |

(v0 to v2), each of which contains a quint (q0 to q2) and a corresponding | |

LSB value (m0 to m2). The first bit of the packed block is bit | |

floor(i/3)*(7+3*n). | |

The bits in the block are packed as follows (in this example, n is 4): | |

18 17 16 | |

----------- | |

|Q6 Q5 | m2 | |

----------- | |

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |

--------------------------------------------------------------- | |

m2 |Q4 Q3 | m1 |Q2 Q1 Q0 | m0 | | |

--------------------------------------------------------------- | |

Figure C.6 - Quint-based Packing | |

The three quints q0 to q2 are obtained by bit manipulations of the 7 bits | |

Q[6:0] as follows: | |

if Q[2:1] = 11 and Q[6:5] = 00 | |

q2 = { Q[0], Q[4]&~Q[0], Q[3]&~Q[0] }; q1 = q0 = 4 | |

else | |

if Q[2:1] = 11 | |

q2 = 4; C = { Q[4:3], ~Q[6:5], Q[0] } | |

else | |

q2 = Q[6:5]; C = Q[4:0] | |

if C[2:0] = 101 | |

q1 = 4; q0 = C[4:3] | |

else | |

q1 = C[4:3]; q0 = C[2:0] | |

Both these procedures ensure a valid decoding for all 128 possible values | |

(even though a few are duplicates). They can also be implemented | |

efficiently in software using small tables. | |

Encoding methods are not specified here, although table-based mechanisms | |

work well. | |

C.2.13 Endpoint Unquantization | |

------------------------------- | |

Each color endpoint is specified as a sequence of integers in a given | |

range. These values are packed using integer sequence encoding, as a | |

stream of bits stored from just above the configuration data, and | |

growing upwards. | |

Once unpacked, the values must be unquantized from their storage range, | |

returning them to a standard range of 0..255. | |

For bit-only representations, this is simple bit replication from the | |

most significant bit of the value. | |

For trit or quint-based representations, this involves a set of bit | |

manipulations and adjustments to avoid the expense of full-width | |

multipliers. This procedure ensures correct scaling, but scrambles | |

the order of the decoded values relative to the encoded values. | |

This must be compensated for using a table in the encoder. | |

The initial inputs to the procedure are denoted A (9 bits), B (9 bits), | |

C (9 bits) and D (3 bits) and are decoded using the range as follows: | |

--------------------------------------------------------------- | |

Range T Q B Bits A B C D | |

--------------------------------------------------------------- | |

0..5 1 1 a aaaaaaaaa 000000000 204 Trit value | |

0..9 1 1 a aaaaaaaaa 000000000 113 Quint value | |

0..11 1 2 ba aaaaaaaaa b000b0bb0 93 Trit value | |

0..19 1 2 ba aaaaaaaaa b0000bb00 54 Quint value | |

0..23 1 3 cba aaaaaaaaa cb000cbcb 44 Trit value | |

0..39 1 3 cba aaaaaaaaa cb0000cbc 26 Quint value | |

0..47 1 4 dcba aaaaaaaaa dcb000dcb 22 Trit value | |

0..79 1 4 dcba aaaaaaaaa dcb0000dc 13 Quint value | |

0..95 1 5 edcba aaaaaaaaa edcb000ed 11 Trit value | |

0..159 1 5 edcba aaaaaaaaa edcb0000e 6 Quint value | |

0..191 1 6 fedcba aaaaaaaaa fedcb000f 5 Trit value | |

--------------------------------------------------------------- | |

Table C.2.16 - Color Unquantization Parameters | |

These are then processed as follows: | |

T = D * C + B; | |

T = T ^ A; | |

T = (A & 0x80) | (T >> 2); | |

Note that the multiply in the first line is nearly trivial as it only | |

needs to multiply by 0, 1, 2, 3 or 4. | |

C.2.14 LDR Endpoint Decoding | |

----------------------------- | |

The decoding method used depends on the Color Endpoint Mode (CEM) field, | |

which specifies how many values are used to represent the endpoint. | |

The CEM field also specifies how to take the n unquantized color endpoint | |

values v0 to v[n-1] and convert them into two RGBA color endpoints e0 | |

and e1. | |

The HDR Modes are more complex and do not fit neatly into this section. | |

They are documented in following section. | |

The methods can be summarized as follows. | |

------------------------------------------------- | |

CEM Range Description n | |

------------------------------------------------- | |

0 LDR Luminance, direct 2 | |

1 LDR Luminance, base+offset 2 | |

2 HDR Luminance, large range 2 | |

3 HDR Luminance, small range 2 | |

4 LDR Luminance+Alpha, direct 4 | |

5 LDR Luminance+Alpha, base+offset 4 | |

6 LDR RGB, base+scale 4 | |

7 HDR RGB, base+scale 4 | |

8 LDR RGB, direct 6 | |

9 LDR RGB, base+offset 6 | |

10 LDR RGB, base+scale plus two A 6 | |

11 HDR RGB 6 | |

12 LDR RGBA, direct 8 | |

13 LDR RGBA, base+offset 8 | |

14 HDR RGB + LDR Alpha 8 | |

15 HDR RGB + HDR Alpha 8 | |

------------------------------------------------- | |

Table C.2.17 -Color Endpoint Modes | |

[[ If the HDR profile is not implemented, remove from table C.2.17 | |

all rows whose description starts with "HDR", and add to the | |

caption: ]] | |

Modes not described are reserved, as described in table C.2.10. | |

[[ HDR profile only ]] | |

Mode 14 is special in that the alpha values are interpolated linearly, | |

but the color components are interpolated logarithmically. This is the | |

only endpoint format with mixed-mode operation, and will return the | |

error value if encountered in LDR mode. | |

Decode the different LDR endpoint modes as follows: | |

Mode 0 LDR Luminance, direct | |

e0=(v0,v0,v0,0xFF); e1=(v1,v1,v1,0xFF); | |

Mode 1 LDR Luminance, base+offset | |

L0 = (v0>>2)|(v1&0xC0); L1=L0+(v1&0x3F); | |

if (L1>0xFF) { L1=0xFF; } | |

e0=(L0,L0,L0,0xFF); e1=(L1,L1,L1,0xFF); | |

Mode 4 LDR Luminance+Alpha,direct | |

e0=(v0,v0,v0,v2); | |

e1=(v1,v1,v1,v3); | |

Mode 5 LDR Luminance+Alpha, base+offset | |

bit_transfer_signed(v1,v0); bit_transfer_signed(v3,v2); | |

e0=(v0,v0,v0,v2); e1=(v0+v1,v0+v1,v0+v1,v2+v3); | |

clamp_unorm8(e0); clamp_unorm8(e1); | |

Mode 6 LDR RGB, base+scale | |

e0=(v0*v3>>8,v1*v3>>8,v2*v3>>8, 0xFF); | |

e1=(v0,v1,v2,0xFF); | |

Mode 8 LDR RGB, Direct | |

s0= v0+v2+v4; s1= v1+v3+v5; | |

if (s1>=s0){e0=(v0,v2,v4,0xFF); | |

e1=(v1,v3,v5,0xFF); } | |

else { e0=blue_contract(v1,v3,v5,0xFF); | |

e1=blue_contract(v0,v2,v4,0xFF); } | |

Mode 9 LDR RGB, base+offset | |

bit_transfer_signed(v1,v0); | |

bit_transfer_signed(v3,v2); | |

bit_transfer_signed(v5,v4); | |

if(v1+v3+v5 >= 0) | |

{ e0=(v0,v2,v4,0xFF); e1=(v0+v1,v2+v3,v4+v5,0xFF); } | |

else | |

{ e0=blue_contract(v0+v1,v2+v3,v4+v5,0xFF); | |

e1=blue_contract(v0,v2,v4,0xFF); } | |

clamp_unorm8(e0); clamp_unorm8(e1); | |

Mode 10 LDR RGB, base+scale plus two A | |

e0=(v0*v3>>8,v1*v3>>8,v2*v3>>8, v4); | |

e1=(v0,v1,v2, v5); | |

Mode 12 LDR RGBA, direct | |

s0= v0+v2+v4; s1= v1+v3+v5; | |

if (s1>=s0){e0=(v0,v2,v4,v6); | |

e1=(v1,v3,v5,v7); } | |

else { e0=blue_contract(v1,v3,v5,v7); | |

e1=blue_contract(v0,v2,v4,v6); } | |

Mode 13 LDR RGBA, base+offset | |

bit_transfer_signed(v1,v0); | |

bit_transfer_signed(v3,v2); | |

bit_transfer_signed(v5,v4); | |

bit_transfer_signed(v7,v6); | |

if(v1+v3+v5>=0) { e0=(v0,v2,v4,v6); | |

e1=(v0+v1,v2+v3,v4+v5,v6+v7); } | |

else { e0=blue_contract(v0+v1,v2+v3,v4+v5,v6+v7); | |

e1=blue_contract(v0,v2,v4,v6); } | |

clamp_unorm8(e0); clamp_unorm8(e1); | |

The bit_transfer_signed procedure transfers a bit from one value (a) | |

to another (b). Initially, both a and b are in the range 0..255. | |

After calling this procedure, a's range becomes -32..31, and b remains | |

in the range 0..255. Note that, as is often the case, this is easier to | |

express in hardware than in C: | |

bit_transfer_signed(int& a, int& b) | |

{ | |

b >>= 1; | |

b |= a & 0x80; | |

a >>= 1; | |

a &= 0x3F; | |

if( (a&0x20)!=0 ) a-=0x40; | |

} | |

The blue_contract procedure is used to give additional precision to | |

RGB colors near grey: | |

color blue_contract( int r, int g, int b, int a ) | |

{ | |

color c; | |

c.r = (r+b) >> 1; | |

c.g = (g+b) >> 1; | |

c.b = b; | |

c.a = a; | |

return c; | |

} | |

The clamp_unorm8 procedure is used to clamp a color into the UNORM8 range: | |

void clamp_unorm8(color c) | |

{ | |

if(c.r < 0) {c.r=0;} else if(c.r > 255) {c.r=255;} | |

if(c.g < 0) {c.g=0;} else if(c.g > 255) {c.g=255;} | |

if(c.b < 0) {c.b=0;} else if(c.b > 255) {c.b=255;} | |

if(c.a < 0) {c.a=0;} else if(c.a > 255) {c.a=255;} | |

} | |

[[ If the HDR profile is not implemented, do not include section | |

C.2.15 ]] | |

C.2.15 HDR Endpoint Decoding | |

------------------------- | |

For HDR endpoint modes, color values are represented in a 12-bit | |

pseudo-logarithmic representation. | |

HDR Endpoint Mode 2 | |

Mode 2 represents luminance-only data with a large range. It encodes | |

using two values (v0, v1). The complete decoding procedure is as follows: | |

if(v1 >= v0) | |

{ | |

y0 = (v0 << 4); | |

y1 = (v1 << 4); | |

} | |

else | |

{ | |

y0 = (v1 << 4) + 8; | |

y1 = (v0 << 4) - 8; | |

} | |

// Construct RGBA result (0x780 is 1.0f) | |

e0 = (y0, y0, y0, 0x780); | |

e1 = (y1, y1, y1, 0x780); | |

HDR Endpoint Mode 3 | |

Mode 3 represents luminance-only data with a small range. It packs the | |

bits for a base luminance value, together with an offset, into two values | |

(v0, v1): | |

Value 7 6 5 4 3 2 1 0 | |

----- ------------------------------ | |

v0 |M | L[6:0] | | |

------------------------------ | |

v1 | X[3:0] | d[3:0] | | |

------------------------------ | |

Table C.2.18 - HDR Mode 3 Value Layout | |

The bit field marked as X allocates different bits to L or d depending | |

on the value of the mode bit M. | |

The complete decoding procedure is as follows: | |

// Check mode bit and extract. | |

if((v0&0x80) !=0) | |

{ | |

y0 = ((v1 & 0xE0) << 4) | ((v0 & 0x7F) << 2); | |

d = (v1 & 0x1F) << 2; | |

} | |

else | |

{ | |

y0 = ((v1 & 0xF0) << 4) | ((v0 & 0x7F) << 1); | |

d = (v1 & 0x0F) << 1; | |

} | |

// Add delta and clamp | |

y1 = y0 + d; | |

if(y1 > 0xFFF) { y1 = 0xFFF; } | |

// Construct RGBA result (0x780 is 1.0f) | |

e0 = (y0, y0, y0, 0x780); | |

e1 = (y1, y1, y1, 0x780); | |

HDR Endpoint Mode 7 | |

Mode 7 packs the bits for a base RGB value, a scale factor, and some | |

mode bits into the four values (v0, v1, v2, v3): | |

Value 7 6 5 4 3 2 1 0 | |

----- ------------------------------ | |

v0 |M[3:2] | R[5:0] | | |

----- ------------------------------ | |

v1 |M1 |X0 |X1 | G[4:0] | | |

----- ------------------------------ | |

v2 |M0 |X2 |X3 | B[4:0] | | |

----- ------------------------------ | |

v3 |X4 |X5 |X6 | S[4:0] | | |

----- ------------------------------ | |

Table C.2.19 - HDR Mode 7 Value Layout | |

The mode bits M0 to M3 are a packed representation of an endpoint bit | |

mode, together with the major component index. For modes 0 to 4, the | |

component (red, green, or blue) with the largest magnitude is identified, | |

and the values swizzled to ensure that it is decoded from the red channel. | |

The endpoint bit mode is used to determine the number of bits assigned | |

to each component of the endpoint, and the destination of each of the | |

extra bits X0 to X6, as follows: | |

------------------------------------------------------ | |

Number of bits Destination of extra bits | |

Mode R G B S X0 X1 X2 X3 X4 X5 X6 | |

------------------------------------------------------ | |

0 11 5 5 7 R9 R8 R7 R10 R6 S6 S5 | |

1 11 6 6 5 R8 G5 R7 B5 R6 R10 R9 | |

2 10 5 5 8 R9 R8 R7 R6 S7 S6 S5 | |

3 9 6 6 7 R8 G5 R7 B5 R6 S6 S5 | |

4 8 7 7 6 G6 G5 B6 B5 R6 R7 S5 | |

5 7 7 7 7 G6 G5 B6 B5 R6 S6 S5 | |

------------------------------------------------------ | |

Table C.2.20 - Endpoint Bit Mode | |

As noted before, this appears complex when expressed in C, but much | |

easier to achieve in hardware - bit masking, extraction, shifting | |

and assignment usually ends up as a single wire or multiplexer. | |

The complete decoding procedure is as follows: | |

// Extract mode bits and unpack to major component and mode. | |

int modeval = ((v0&0xC0)>>6) | ((v1&0x80)>>5) | ((v2&0x80)>>4); | |

int majcomp; | |

int mode; | |

if( (modeval & 0xC ) != 0xC ) | |

{ | |

majcomp = modeval >> 2; mode = modeval & 3; | |

} | |

else if( modeval != 0xF ) | |

{ | |

majcomp = modeval & 3; mode = 4; | |

} | |

else | |

{ | |

majcomp = 0; mode = 5; | |

} | |

// Extract low-order bits of r, g, b, and s. | |

int red = v0 & 0x3f; | |

int green = v1 & 0x1f; | |

int blue = v2 & 0x1f; | |

int scale = v3 & 0x1f; | |

// Extract high-order bits, which may be assigned depending on mode | |

int x0 = (v1 >> 6) & 1; int x1 = (v1 >> 5) & 1; | |

int x2 = (v2 >> 6) & 1; int x3 = (v2 >> 5) & 1; | |

int x4 = (v3 >> 7) & 1; int x5 = (v3 >> 6) & 1; | |

int x6 = (v3 >> 5) & 1; | |

// Now move the high-order xs into the right place. | |

int ohm = 1 << mode; | |

if( ohm & 0x30 ) green |= x0 << 6; | |

if( ohm & 0x3A ) green |= x1 << 5; | |

if( ohm & 0x30 ) blue |= x2 << 6; | |

if( ohm & 0x3A ) blue |= x3 << 5; | |

if( ohm & 0x3D ) scale |= x6 << 5; | |

if( ohm & 0x2D ) scale |= x5 << 6; | |

if( ohm & 0x04 ) scale |= x4 << 7; | |

if( ohm & 0x3B ) red |= x4 << 6; | |

if( ohm & 0x04 ) red |= x3 << 6; | |

if( ohm & 0x10 ) red |= x5 << 7; | |

if( ohm & 0x0F ) red |= x2 << 7; | |

if( ohm & 0x05 ) red |= x1 << 8; | |

if( ohm & 0x0A ) red |= x0 << 8; | |

if( ohm & 0x05 ) red |= x0 << 9; | |

if( ohm & 0x02 ) red |= x6 << 9; | |

if( ohm & 0x01 ) red |= x3 << 10; | |

if( ohm & 0x02 ) red |= x5 << 10; | |

// Shift the bits to the top of the 12-bit result. | |

static const int shamts[6] = { 1,1,2,3,4,5 }; | |

int shamt = shamts[mode]; | |

red <<= shamt; green <<= shamt; blue <<= shamt; scale <<= shamt; | |

// Minor components are stored as differences | |

if( mode != 5 ) { green = red - green; blue = red - blue; } | |

// Swizzle major component into place | |

if( majcomp == 1 ) swap( red, green ); | |

if( majcomp == 2 ) swap( red, blue ); | |

// Clamp output values, set alpha to 1.0 | |

e1.r = clamp( red, 0, 0xFFF ); | |

e1.g = clamp( green, 0, 0xFFF ); | |

e1.b = clamp( blue, 0, 0xFFF ); | |

e1.alpha = 0x780; | |

e0.r = clamp( red - scale, 0, 0xFFF ); | |

e0.g = clamp( green - scale, 0, 0xFFF ); | |

e0.b = clamp( blue - scale, 0, 0xFFF ); | |

e0.alpha = 0x780; | |

HDR Endpoint Mode 11 | |

Mode 11 specifies two RGB values, which it calculates from a number of | |

bitfields (a, b0, b1, c, d0 and d1) which are packed together with some | |

mode bits into the six values (v0, v1, v2, v3, v4, v5): | |

Value 7 6 5 4 3 2 1 0 | |

----- ------------------------------ | |

v0 | a[7:0] | | |

----- ------------------------------ | |

v1 |m0 |a8 | c[5:0] | | |

----- ------------------------------ | |

v2 |m1 |X0 | b0[5:0] | | |

----- ------------------------------ | |

v3 |m2 |X1 | b1[5:0] | | |

----- ------------------------------ | |

v4 |mj0|X2 |X4 | d0[4:0] | | |

----- ------------------------------ | |

v5 |mj1|X3 |X5 | d1[4:0] | | |

----- ------------------------------ | |

Table C.2.21 - HDR Mode 11 Value Layout | |

If the major component bits mj[1:0 ] are both 1, then the RGB values | |

are specified directly | |

Value 7 6 5 4 3 2 1 0 | |

----- ------------------------------ | |

v0 | R0[11:4] | | |

----- ------------------------------ | |

v1 | R1[11:4] | | |

----- ------------------------------ | |

v2 | G0[11:4] | | |

----- ------------------------------ | |

v3 | G1[11:4] | | |

----- ------------------------------ | |

v4 | 1 | B0[11:5] | | |

----- ------------------------------ | |

v5 | 1 | B1[11:5] | | |

----- ------------------------------ | |

Table C.2.22 - HDR Mode 11 Value Layout | |

The mode bits m[2:0] specify the bit allocation for the different | |

values, and the destinations of the extra bits X0 to X5: | |

------------------------------------------------------------------------- | |

Number of bits Destination of extra bits | |

Mode a b c d X0 X1 X2 X3 X4 X5 | |

------------------------------------------------------------------------- | |

0 9 7 6 7 b0[6] b1[6] d0[6] d1[6] d0[5] d1[5] | |

1 9 8 6 6 b0[6] b1[6] b0[7] b1[7] d0[5] d1[5] | |

2 10 6 7 7 a[9] c[6] d0[6] d1[6] d0[5] d1[5] | |

3 10 7 7 6 b0[6] b1[6] a[9] c[6] d0[5] d1[5] | |

4 11 8 6 5 b0[6] b1[6] b0[7] b1[7] a[9] a[10] | |

5 11 6 7 6 a[9] a[10] c[7] c[6] d0[5] d1[5] | |

6 12 7 7 5 b0[6] b1[6] a[11] c[6] a[9] a[10] | |

7 12 6 7 6 a[9] a[10] a[11] c[6] d0[5] d1[5] | |

------------------------------------------------------------------------- | |

Table C.2.23 - Endpoint Bit Mode | |

The complete decoding procedure is as follows: | |

// Find major component | |

int majcomp = ((v4 & 0x80) >> 7) | ((v5 & 0x80) >> 6); | |

// Deal with simple case first | |

if( majcomp == 3 ) | |

{ | |

e0 = (v0 << 4, v2 << 4, (v4 & 0x7f) << 5, 0x780); | |

e1 = (v1 << 4, v3 << 4, (v5 & 0x7f) << 5, 0x780); | |

return; | |

} | |

// Decode mode, parameters. | |

int mode = ((v1&0x80)>>7) | ((v2&0x80)>>6) | ((v3&0x80)>>5); | |

int va = v0 | ((v1 & 0x40) << 2); | |

int vb0 = v2 & 0x3f; | |

int vb1 = v3 & 0x3f; | |

int vc = v1 & 0x3f; | |

int vd0 = v4 & 0x7f; | |

int vd1 = v5 & 0x7f; | |

// Assign top bits of vd0, vd1. | |

static const int dbitstab[8] = {7,6,7,6,5,6,5,6}; | |

vd0 = signextend( vd0, dbitstab[mode] ); | |

vd1 = signextend( vd1, dbitstab[mode] ); | |

// Extract and place extra bits | |

int x0 = (v2 >> 6) & 1; | |

int x1 = (v3 >> 6) & 1; | |

int x2 = (v4 >> 6) & 1; | |

int x3 = (v5 >> 6) & 1; | |

int x4 = (v4 >> 5) & 1; | |

int x5 = (v5 >> 5) & 1; | |

int ohm = 1 << mode; | |

if( ohm & 0xA4 ) va |= x0 << 9; | |

if( ohm & 0x08 ) va |= x2 << 9; | |

if( ohm & 0x50 ) va |= x4 << 9; | |

if( ohm & 0x50 ) va |= x5 << 10; | |

if( ohm & 0xA0 ) va |= x1 << 10; | |

if( ohm & 0xC0 ) va |= x2 << 11; | |

if( ohm & 0x04 ) vc |= x1 << 6; | |

if( ohm & 0xE8 ) vc |= x3 << 6; | |

if( ohm & 0x20 ) vc |= x2 << 7; | |

if( ohm & 0x5B ) vb0 |= x0 << 6; | |

if( ohm & 0x5B ) vb1 |= x1 << 6; | |

if( ohm & 0x12 ) vb0 |= x2 << 7; | |

if( ohm & 0x12 ) vb1 |= x3 << 7; | |

// Now shift up so that major component is at top of 12-bit value | |

int shamt = (modeval >> 1) ^ 3; | |

va <<= shamt; vb0 <<= shamt; vb1 <<= shamt; | |

vc <<= shamt; vd0 <<= shamt; vd1 <<= shamt; | |

e1.r = clamp( va, 0, 0xFFF ); | |

e1.g = clamp( va - vb0, 0, 0xFFF ); | |

e1.b = clamp( va - vb1, 0, 0xFFF ); | |

e1.alpha = 0x780; | |

e0.r = clamp( va - vc, 0, 0xFFF ); | |

e0.g = clamp( va - vb0 - vc - vd0, 0, 0xFFF ); | |

e0.b = clamp( va - vb1 - vc - vd1, 0, 0xFFF ); | |

e0.alpha = 0x780; | |

if( majcomp == 1 ) { swap( e0.r, e0.g ); swap( e1.r, e1.g ); } | |

else if( majcomp == 2 ) { swap( e0.r, e0.b ); swap( e1.r, e1.b ); } | |

HDR Endpoint Mode 14 | |

Mode 14 specifies two RGBA values, using the eight values (v0, v1, v2, | |

v3, v4, v5, v6, v7). First, the RGB values are decoded from (v0..v5) | |

using the method from Mode 11, then the alpha values are filled in | |

from v6 and v7: | |

// Decode RGB as for mode 11 | |

(e0,e1) = decode_mode_11(v0,v1,v2,v3,v4,v5) | |

// Now fill in the alphas | |

e0.alpha = v6; | |

e1.alpha = v7; | |

Note that in this mode, the alpha values are interpreted (and | |

interpolated) as 8-bit unsigned normalized values, as in the LDR modes. | |

This is the only mode that exhibits this behaviour. | |

HDR Endpoint Mode 15 | |

Mode 15 specifies two RGBA values, using the eight values (v0, v1, v2, | |

v3, v4, v5, v6, v7). First, the RGB values are decoded from (v0..v5) | |

using the method from Mode 11. The alpha values are stored in values | |

v6 and v7 as a mode and two values which are interpreted according | |

to the mode: | |

Value 7 6 5 4 3 2 1 0 | |

----- ------------------------------ | |

v6 |M0 | A[6:0] | | |

----- ------------------------------ | |

v7 |M1 | B[6:0] | | |

----- ------------------------------ | |

Table C.2.24 - HDR Mode 15 Alpha Value Layout | |

The alpha values are decoded from v6 and v7 as follows: | |

// Decode RGB as for mode 11 | |

(e0,e1) = decode_mode_11(v0,v1,v2,v3,v4,v5) | |

// Extract mode bits | |

mode = ((v6 >> 7) & 1) | ((v7 >> 6) & 2); | |

v6 &= 0x7F; | |

v7 &= 0x7F; | |

if(mode==3) | |

{ | |

// Directly specify alphas | |

e0.alpha = v6 << 5; | |

e1.alpha = v7 << 5; | |

} | |

else | |

{ | |

// Transfer bits from v7 to v6 and sign extend v7. | |

v6 |= (v7 << (mode+1))) & 0x780; | |

v7 &= (0x3F >> mode); | |

v7 ^= 0x20 >> mode; | |

v7 -= 0x20 >> mode; | |

v6 <<= (4-mode); | |

v7 <<= (4-mode); | |

// Add delta and clamp | |

v7 += v6; | |

v7 = clamp(v7, 0, 0xFFF); | |

e0.alpha = v6; | |

e1.alpha = v7; | |

} | |

Note that in this mode, the alpha values are interpreted (and | |

interpolated) as 12-bit HDR values, and are interpolated as | |

for any other HDR component. | |

C.2.16 Weight Decoding | |

----------------------- | |

The weight information is stored as a stream of bits, growing downwards | |

from the most significant bit in the block. Bit n in the stream is thus | |

bit 127-n in the block. | |

For each location in the weight grid, a value (in the specified range) | |

is packed into the stream. These are ordered in a raster pattern | |

starting from location (0,0,0), with the X dimension increasing fastest, | |

and the Z dimension increasing slowest. If dual-plane mode is selected, | |

both weights are emitted together for each location, plane 0 first, | |

then plane 1. | |

C.2.17 Weight Unquantization | |

----------------------------- | |

Each weight plane is specified as a sequence of integers in a given | |

range. These values are packed using integer sequence encoding. | |

Once unpacked, the values must be unquantized from their storage | |

range, returning them to a standard range of 0..64. The procedure | |

for doing so is similar to the color endpoint unquantization. | |

First, we unquantize the actual stored weight values to the range 0..63. | |

For bit-only representations, this is simple bit replication from the | |

most significant bit of the value. | |

For trit or quint-based representations, this involves a set of bit | |

manipulations and adjustments to avoid the expense of full-width | |

multipliers. | |

For representations with no additional bits, the results are as follows: | |

Range 0 1 2 3 4 | |

-------------------------- | |

0..2 0 32 63 - - | |

0..4 0 16 32 47 63 | |

-------------------------- | |

Table C.2.25 - Weight Unquantization Values | |

For other values, we calculate the initial inputs to a bit manipulation | |

procedure. These are denoted A (7 bits), B (7 bits), C (7 bits), and | |

D (3 bits) and are decoded using the range as follows: | |

Range T Q B Bits A B C D | |

------------------------------------------------------- | |

0..5 1 1 a aaaaaaa 0000000 50 Trit value | |

0..9 1 1 a aaaaaaa 0000000 28 Quint value | |

0..11 1 2 ba aaaaaaa b000b0b 23 Trit value | |

0..19 1 2 ba aaaaaaa b0000b0 13 Quint value | |

0..23 1 3 cba aaaaaaa cb000cb 11 Trit value | |

------------------------------------------------------- | |

Table C.2.26 - Weight Unquantization Parameters | |

These are then processed as follows: | |

T = D * C + B; | |

T = T ^ A; | |

T = (A & 0x20) | (T >> 2); | |

Note that the multiply in the first line is nearly trivial as it only | |

needs to multiply by 0, 1, 2, 3 or 4. | |

As a final step, for all types of value, the range is expanded from | |

0..63 up to 0..64 as follows: | |

if (T > 32) { T += 1; } | |

This allows the implementation to use 64 as a divisor during inter- | |

polation, which is much easier than using 63. | |

C.2.18 Weight Infill | |

--------------------- | |

After unquantization, the weights are subject to weight selection and | |

infill. The infill method is used to calculate the weight for a texel | |

position, based on the weights in the stored weight grid array (which | |

may be a different size). | |

The procedure below must be followed exactly, to ensure bit exact | |

results. | |

The block size is specified as two dimensions along the s and t | |

axes (Bs, Bt). Texel coordinates within the block (s,t) can have values | |

from 0 to one less than the block dimension in that axis. | |

For each block dimension, we compute scale factors (Ds, Dt) | |

Ds = floor( (1024 + floor(Bs/2)) / (Bs-1) ); | |

Dt = floor( (1024 + floor(Bt/2)) / (Bt-1) ); | |

Since the block dimensions are constrained, these are easily looked up | |

in a table. These scale factors are then used to scale the (s,t) | |

coordinates to a homogeneous coordinate (cs, ct): | |

cs = Ds * s; | |

ct = Dt * t; | |

This homogeneous coordinate (cs, ct) is then scaled again to give | |

a coordinate (gs, gt) in the weight-grid space . The weight-grid is | |

of size (N, M), as specified in the block mode field: | |

gs = (cs*(N-1)+32) >> 6; | |

gt = (ct*(M-1)+32) >> 6; | |

The resulting coordinates may be in the range 0..176. These are inter- | |

preted as 4:4 unsigned fixed point numbers in the range 0.0 .. 11.0. | |

If we label the integral parts of these (js, jt) and the fractional | |

parts (fs, ft), then: | |

js = gs >> 4; fs = gs & 0x0F; | |

jt = gt >> 4; ft = gt & 0x0F; | |

These values are then used to bilinearly interpolate between the stored | |

weights. | |

v0 = js + jt*N; | |

p00 = decode_weight(v0); | |

p01 = decode_weight(v0 + 1); | |

p10 = decode_weight(v0 + N); | |

p11 = decode_weight(v0 + N + 1); | |

The function decode_weight(n) decodes the nth weight in the stored weight | |

stream. The values p00 to p11 are the weights at the corner of the square | |

in which the texel position resides. These are then weighted using the | |

fractional position to produce the effective weight i as follows: | |

w11 = (fs*ft+8) >> 4; | |

w10 = ft - w11; | |

w01 = fs - w11; | |

w00 = 16 - fs - ft + w11; | |

i = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4; | |

C.2.19 Weight Application | |

-------------------------- | |

Once the effective weight i for the texel has been calculated, the color | |

endpoints are interpolated and expanded. | |

For LDR endpoint modes, each color component C is calculated from the | |

corresponding 8-bit endpoint components C0 and C1 as follows: | |

If sRGB conversion is not enabled, or for the alpha channel in any case, | |

C0 and C1 are first expanded to 16 bits by bit replication: | |

C0 = (C0 << 8) | C0; C1 = (C1 << 8) | C1; | |

If sRGB conversion is enabled, C0 and C1 for the R, G, and B channels | |

are expanded to 16 bits differently, as follows: | |

C0 = (C0 << 8) | 0x80; C1 = (C1 << 8) | 0x80; | |

C0 and C1 are then interpolated to produce a UNORM16 result C: | |

C = floor( (C0*(64-i) + C1*i + 32)/64 ) | |

If sRGB conversion is enabled, the top 8 bits of the interpolation | |

result for the R, G and B channels are passed to the external sRGB | |

conversion block. Otherwise, if C = 65535, then the final result is | |

1.0 (0x3C00) otherwise C is divided by 65536 and the infinite-precision | |

result of the division is converted to FP16 with round-to-zero | |

semantics. | |

For HDR endpoint modes, color values are represented in a 12-bit | |

pseudo-logarithmic representation, and interpolation occurs in a | |

piecewise-approximate logarithmic manner as follows: | |

In LDR mode, the error result is returned. | |

In HDR mode, the color components from each endpoint, C0 and C1, are | |

initially shifted left 4 bits to become 16-bit integer values and these | |

are interpolated in the same way as LDR. The 16-bit value C is then | |

decomposed into the top five bits, E, and the bottom 11 bits M, which | |

are then processed and recombined with E to form the final value Cf: | |

C = floor( (C0*(64-i) + C1*i + 32)/64 ) | |

E = (C&0xF800) >> 11; M = C&0x7FF; | |

if (M < 512) { Mt = 3*M; } | |

else if (M >= 1536) { Mt = 5*M - 2048; } | |

else { Mt = 4*M - 512; } | |

Cf = (E<<10) + (Mt>>3) | |

This interpolation is a considerably closer approximation to a | |

logarithmic space than simple 16-bit interpolation. | |

This final value Cf is interpreted as an IEEE FP16 value. If the result | |

is +Inf or NaN, it is converted to the bit pattern 0x7BFF, which is the | |

largest representable finite value. | |

C.2.20 Dual-Plane Decoding | |

--------------------------- | |

If dual-plane mode is disabled, all of the endpoint components are inter- | |

polated using the same weight value. | |

If dual-plane mode is enabled, two weights are stored with each texel. | |

One component is then selected to use the second weight for interpolation, | |

instead of the first weight. The first weight is then used for all other | |

components. | |

The component to treat specially is indicated using the 2-bit Color | |

Component Selector (CCS) field as follows: | |

Value Weight 0 Weight 1 | |

-------------------------- | |

0 GBA R | |

1 RBA G | |

2 RGA B | |

3 RGB A | |

-------------------------- | |

Table C.2.28 - Dual Plane Color Component Selector Values | |

The CCS bits are stored at a variable position directly below the weight | |

bits and any additional CEM bits. | |

C.2.21 Partition Pattern Generation | |

------------------------------------ | |

When multiple partitions are active, each texel position is assigned a | |

partition index. This partition index is calculated using a seed (the | |

partition pattern index), the texel's x,y,z position within the block, | |

and the number of partitions. An additional argument, small_block, is | |

set to 1 if the number of texels in the block is less than 31, | |

otherwise it is set to 0. | |

This function is specified in terms of x, y and z in order to support | |

3D textures. For 2D textures and texture slices, z will always be 0. | |

The full partition selection algorithm is as follows: | |

int select_partition(int seed, int x, int y, int z, | |

int partitioncount, int small_block) | |

{ | |

if( small_block ){ x <<= 1; y <<= 1; z <<= 1; } | |

seed += (partitioncount-1) * 1024; | |

uint32_t rnum = hash52(seed); | |

uint8_t seed1 = rnum & 0xF; | |

uint8_t seed2 = (rnum >> 4) & 0xF; | |

uint8_t seed3 = (rnum >> 8) & 0xF; | |

uint8_t seed4 = (rnum >> 12) & 0xF; | |

uint8_t seed5 = (rnum >> 16) & 0xF; | |

uint8_t seed6 = (rnum >> 20) & 0xF; | |

uint8_t seed7 = (rnum >> 24) & 0xF; | |

uint8_t seed8 = (rnum >> 28) & 0xF; | |

uint8_t seed9 = (rnum >> 18) & 0xF; | |

uint8_t seed10 = (rnum >> 22) & 0xF; | |

uint8_t seed11 = (rnum >> 26) & 0xF; | |

uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF; | |

seed1 *= seed1; seed2 *= seed2; | |

seed3 *= seed3; seed4 *= seed4; | |

seed5 *= seed5; seed6 *= seed6; | |

seed7 *= seed7; seed8 *= seed8; | |

seed9 *= seed9; seed10 *= seed10; | |

seed11 *= seed11; seed12 *= seed12; | |

int sh1, sh2, sh3; | |

if( seed & 1 ) | |

{ sh1 = (seed&2 ? 4:5); sh2 = (partitioncount==3 ? 6:5); } | |

else | |

{ sh1 = (partitioncount==3 ? 6:5); sh2 = (seed&2 ? 4:5); } | |

sh3 = (seed & 0x10) ? sh1 : sh2; | |

seed1 >>= sh1; seed2 >>= sh2; seed3 >>= sh1; seed4 >>= sh2; | |

seed5 >>= sh1; seed6 >>= sh2; seed7 >>= sh1; seed8 >>= sh2; | |

seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3; | |

int a = seed1*x + seed2*y + seed11*z + (rnum >> 14); | |

int b = seed3*x + seed4*y + seed12*z + (rnum >> 10); | |

int c = seed5*x + seed6*y + seed9 *z + (rnum >> 6); | |

int d = seed7*x + seed8*y + seed10*z + (rnum >> 2); | |

a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F; | |

if( partitioncount < 4 ) d = 0; | |

if( partitioncount < 3 ) c = 0; | |

if( a >= b && a >= c && a >= d ) return 0; | |

else if( b >= c && b >= d ) return 1; | |

else if( c >= d ) return 2; | |

else return 3; | |

} | |

As has been observed before, the bit selections are much easier to | |

express in hardware than in C. | |

The seed is expanded using a hash function hash52, which is defined as | |

follows: | |

uint32_t hash52( uint32_t p ) | |

{ | |

p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4; | |

p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3; | |

p ^= p << 6; p ^= p >> 17; | |

return p; | |

} | |

This assumes that all operations act on 32-bit values | |

C.2.22 Data Size Determination | |

------------------------------- | |

The size of the data used to represent color endpoints is not | |

explicitly specified. Instead, it is determined from the block mode and | |

number of partitions as follows: | |

config_bits = 17; | |

if(num_partitions>1) | |

if(single_CEM) | |

config_bits = 29; | |

else | |

config_bits = 25 + 3*num_partitions; | |

num_weights = M * N * Q; // size of weight grid | |

if(dual_plane) | |

config_bits += 2; | |

num_weights *= 2; | |

weight_bits = ceil(num_weights*8*trits_in_weight_range/5) + | |

ceil(num_weights*7*quints_in_weight_range/3) + | |

num_weights*bits_in_weight_range; | |

remaining_bits = 128 - config_bits - weight_bits; | |

num_CEM_pairs = base_CEM_class+1 + count_bits(extra_CEM_bits); | |

The CEM value range is then looked up from a table indexed by remaining | |

bits and num_CEM_pairs. This table is initialized such that the range | |

is as large as possible, consistent with the constraint that the number | |

of bits required to encode num_CEM_pairs pairs of values is not more | |

than the number of remaining bits. | |

An equivalent iterative algorithm would be: | |

num_CEM_values = num_CEM_pairs*2; | |

for(range = each possible CEM range in descending order of size) | |

{ | |

CEM_bits = ceil(num_CEM_values*8*trits_in_CEM_range/5) + | |

ceil(num_CEM_values*7*quints_in_CEM_range/3) + | |

num_CEM_values*bits_in_CEM_range; | |

if(CEM_bits <= remaining_bits) | |

break; | |

} | |

return range; | |

In cases where this procedure results in unallocated bits, these bits | |

are not read by the decoding process and can have any value. | |

C.2.23 Void-Extent Blocks | |

-------------------------- | |

A void-extent block is a block encoded with a single color. It also | |

specifies some additional information about the extent of the single- | |

color area beyond this block, which can optionally be used by a | |

decoder to reduce or prevent redundant block fetches. | |

The layout of a 2D Void-Extent block is as follows: | |

127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 | |

--------------------------------------------------------------- | |

| Block color A component | | |

--------------------------------------------------------------- | |

111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 | |

---------------------------------------------------------------- | |

| Block color B component | | |

---------------------------------------------------------------- | |

95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 | |

---------------------------------------------------------------- | |

| Block color G component | | |

---------------------------------------------------------------- | |

79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 | |

---------------------------------------------------------------- | |

| Block color R component | | |

---------------------------------------------------------------- | |

63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 | |

---------------------------------------------------------------- | |

| Void-extent maximum T coordinate | Min T | | |

---------------------------------------------------------------- | |

47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 | |

---------------------------------------------------------------- | |

Void-extent minimum T coordinate | Void-extent max S | | |

---------------------------------------------------------------- | |

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 | |

---------------------------------------------------------------- | |

Void-extent max S coord | Void-extent minimum S coordinate | | |

---------------------------------------------------------------- | |

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |

---------------------------------------------------------------- | |

Min S coord | 1 | 1 | D | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | | |

---------------------------------------------------------------- | |

------------------------------------------------- | |

Figure C.7 - 2D Void-Extent Block Layout Overview | |

Bit 9 is the Dynamic Range flag, which indicates the format in which | |

colors are stored. A 0 value indicates LDR, in which case the color | |

components are stored as UNORM16 values. A 1 indicates HDR, in which | |

case the color components are stored as FP16 values. | |

The reason for the storage of UNORM16 values in the LDR case is due | |

to the possibility that the value will need to be passed on to sRGB | |

conversion. By storing the color value in the format which comes out | |

of the interpolator, before the conversion to FP16, we avoid having | |

to have separate versions for sRGB and linear modes. | |

If a void-extent block with HDR values is decoded in LDR mode, then | |

the result will be the error color, opaque magenta, for all texels | |

within the block. | |

In the HDR case, if the color component values are infinity or NaN, this | |

will result in undefined behavior. As usual, this must not lead to GL | |

interruption or termination. | |

Bits 10 and 11 are reserved and must be 1. | |

The minimum and maximum coordinate values are treated as unsigned | |

integers and then normalized into the range 0..1 (by dividing by 2^13-1 | |

or 2^9-1, for 2D and 3D respectively). The maximum values for each | |

dimension must be greater than the corresponding minimum values, | |

unless they are all all-1s. | |

If all the coordinates are all-1s, then the void extent is ignored, | |

and the block is simply a constant-color block. | |

The existence of single-color blocks with void extents must not produce | |

results different from those obtained if these single-color blocks are | |

defined without void-extents. Any situation in which the results would | |

differ is invalid. Results from invalid void extents are undefined. | |

If a void-extent appears in a MIPmap level other than the most detailed | |

one, then the extent will apply to all of the more detailed levels too. | |

This allows decoders to avoid sampling more detailed MIPmaps. | |

If the more detailed MIPmap level is not a constant color in this region, | |

then the block may be marked as constant color, but without a void extent, | |

as detailed above. | |

If a void-extent extends to the edge of a texture, then filtered texture | |

colors may not be the same color as that specified in the block, due to | |

texture border colors, wrapping, or cube face wrapping. | |

Care must be taken when updating or extracting partial image data that | |

void-extents in the image do not become invalid. | |

C.2.24 Illegal Encodings | |

------------------------- | |

In ASTC, there is a variety of ways to encode an illegal block. Decoders | |

are required to recognize all illegal blocks and emit the standard error | |

color value upon encountering an illegal block. | |

Here is a comprehensive list of situations that represent illegal block | |

encodings: | |

* The block mode specified is one of the modes explicitly listed | |

as Reserved. | |

* A 2D void-extent block that has any of the reserved bits not | |

set to 1. | |

* A block mode has been specified that would require more than | |

64 weights total. | |

* A block mode has been specified that would require more than | |

96 bits for integer sequence encoding of the weight grid. | |

* A block mode has been specifed that would require fewer than | |

24 bits for integer sequence encoding of the weight grid. | |

* The size of the weight grid exceeds the size of the block footprint | |

in any dimension. | |

* Color endpoint modes have been specified such that the color | |

integer sequence encoding would require more than 18 integers. | |

* The number of bits available for color endpoint encoding after all | |

the other fields have been counted is less than ceil(13C/5) where C | |

is the number of color endpoint integers (this would restrict color | |

integers to a range smaller than 0..5, which is not supported). | |

* Dual weight mode is enabled for a block with 4 partitions. | |

* Void-Extent blocks where the low coordinate for some texture axis | |

is greater than or equal to the high coordinate. | |

Note also that, in LDR mode, a block which has both HDR and LDR endpoint | |

modes assigned to different partitions is not an error block. Only those | |

texels which belong to the HDR partition will result in the error color. | |

Texels belonging to a LDR partition will be decoded as normal. | |

C.2.25 LDR PROFILE SUPPORT | |

--------------------------- | |

Implementations of the LDR Profile must satisfy the following requirements: | |

* All textures with valid encodings for LDR Profile must decode | |

identically using either a LDR Profile, HDR Profile, or Full Profile | |

decoder. | |

* All features included only in the HDR Profile or Full Profile must be | |

treated as reserved in the LDR Profile, and return the error color on | |

decoding. | |

* Any sequence of API calls valid for the LDR Profile must also be valid | |

for the HDR Profile or Full Profile and return identical results when | |

given a texture encoded for the LDR Profile. | |

The feature subset for the LDR profile is: | |

* 2D textures only, including 2D, 2D array, cube map face, | |

and cube map array texture targets. | |

* Only those block sizes listed in Table C.2.2 are supported. | |

* LDR operation mode only. | |

* Only LDR endpoint formats must be supported, namely formats | |

0, 1, 4, 5, 6, 8, 9, 10, 12, 13. | |

* Decoding from a HDR endpoint results in the error color. | |

* Interpolation returns UNORM8 results when used in conjunction | |

with sRGB. | |

* LDR void extent blocks must be supported, but void extents | |

may not be checked." | |

If only the LDR profile is supported, read this extension by striking | |

all descriptions of HDR modes and decoding algorithms. The extension | |

documents how to modify the document for some particularly tricky cases, | |

but the general rule is as described in this paragraph. | |

Interactions with immutable-format texture images | |

ASTC texture formats are supported by immutable-format textures only if | |

such textures are supported by the underlying implementation (e.g. | |

OpenGL 4.1 or later, OpenGL ES 3.0 or later, or earlier versions | |

supporting the GL_EXT_texture_storage extension). Otherwise, remove all | |

references to the Tex*Storage* commands from this specification. | |

Interactions with texture cube map arrays | |

ASTC textures are supported for the TEXTURE_CUBE_MAP_ARRAY target only | |

when cube map arrays are supported by the underlying implementation | |

(e.g. OpenGL 4.0 or later, or an OpenGL or OpenGL ES version supporting | |

an extension defining cube map arrays). Otherwise, remove all references | |

to texture cube map arrays from this specification. | |

Interactions with OpenGL (all versions) | |

ASTC is not supported for 1D textures and texture rectangles, and does | |

not support non-zero borders. | |

Add the following error conditions to CompressedTexImage*D: | |

"An INVALID_ENUM error is generated by CompressedTexImage1D if | |

<internalformat> is one of the ASTC formats. | |

An INVALID_OPERATION error is generated by CompressedTexImage2D | |

and CompressedTexImage3D if <internalformat> is one of the ASTC | |

formats and <border> is non-zero." | |

Add the following error conditions to CompressedTexSubImage*D: | |

"An INVALID_ENUM error is generated by CompressedTex*SubImage1D | |

if the internal format of the texture is one of the ASTC formats. | |

An INVALID_OPERATION error is generated by CompressedTex*SubImage2D | |

if the internal format of the texture is one of the ASTC formats | |

and <border> is non-zero." | |

Add the following error conditions to TexStorage1D and TextureStorage1D: | |

"An INVALID_ENUM error is generated by TexStorage1D and TextureStorage1D | |

if <format> is one of the ASTC formats." | |

Add the following error conditions to TexStorage2D and TextureStorage2D | |

for versions of OpenGL that support texture rectangles: | |

"An INVALID_OPERATON error is generated by TexStorage2D and | |

TextureStorage2D if <format> is one of the ASTC formats and <target> | |

is TEXTURE_RECTANGLE. | |

Interactions with OpenGL 4.2 | |

OpenGL 4.2 supports the feature that compressed textures can be | |

compressed online, by passing the compressed texture format enum as | |

the internal format when uploading a texture using TexImage1D, | |

TexImage2D or TexImage3D (see Section 3.9.3, Texture Image | |

Specification, subsection Encoding of Special Internal Formats). | |

Due to the complexity of the ASTC compression algorithm, it is not | |

usually suitable for online use, and therefore ASTC support will be | |

limited to pre-compressed textures only. Where on-device compression | |

is required, a domain-specific limited compressor will typically | |

be used, and this is therefore not suitable for implementation in | |

the driver. | |

In particular, the ASTC format specifiers will not be added to | |

Table 3.14, and thus will not be accepted by the TexImage*D | |

functions, and will not be returned by the (already deprecated) | |

COMPRESSED_TEXTURE_FORMATS query. | |

Issues | |

1) Three-dimensional block ASTC formats (e.g. formats whose block depth | |

is greater than one) are not supported by these extensions. | |

2) The first release of the extension was not clear about the | |

restrictions of the LDR profile and did not document interactions | |

with cube map array textures. | |

RESOLVED. This extension has been rewritten to be based on OpenGL ES | |

3.1, to clearly document LDR restrictions, and to add cube map array | |

texture interactions. | |

Revision History | |

Revision 8, June 8, 2017 - Added missing interactions with OpenGL. | |

Revision 7, July 14, 2016 - Clarified definition of 2D void-extent | |

blocks. | |

Revision 6, March 8, 2016 - Clarified that sRGB transform is not | |

applied to Alpha channel. | |

Revision 5, September 15, 2015 - fix typo in third paragraph of section | |

8.7. | |

Revision 4, June 24, 2015 - minor cleanup from feedback. Move Issues and | |

Interactions sections to the end of the document. Merge some language | |

from OpenGL ES specification edits and rename some tables to figures, | |

due to how they're generated in the core specifications. Include a | |

description of the "Cube Map Array Texture" column added to table 3.19 | |

and expand the description of how to read this document when supporting | |

only the LDR profile (Bug 13921). | |

Revision 3, May 28, 2015 - rebase extension on OpenGL ES 3.1. Clarify | |

texture formats and targets supported by LDR and HDR profiles. Add cube | |

map array targets and an Interactions section defining when they are | |

supported. Add an Interactions section for immutable-format textures | |

(Bug 13921). | |

Revision 2, April 28, 2015 - added CompressedTex{Sub,}Image3D to | |

commands accepting ASTC format tokens in the New Tokens section (Bug | |

10183). |