EXT_texture_compression_rgtc

Name

EXT_texture_compression_rgtc

Name Strings

GL_EXT_texture_compression_rgtc

Contributors

Mark J. Kilgard, NVIDIA
Pat Brown, NVIDIA
Yanjun Zhang, S3
Attila Barsi, Holografika
Jason Schmidt, NVIDIA
Slawomir Grajewski, Intel
Daniel Koch, NVIDIA

Contact

Mark J. Kilgard, NVIDIA Corporation (mjk 'at' nvidia.com)

Status

Shipping for GeForce 8 Series (November 2006, Release 95)

Version

Date: March 28, 2017
Revision: 2

Number

OpenGL Extension #332
OpenGL ES Extension #286

Dependencies

OpenGL 1.3, ARB_texture_compression, or OpenGL ES 3.0 required

This extension is written against the OpenGL 2.0 (September 7,
2004) specification.

This extension interacts with OpenGL 2.0 and ARB_texture_non_power_of_two.

This extension interacts with the OpenGL ES 3.2 specification.

Overview

This extension introduces four new block-based texture compression
formats suited for unsigned and signed red and red-green textures
(hence the name "rgtc" for Red-Green Texture Compression).

These formats are designed to reduce the storage requirements
and memory bandwidth required for red and red-green textures by
a factor of 2-to-1 over conventional uncompressed luminance and
luminance-alpha textures with 8-bit components (GL_LUMINANCE8 and
GL_LUMINANCE8_ALPHA8).

The compressed signed red-green format is reasonably suited for
storing compressed normal maps.

This extension uses the same compression format as the
EXT_texture_compression_latc extension except the color data is stored
in the red and green components rather than luminance and alpha.
Representing compressed red and green components is consistent with
the BC4 and BC5 compressed formats supported by DirectX 10.

New Procedures and Functions

None.

New Tokens

In OpenGL 2.0, these tokens are accepted by the <internalformat> parameter
of TexImage2D, CopyTexImage2D, and CompressedTexImage2D and
the <format> parameter of CompressedTexSubImage2D.

In OpenGL ES 3.2, these tokens are accepted by the <internalFormat>
parameter of TexImage2D, TexStorage2D, and CompressedTexImage2D and
the <format> parameter of CompressedTexSubImage2D.

    COMPRESSED_RED_RGTC1_EXT                       0x8DBB
    COMPRESSED_SIGNED_RED_RGTC1_EXT                0x8DBC
    COMPRESSED_RED_GREEN_RGTC2_EXT                 0x8DBD
    COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT          0x8DBE

Additions to Chapter 2 of the OpenGL 2.0 Specification (OpenGL Operation)

None.

Additions to Chapter 3 of the OpenGL 2.0 Specification (Rasterization)

– Section 3.8.1, Texture Image Specification

Add to Table 3.17 (page 155):  Specific compressed internal formats

    Compressed Internal Format                   Base Internal Format
    -------------------------------------------  --------------------
    COMPRESSED_RED_RGTC1_EXT                     RGB
    COMPRESSED_SIGNED_RED_RGTC1_EXT              RGB
    COMPRESSED_RED_GREEN_RGTC2_EXT               RGB
    COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT        RGB

– Section 3.8.2, Alternative Texture Image Specification Commands [Section 8.6 in OpenGL ES 3.2]

Add to the end of the section (page 163):

"If the internal format of the texture image
being modified is COMPRESSED_RED_RGTC1_EXT,
COMPRESSED_SIGNED_RED_RGTC1_EXT, COMPRESSED_RED_GREEN_RGTC2_EXT,
or COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, the texture is stored
using one of the two RGTC compressed texture image encodings (see
appendix).  Such images are easily edited along 4x4 texel boundaries,
so the limitations on TexSubImage2D or CopyTexSubImage2D parameters
are relaxed.  TexSubImage2D and CopyTexSubImage2D will result in
an INVALID_OPERATION error only if one of the following conditions
occurs:

    * <width> is not a multiple of four, <width> plus <xoffset> is not
      equal to TEXTURE_WIDTH, and either <xoffset> or <yoffset> is
      non-zero;

    * <height> is not a multiple of four, <height> plus <yoffset> is not
      equal to TEXTURE_HEIGHT, and either <xoffset> or <yoffset> is
      non-zero; or

    * <xoffset> or <yoffset> is not a multiple of four.

The contents of any 4x4 block of texels of an RGTC compressed texture
image that does not intersect the area being modified are preserved
during valid TexSubImage2D and CopyTexSubImage2D calls."

– Section 3.8.3, Compressed Texture Images [Section 8.7 in OpenGL ES 3.2]

Add after the 4th paragraph (page 164) at the end of the
CompressedTexImage discussion:

"If <internalformat> is COMPRESSED_RED_RGTC1_EXT,
COMPRESSED_SIGNED_RED_RGTC1_EXT, COMPRESSED_RED_GREEN_RGTC2_EXT,
or COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, the compressed texture is
stored using one of several RGTC compressed texture image formats.
The RGTC texture compression algorithm supports only 2D images
without borders.  CompressedTexImage1D and CompressedTexImage3D
produce an INVALID_ENUM error if <internalformat> is an RGTC format.
CompressedTexImage2D will produce an INVALID_OPERATION error if
<border> is non-zero.

Add to the end of the section (page 166) at the end of the
CompressedTexSubImage discussion:

"If the internal format of the texture image
being modified is COMPRESSED_RED_RGTC1_EXT,
COMPRESSED_SIGNED_RED_RGTC1_EXT, COMPRESSED_RED_GREEN_RGTC2_EXT,
or COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, the texture is stored
using one of the several RGTC compressed texture image formats.
Since the RGTC texture compression algorithm supports only 2D images,
CompressedTexSubImage1D and CompressedTexSubImage3D produce an
INVALID_ENUM error if <format> is an RGTC format.  Since RGTC images
are easily edited along 4x4 texel boundaries, the limitations on
CompressedTexSubImage2D are relaxed.  CompressedTexSubImage2D will
result in an INVALID_OPERATION error only if one of the following
conditions occurs:

    * <width> is not a multiple of four, and <width> plus <xoffset> is not
      equal to TEXTURE_WIDTH;

    * <height> is not a multiple of four, and <height> plus <yoffset> is
      not equal to TEXTURE_HEIGHT; or

    * <xoffset> or <yoffset> is not a multiple of four.

The contents of any 4x4 block of texels of an RGTC compressed texture
image that does not intersect the area being modified are preserved
during valid TexSubImage2D and CopyTexSubImage2D calls."

– Section 3.8.8, Texture Minification [Section 8.14 in OpenGL ES 3.2]

Add a sentence to the last paragraph (page 174) just prior to the
"Mipmapping" subheading:

"If the texture's internal format lacks components that exist in
the texture's base internal format, such components are considered
zero when the texture border color is sampled.  (So despite the
RGB base internal format of the COMPRESSED_RED_RGTC1_EXT and
COMPRESSED_SIGNED_RED_RGTC1_EXT formats, the green and blue
components of the texture border color are always considered
zero.  Likewise for the COMPRESSED_RED_GREEN_RGTC2_EXT, and
COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT formats, the blue component
is always considered zero.)"

Additions to Chapter 4 of the OpenGL 2.0 Specification (Per-Fragment Operations and the Frame Buffer)

None.

Additions to Chapter 5 of the OpenGL 2.0 Specification (Special Functions)

None.

Additions to Chapter 6 of the OpenGL 2.0 Specification (State and State Requests)

None.

Additions to Appendix A of the OpenGL 2.0 Specification (Invariance)

None.

Additions to the AGL/GLX/WGL Specifications

None.

Additions to Appendix C of the OpenGL ES 3.2 Specification (Compressed Texture Image Formats)

Add a new Section C.3 (RGTC Compressed Texture Image Formats)

RGTC formats are described in the "RGTC Compressed Texture Image Formats"
chapter of the Khronos Data Format Specification. The mapping between
OpenGL ES RGTC formats and that specification is shown in table C.3.

OpenGL ES format                        Data Format Specification
                                        Description
-------------------------------         -------------------------
COMPRESSED_RED_RGTC1_EXT                BC4 unsigned
COMPRESSED_SIGNED_RED_RGTC1_EXT         BC4 signed
COMPRESSED_RED_GREEN_RGTC2_EXT          BC5 unsigned
COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT   BC5 signed

GLX Protocol

None.

Dependencies on ARB_texture_compression

If ARB_texture_compression is supported, all the
errors and accepted tokens for CompressedTexImage1D,
CompressedTexImage2D, CompressedTexImage3D, CompressedTexSubImage1D,
CompressedTexSubImage2D, and CompressedTexSubImage3D also apply
respectively to the ARB-suffixed CompressedTexImage1DARB,
CompressedTexImage2DARB, CompressedTexImage3DARB,
CompressedTexSubImage1DARB, CompressedTexSubImage2DARB, and
CompressedTexSubImage3DARB.

Dependencies on OpenGL 2.0 or ARB_texture_non_power_of_two

If OpenGL 2.0 or ARB_texture_non_power_of_two is supported, compressed
texture images can have sizes that are neither multiples of four nor small
values like one or two.  The original version of this specification didn't
allow TexSubImage2D and CompressedTexSubImage2D to update only a portion
of such images.  The spec has been updated to allow such edits in the
spirit of the resolution of issue (3) of the EXT_texture_compression_s3tc
specification.  See the "Implementation Note" section for more details.

Interactions with the OpenGL ES 3.2 Specification

If implemented in OpenGL ES, replace the addition to Table 3.17
in Section 3.8.1 with an addition to Table 8.17 in Section 8.7:

Compressed Internal Format             Base      Block    Border  3D   Cube
                                       Internal  Width x  Type    Tex  Map
                                       Format    Height                Array
                                                                       Tex
---------------------------------      --------  -------  ------  ---  -----
COMPRESSED_RED_RGTC1_EXT               RED       4x4      unorm
COMPRESSED_SIGNED_RED_RGTC1_EXT        RED       4x4      snorm
COMPRESSED_RED_GREEN_RGTC2_EXT         RG        4x4      unorm
COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT  RG        4x4      snorm


Also, add to Section 8.4, Table 8.2: Valid combinations of format, type,
and sized internalFormat

                       External
                       Bytes
Format  Type           Per Pixel  Internal Format
------  -------------  ---------  --------------------------------------
RED     UNSIGNED_BYTE  4          COMPRESSED_RED_RGTC1_EXT
RED     SIGNED_BYTE    4          COMPRESSED_SIGNED_RED_RGTC1_EXT
RG      UNSIGNED_BYTE  8          COMPRESSED_RED_GREEN_RGTC2_EXT
RG      SIGNED_BYTE    8          COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT


In OpenGL ES, queries to GL_NUM_COMPRESSED_TEXTURE_FORMATS and
GL_COMPRESSED_TEXTURE_FORMATS should return the RGTC formats.

In OpenGL ES, INVALID_OPERATION is generated by TexImage2D and TexStorage2D
if an RGTC format is used as the <internalFormat> parameter with a <type>
and <format> combination NOT listed:

InternalFormat                          Format      Type
----------------------                  ----------  --------------
COMPRESSED_RED_RGTC1_EXT                RED         UNSIGNED_BYTE
COMPRESSED_SIGNED_RED_RGTC1_EXT         RED         SIGNED_BYTE
COMPRESSED_RED_GREEN_RGTC2_EXT          RG          UNSIGNED_BYTE
COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT   RG          SIGNED_BYTE

Errors

INVALID_ENUM is generated by CompressedTexImage1D
or CompressedTexImage3D if <internalformat> is
COMPRESSED_RED_RGTC1_EXT, COMPRESSED_SIGNED_RED_RGTC1_EXT,
COMPRESSED_RED_GREEN_RGTC2_EXT, or
COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT.

INVALID_OPERATION is generated by CompressedTexImage2D
if <internalformat> is COMPRESSED_RED_RGCT1_EXT,
COMPRESSED_SIGNED_RED_RGTC1_EXT, COMPRESSED_RED_GREEN_RGTC2_EXT,
or COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT and <border> is not equal
to zero.

INVALID_ENUM is generated by CompressedTexSubImage1D
or CompressedTexSubImage3D if
<format> is COMPRESSED_RED_RGCT1_EXT,
COMPRESSED_SIGNED_RED_RGTC1_EXT, COMPRESSED_RED_GREEN_RGTC2_EXT,
or COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT.

INVALID_OPERATION is generated by TexSubImage2D or CopyTexSubImage2D if
TEXTURE_INTERNAL_FORMAT is COMPRESSED_RED_RGCT1_EXT,
COMPRESSED_SIGNED_RED_RGTC1_EXT, COMPRESSED_RED_GREEN_RGTC2_EXT, or
COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT and any of the following apply:

    * <width> is not a multiple of four, <width> plus <xoffset> is not
      equal to TEXTURE_WIDTH, and either <xoffset> or <yoffset> is
      non-zero;

    * <height> is not a multiple of four, <height> plus <yoffset> is not
      equal to TEXTURE_HEIGHT, and either <xoffset> or <yoffset> is
      non-zero; or

    * <xoffset> or <yoffset> is not a multiple of four.

INVALID_OPERATION is generated by CompressedTexSubImage2D if
TEXTURE_INTERNAL_FORMAT is COMPRESSED_RED_RGCT1_EXT,
COMPRESSED_SIGNED_RED_RGTC1_EXT, COMPRESSED_RED_GREEN_RGTC2_EXT, or
COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT and any of the following apply:

    * <width> is not a multiple of four, and <width> plus <xoffset> is not
      equal to TEXTURE_WIDTH;

    * <height> is not a multiple of four, and <height> plus <yoffset> is
      not equal to TEXTURE_HEIGHT; or

    * <xoffset> or <yoffset> is not a multiple of four.

The following restrictions from the ARB_texture_compression
specification do not apply to RGTC texture formats, since subimage
modification is straightforward as long as the subimage is properly
aligned.

DELETE: INVALID_OPERATION is generated by TexSubImage1D, TexSubImage2D,
DELETE: TexSubImage3D, CopyTexSubImage1D, CopyTexSubImage2D, or
DELETE: CopyTexSubImage3D if the internal format of the texture image is
DELETE: compressed and <xoffset>, <yoffset>, or <zoffset> does not equal
DELETE: -b, where b is value of TEXTURE_BORDER.

DELETE: INVALID_VALUE is generated by CompressedTexSubImage1D,
DELETE: CompressedTexSubImage2D, or CompressedTexSubImage3D if the
DELETE: entire texture image is not being edited:  if <xoffset>,
DELETE: <yoffset>, or <zoffset> is greater than -b, <xoffset> + <width> is
DELETE: less than w+b, <yoffset> + <height> is less than h+b, or <zoffset>
DELETE: + <depth> is less than d+b, where b is the value of
DELETE: TEXTURE_BORDER, w is the value of TEXTURE_WIDTH, h is the value of
DELETE: TEXTURE_HEIGHT, and d is the value of TEXTURE_DEPTH.

See also errors in the GL_ARB_texture_compression specification.

New State

4 new state values are added for the per-texture object
GL_TEXTURE_INTERNAL_FORMAT state.

In the "Textures" state table( page 278), increment the
TEXTURE_INTERNAL_FORMAT subscript for Z by 4 in the "Type" row.

[NOTE: The OpenGL 2.0 specification actually should read "n x Z48*"
because of the 6 generic compressed internal formats in table 3.18.]

New Implementation Dependent State

None

Appendix

RGTC Compressed Texture Image Formats

Compressed texture images stored using the RGTC compressed image
encodings are represented as a collection of 4x4 texel blocks,
where each block contains 64 or 128 bits of texel data.  The image
is encoded as a normal 2D raster image in which each 4x4 block is
treated as a single pixel.  If an RGTC image has a width or height
that is not a multiple of four, the data corresponding to texels
outside the image are irrelevant and undefined.

When an RGTC image with a width of <w>, height of <h>, and block
size of <blocksize> (8 or 16 bytes) is decoded, the corresponding
image size (in bytes) is:

    ceil(<w>/4) * ceil(<h>/4) * blocksize.

When decoding an RGTC image, the block containing the texel at offset
(<x>, <y>) begins at an offset (in bytes) relative to the base of the
image of:

    blocksize * (ceil(<w>/4) * floor(<y>/4) + floor(<x>/4)).

The data corresponding to a specific texel (<x>, <y>) are extracted
from a 4x4 texel block using a relative (x,y) value of

    (<x> modulo 4, <y> modulo 4).

There are four distinct RGTC image formats:


COMPRESSED_RED_RGTC1:  Each 4x4 block of texels consists of
64 bits of unsigned red image data.

Each red image data block is encoded as a sequence of 8 bytes, called
(in order of increasing address):

        red0, red1, bits_0, bits_1, bits_2, bits_3, bits_4, bits_5

    The 6 "bits_*" bytes of the block are decoded into a 48-bit bit
    vector:

        bits   = bits_0 +
                 256 * (bits_1 +
                        256 * (bits_2 +
                               256 * (bits_3 +
                                      256 * (bits_4 +
                                             256 * bits_5))))

    red0 and red1 are 8-bit unsigned integers that are unpacked to red
    values RED0 and RED1 as though they were pixels with a <format>
    of LUMINANCE and a type of UNSIGNED_BTYE.

    bits is a 48-bit unsigned integer, from which a three-bit control
    code is extracted for a texel at location (x,y) in the block
    using:

        code(x,y) = bits[3*(4*y+x)+2..3*(4*y+x)+0]

    where bit 47 is the most significant and bit 0 is the least
    significant bit.

    The red value R for a texel at location (x,y) in the block is
    given by:

        RED0,              if red0 > red1 and code(x,y) == 0
        RED1,              if red0 > red1 and code(x,y) == 1
        (6*RED0+  RED1)/7, if red0 > red1 and code(x,y) == 2
        (5*RED0+2*RED1)/7, if red0 > red1 and code(x,y) == 3
        (4*RED0+3*RED1)/7, if red0 > red1 and code(x,y) == 4
        (3*RED0+4*RED1)/7, if red0 > red1 and code(x,y) == 5
        (2*RED0+5*RED1)/7, if red0 > red1 and code(x,y) == 6
        (  RED0+6*RED1)/7, if red0 > red1 and code(x,y) == 7

        RED0,              if red0 <= red1 and code(x,y) == 0
        RED1,              if red0 <= red1 and code(x,y) == 1
        (4*RED0+  RED1)/5, if red0 <= red1 and code(x,y) == 2
        (3*RED0+2*RED1)/5, if red0 <= red1 and code(x,y) == 3
        (2*RED0+3*RED1)/5, if red0 <= red1 and code(x,y) == 4
        (  RED0+4*RED1)/5, if red0 <= red1 and code(x,y) == 5
        MINRED,            if red0 <= red1 and code(x,y) == 6
        MAXRED,            if red0 <= red1 and code(x,y) == 7

    MINRED and MAXRED are 0.0 and 1.0 respectively.

Since the decoded texel has a red format, the resulting RGBA value
for the texel is (R,0,0,1).


COMPRESSED_SIGNED_RED_RGTC1:  Each 4x4 block of texels consists of
64 bits of signed red image data.  The red values of a texel are
extracted in the same way as COMPRESSED_RED_RGTC1 except red0, red1,
RED0, RED1, MINRED, and MAXRED are signed values defined as follows:

    red0 and red1 are 8-bit signed (two's complement) integers.

           { red0 / 127.0, red0 > -128
    RED0 = {
           { -1.0,         red0 == -128

           { red1 / 127.0, red1 > -128
    RED1 = {
           { -1.0,         red1 == -128

    MINRED = -1.0

    MAXRED =  1.0

CAVEAT for signed red0 and red1 values: the expressions "red0 >
red1" and "red0 <= red1" above are considered undefined (read: may
vary by implementation) when red0 equals -127 and red1 equals -128,
This is because if red0 were remapped to -127 prior to the comparison
to reduce the latency of a hardware decompressor, the expressions
would reverse their logic.  Encoders for the signed LA formats should
avoid encoding blocks where red0 equals -127 and red1 equals -128.


COMPRESSED_RED_GREEN_RGTC2:  Each 4x4 block of texels consists of
64 bits of compressed unsigned red image data followed by 64 bits
of compressed unsigned green image data.

The first 64 bits of compressed red are decoded exactly like
COMPRESSED_RED_RGTC1 above.

The second 64 bits of compressed green are decoded exactly like
COMPRESSED_RED_RGTC1 above except the decoded value R for this
second block is considered the resulting green value G.

Since the decoded texel has a red-green format, the resulting RGBA
value for the texel is (R,G,0,1).


COMPRESSED_SIGNED_RED_GREEN_RGTC2:  Each 4x4 block of texels consists
of 64 bits of compressed signed red image data followed by 64 bits
of compressed signed green image data.

The first 64 bits of compressed red are decoded exactly like
COMPRESSED_SIGNED_RED_RGTC1 above.

The second 64 bits of compressed green are decoded exactly like
COMPRESSED_SIGNED_RED_RGTC1 above except the decoded value R
for this second block is considered the resulting green value G.

Since this image has a red-green format, the resulting RGBA value is
(R,G,0,1).

Issues

1)  What should these new formats be called?

    RESOLVED: "rgtc" for Red-Green Texture Compression.

2)  How should the uncompressed and filtered texels be returned by
    texture fetches?

    RESOLVED:  Red values show up as (R,0,0,1) where R is the red
    value, green and blue are forced to 0, and alpha is forced to 1.
    Likewise, red-green values show up as (R,G,0,1) where G is the
    green value.

    Prior extensions such as NV_float_buffer and NV_texture_shader
    have introduced formats such as GL_FLOAT_R_NV and GL_DSDT_NV where
    one- and two-component texture formats show up as (X,0,0,1) or
    (X,Y,0,1) RGBA texels.  The RGTC formats mimic these two-component
    formats.

    The (X,Y,0,1) convention, particularly with signed components,
    is nice for normal maps because a normalized vector can be
    formed by a shader program by computing sqrt(abs(1-X*X-Y*Y))
    for the Z component.

    While GL_RED is a valid external format, core OpenGL provides
    no GL_RED_GREEN external format.  Applications can either use
    GL_RGB or GL_RGBA and pad out the blue and alpha components,
    or use the two-component GL_LUMINANCE_ALPHA color format and
    use the color matrix functionality to swizzle the luminance and
    alpha values into red and green respectively.

3)  Should red and red-green compression formats with signed
    components be introduced when the core specification lacked
    uncompressed red and red-green texture formats?

    RESOLVED:  Yes, signed red and red-green compression formats
    should be added.

    Signed red-green formats are suited for compressed normal maps.
    Compressed normal maps may well be the dominant use of this
    extension.

    Unsigned red-green formats require an extra "expand normal"
    operation to convert [0,1] to [-1,+1].  Direct support for signed
    red-green formats avoids this step in a shader program.

4)  Should there be a mix of signed red and unsigned green or
    vice versa?

    RESOLVED:  No.

    NV_texture_shader provided an internal format
    (GL_SIGNED_RGB_UNSIGNED_ALPHA_NV) with mixed signed and unsigned
    components.  The format saw little usage.  There's no reason to
    think a GL_SIGNED_RED_UNSIGNED_GREEN format would be any more
    useful or popular.

5)  How are signed integer values mapped to floating-point values?

    RESOLVED:  A signed 8-bit two's complement value X is computed to
    a floating-point value Xf with the formula:

             { X / 127.0, X > -128
        Xf = {
             { -1.0,      X == -128

    This conversion means -1, 0, and +1 are all exactly representable,
    however -128 and -127 both map to -1.0.  Mapping -128 to -1.0
    avoids the numerical awkwardness of have a representable value
    slightly more negative than -1.0.

    This conversion is intentionally NOT the "byte" conversion listed
    in Table 2.9 for component conversions.  That conversion says:

        Xf = (2*X + 1) / 255.0

    The Table 2.9 conversion is incapable of exactly representing
    zero.

6)  How will signed components resulting
    from GL_COMPRESSED_SIGNED_RED_RGTC1_EXT and
    GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT texture fetches interact
    with fragment coloring?

    RESOLVED:  The specification language for this extension is silent
    about clamping behavior leaving this to the core specification
    and other extensions.  The clamping or lack of clamping is left
    to the core specification and other extensions.

    For assembly program extensions supporting texture fetches
    (ARB_fragment_program, NV_fragment_program, NV_vertex_program3,
    etc.) or the OpenGL Shading Language, these signed formats will
    appear as expected with unclamped signed components as a result
    of a texture fetch instruction.

    If ARB_color_buffer_float is supported, its clamping controls
    will apply.

    NV_texture_shader extension, if supported, adds support for
    fixed-point textures with signed components and relaxed the
    fixed-function texture environment clamping appropriately.  If the
    NV_texture_shader extension is supported, its specified behavior
    for the texture environment applies where intermediate values
    are clamped to [-1,1] unless stated otherwise as in the case
    of explicitly clamped to [0,1] for GL_COMBINE.  or clamping the
    linear interpolation weight to [0,1] for GL_DECAL and GL_BLEND.

    Otherwise, the conventional core texture environment clamps
    incoming, intermediate, and output color components to [0,1].

    This implies that the conventional texture environment
    functionality of unextended OpenGL 1.5 or OpenGL 2.0 without
    using GLSL (and with none of the extensions referred to above)
    is unable to make proper use of the signed texture formats added
    by this extension because the conventional texture environment
    requires texture source colors to be clamped to [0,1].  Texture
    filtering of these signed formats would be still signed, but
    negative values generated post-filtering would be clamped to
    zero by the core texture environment functionality.  The
    expectation is clearly that this extension would be co-implemented
    with one of the previously referred to extensions or used with
    GLSL for the new signed formats to be useful.

7)  Should a specific normal map compression format be added?

    RESOLVED:  No.

    It's probably short-sighted to design a format just for normal
    maps.  Indeed, NV_texture_shader added a GL_SIGNED_HILO_NV
    format with exactly the kind of "hemisphere remap" useful for
    normal maps and the format went basically unused.  Instead,
    this extension provides the mechanism for compressed normal maps
    based on the more conventional red-green format.

    The GL_COMPRESSED_RED_GREEN_RGTC2_EXT and
    GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT formats are sufficient
    for normal maps with additional shader instructions used to
    generate the 3rd component.

8)  Should uncompressed signed red and red-green formats be added
    by this extension?

    RESOLVED:  No, this extension is focused on just adding compressed
    texture formats.

    The NV_texture_shader extension adds such uncompressed signed
    texture formats.  A distinct multi-vendor extension for signed
    fixed-point texture formats could provide all or a subset of
    the signed fixed-point uncompressed texture formats introduced
    by NV_texture_shader.

9)  What compression ratios does this extension provide?

    The RGTC1 formats are 8 bytes (64 bits) per 4x4 pixel block.
    A 4x4 block of GL_LUMINANCE8 data requires 16 bytes (1 byte
    per texel).  This is a 2-to-1 compression ratio.

    The RGTC2 formats are 16 bytes (128 bits) per 4x4 pixel block.
    A 4x4 block of GL_LUMINANCE8_ALPHA8 data requires 32 bytes
    (2 bytes per texel).  This is again a 2-to-1 compression ratio.

    In contrast, the comparable compression ratio for the S3TC
    formats is 4-to-1.

    Arguably, the lower compression ratio allows better compression
    quality particularly because the RGTC formats compress each
    component separately.

10) How do these new formats compare with the existing GL_LUMINANCE4,
    GL_LUMINANCE4_ALPHA4, and GL_LUMINANCE6_ALPHA2 internal formats?

    RESOLVED:  The existing GL_LUMINANCE4, GL_LUMINANCE4_ALPHA4,
    and GL_LUMINANCE6_ALPHA2 internal formats provide a similar
    2-to-1 compression ratio but mandate a uniform quantization
    for all components.  In contrast, this extension provides a
    compression format with 3-bit quantization over a specifiable
    min/max range that can vary per 4x4 texel tile.

    Additionally, many OpenGL implementations do not natively support
    the GL_LUMINANCE4, GL_LUMINANCE4_ALPHA4, and GL_LUMINANCE6_ALPHA2
    internal formats but rather silently promote these formats
    to store 8 bits per component, thereby eliminating any
    storage/bandwidth advantage for these formats.

11) Does this extension require EXT_texture_compression_s3tc?

    RESOLVED:  No.

    As written, this specification does not rely on wording of the
    EXT_texture_compression_s3tc extension.  For example, certain
    discussion added to Sections 3.8.2 and 3.8.3 is quite similar
    to corresponding EXT_texture_compression_s3tc language.

12) Should anything be said about the precision of texture filtering
    for these new formats?

    RESOLVED:  No precision requirements are part of the specification
    language since OpenGL extensions typically leave precision
    details to the implementation.

    Realistically, at least 8-bit filtering precision can be expected
    from implementations (and probably more).

13) Should these formats be allowed to specify 3D texture images
    when NV_texture_compression_vtc is supported?

    RESOLVED: The NV_texture_compression_vtc stacks 4x4 blocks into
    4x4x4 bricks.  It may be more desirable to represent compressed
    3D textures as simply slices of 4x4 blocks.

    However the NV_texture_compression_vtc extension expects data
    passed to the glCompressedTexImage commands to be "bricked"
    rather than blocked slices.

14) How is the texture border color handled for the blue component
    of an RGTC2 texture and the green and blue components of an
    RGTC1 texture?

    RESOLVED:  The base texture format is RGB for the RGTC1 and
    RGTC2 texture formats.  This would mean table 3.15 would be
    used to determine how the texture border color is interpreted
    and which components are considered.

    However since only red or red/green components exist for the
    RGTC1 and RGTC2 formats, it makes little sense to require
    the blue component be supplied by the texture border color and
    hence be involved (meaningfully only when the border is sampled)
    in texture filtering.

    For this reason, a statement is added to section 3.8.8 says that
    if a texture's internal format lacks components that exist in
    the texture's base internal format, such components contain
    zero (ignoring the texture's corresponding texture border color
    component value) when the texture border color is sampled.

    So the green and blue components of the filtered result of a
    RGTC1 texture are always zero, even when the border is sampled.
    Similarly the blue component of the filtered result of a RGTC2
    texture is always zero, even when the border is sampled.

15) What should glGetTexLevelParameter return for
    GL_TEXTURE_GREEN_SIZE and GL_TEXTURE_BLUE_SIZE for the RGTC1
    formats?  What should glGetTexLevelParameter return for
    GL_TEXTURE_BLUE_SIZE for the RGTC2 formats?

    RESOLVED:  Zero bits.

    These formats always return 0.0 for these respective components
    and have no bits devoted to these components.

    Returning 8 bits for red size of RGTC1 and the red and green
    sizes of RGTC2 makes sense because that's the maximum potential
    precision for the uncompressed texels.

16) Should the token names contain R and RG or RED and RED_GREEN?

    RESOLVED:  RED and RED_GREEN.

    Saying RGB and RGBA makes sense for three- and four-component
    formats rather than spelling out the component names because
    RGB and RGBA are used so commonly and spelling out the names it
    too wordy.

    But for 1- and 2-component names, we follow the precedent by
    GL_LUMINANCE and GL_LUMINANCE_ALPHA.  This extension spells out
    the component names of 1- and 2-component names.

    Another reason to avoid R and RG is the existing meaning of
    the GL_R and GL_RED tokens.  GL_RED already exists as a token
    name for a single-component external format.  GL_R also already
    exists as a token name but refers to the R texture coordinate,
    not the red color component.

17) Can you use the GL_RED external format with glTexImage2D and other
    such commands to load textures with the
    GL_COMPRESSED_RED_RGTC1_EXT or GL_COMPRESSED_SIGNED_RED_RGTC1_EXT
    internal formats?

    RESOLVED: Yes.

    GL_RED has been a valid external format parameter to glTexImage
    and similar commands since OpenGL 1.0.

18) Should any of the generic compression GL_COMPRESSED_* tokens in
    OpenGL 2.1 map to RGTC formats?

    RESOLVED:  No.  The RGTC formats are missing color components
    so are not adequate implementations for any of the generic
    compression formats.

19) Should the GL_NUM_COMPRESSED_TEXTURE_FORMATS and
    GL_COMPRESSED_TEXTURE_FORMATS queries return the RGTC formats?

    RESOLVED:  Not in OpenGL, yes in OpenGL ES.

    The OpenGL 2.1 specification says "The only values returned
    by this query [GL_COMPRESSED_TEXTURE_FORMATS"] are those
    corresponding to formats suitable for general-purpose usage.
    The renderer will not enumerate formats with restrictions that
    need to be specifically understood prior to use."

    Compressed textures with just red or red-green components are
    not general-purpose so should not be returned by these queries
    because they have restrictions.

    Applications that seek to use the RGTC formats should do so
    by looking for this extension's name in the string returned by
    glGetString(GL_EXTENSIONS) rather than
    what GL_NUM_COMPRESSED_TEXTURE_FORMATS and
    GL_COMPRESSED_TEXTURE_FORMATS return.

    The OpenGL ES 3.2 specification does not include the requirement
    for general-purpose usage, and so these queries should return the
    RGTC formats in an ES context.

Implementation Note

This extension allows TexSubImage2D and CompressedTexSubImage2D to perform
partial updates to compressed images, but generally requires that the
updated area be aligned to 4x4 block boundaries.  If the width or height
is not a multiple of four, there will be 4x4 blocks at the edge of the
image that contain "extra" texels that are not part of the image.  This
spec has an exception allowing edits that partially cover such blocks as
long as the edit covers all texels in the block belonging to the image.
For example, in a 2D texture of size 70x50, it is legal to update the
single partial block covering the four texels from (68,48) to (69,49) by
setting (<xoffset>, <yoffset>) to (68,48) and <width> and <height> to 2.

This specification derived some of its language from the
EXT_texture_compression_s3tc specification.  When that extension was
originally written, non-bordered textures were required to have widths and
heights that were powers of two.  Therefore, the only cases where partial
blocks could occur were if the width or height of the texture image was
one or two.  The original spec language allowed partial block edits only
if the width or height of the region edited was equal to the full texture
size.  That language didn't handle cases such as the 70x50 example above.

This specification was updated in April, 2009 to allow such edits.
Multiple OpenGL implementers correctly implemented the original
restriction, and partial edits that include partially covered tiles will
result in INVALID_OPERATION errors on older drivers.

Revision History

Revision 1.1, April 24, 2007: mjk
    -  Add caveat about how signed LA decompression happens when
       lum0 equals -127 and lum1 equals -128.  This caveat matches
       a decoding allowance in DirectX 10.

Revision 1.2, January 21, 2008: mjk
    -  Add issues #18 and #19.

Revision 1.3, April 14, 2009: pbrown
    - Add interaction with non-power-of-two textures from OpenGL 2.0 /
      ARB_texture_non_power_of_two.  Allow CompressedTexSubImage2D to
      perform edits that include partial tiles at the edge of the image as
      long as the specified width/height parameters line up with the edge.
      Thanks to Emil Persson for finding this issue.

Revision 2, March 28, 2017: jaschmidt
    - Add interactions with the OpenGL ES 3.2 specification.
    - repace incorrect references to COMPRESSED_LUMINANCE_LACT1_EXT with
      correct references to COMPRESSED_RED_RGTC1_EXT.