Name
EXT_texture_shared_exponent
Name Strings
GL_EXT_texture_shared_exponent
Contact
Mark J. Kilgard, NVIDIA Corporation (mjk 'at' nvidia.com)
Contributors
Pat Brown, NVIDIA
Jon Leech
Bruce Merry, ARM
Status
Shipping
Version
Date: July 18, 2008
Revision: 1.0
Number
333
Dependencies
OpenGL 1.1 required
ARB_color_buffer_float affects this extension.
EXT_framebuffer_object affects this extension.
This extension is written against the OpenGL 2.0 (September 7,
2004) specification.
Overview
Existing texture formats provide either fixed-point formats with
limited range and precision but with compact encodings (allowing 32
or fewer bits per multi-component texel), or floating-point formats
with tremendous range and precision but without compact encodings
(typically 16 or 32 bits per component).
This extension adds a new packed format and new internal texture
format for encoding 3-component vectors (typically RGB colors) with
a single 5-bit exponent (biased up by 15) and three 9-bit mantissas
for each respective component. There is no sign bit so all three
components must be non-negative. The fractional mantissas are
stored without an implied 1 to the left of the decimal point.
Neither infinity nor not-a-number (NaN) are representable in this
shared exponent format.
This 32 bits/texel shared exponent format is particularly well-suited
to high dynamic range (HDR) applications where light intensity is
typically stored as non-negative red, green, and blue components
with considerable range.
New Procedures and Functions
None
New Tokens
Accepted by the parameter of TexImage1D,
TexImage2D, TexImage3D, CopyTexImage1D, CopyTexImage2D, and
RenderbufferStorageEXT:
RGB9_E5_EXT 0x8C3D
Accepted by the parameter of DrawPixels, ReadPixels,
TexImage1D, TexImage2D, GetTexImage, TexImage3D, TexSubImage1D,
TexSubImage2D, TexSubImage3D, GetHistogram, GetMinmax,
ConvolutionFilter1D, ConvolutionFilter2D, ConvolutionFilter3D,
GetConvolutionFilter, SeparableFilter2D, GetSeparableFilter,
ColorTable, ColorSubTable, and GetColorTable:
UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E
Accepted by the parameter of GetTexLevelParameterfv and
GetTexLevelParameteriv:
TEXTURE_SHARED_SIZE_EXT 0x8C3F
Additions to Chapter 2 of the 2.0 Specification (OpenGL Operation)
None
Additions to Chapter 3 of the 2.0 Specification (Rasterization)
-- Section 3.6.4, Rasterization of Pixel Rectangles
Add a new row to Table 3.5 (page 128):
type Parameter Corresponding Special
Token Name GL Data Type Interpretation
----------------------------- ------------- --------------
UNSIGNED_INT_5_9_9_9_REV_EXT uint yes
Add a new row to table 3.8: Packed pixel formats (page 132):
type Parameter GL Data Number of Matching
Token Name Type Components Pixel Formats
----------------------------- ------- ---------- -------------
UNSIGNED_INT_5_9_9_9_REV_EXT uint 4 RGB
Add a new entry to table 3.11: UNSIGNED_INT formats (page 134):
UNSIGNED_INT_5_9_9_9_REV_EXT:
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+-------------+--------------------------+---------------------------+--------------------------+
| 4th | 3rd | 2nd | 1st |
+-------------+--------------------------+---------------------------+--------------------------+
Add to the end of the 2nd paragraph starting "Pixels are draw using":
"If type is UNSIGNED_INT_5_9_9_9_REV_EXT and format is not RGB then
the error INVALID_ENUM occurs."
Add UNSIGNED_INT_5_9_9_9_REV_EXT to the list of packed formats in
the 10th paragraph after the "Packing" subsection (page 130).
Add before the 3rd paragraph (page 135, starting "Calling DrawPixels
with a type of BITMAP...") from the end of the "Packing" subsection:
"Calling DrawPixels with a type of UNSIGNED_INT_5_9_9_9_REV_EXT and
format of RGB is a special case in which the data are a series of GL
uint values. Each uint value specifies 4 packed components as shown
in table 3.11. The 1st, 2nd, 3rd, and 4th components are called
p_red, p_green, p_blue, and p_exp respectively and are treated as
unsigned integers. These are then used to compute floating-point
RGB components (ignoring the "Conversion to floating-point" section
below in this case) as follows:
red = p_red * 2^(p_exp - B - N)
green = p_green * 2^(p_exp - B - N)
blue = p_blue * 2^(p_exp - B - N)
where B is 15 (the exponent bias) and N is 9 (the number of mantissa
bits)."
-- Section 3.8.1, Texture Image Specification:
"Alternatively if the internalformat is RGB9_E5_EXT, the red, green,
and blue bits are converted to a shared exponent format according
to the following procedure:
Components red, green, and blue are first clamped (in the process,
mapping NaN to zero) so:
red_c = max(0, min(sharedexp_max, red))
green_c = max(0, min(sharedexp_max, green))
blue_c = max(0, min(sharedexp_max, blue))
where sharedexp_max is (2^N-1)/2^N * 2^(Emax-B), N is the number
of mantissa bits per component, Emax is the maximum allowed biased
exponent value (careful: not necessarily 2^E-1 when E is the number of
exponent bits), bits, and B is the exponent bias. For the RGB9_E5_EXT
format, N=9, Emax=31, and B=15.
The largest clamped component, max_c, is determined:
max_c = max(red_c, green_c, blue_c)
A preliminary shared exponent is computed:
exp_shared_p = max(-B-1, floor(log2(max_c))) + 1 + B
A refined shared exponent is then computed as:
max_s = floor(max_c / 2^(exp_shared_p - B - N) + 0.5)
{ exp_shared_p, 0 <= max_s < 2^N
exp_shared = {
{ exp_shared_p+1, max_s == 2^N
These integers values in the range 0 to 2^N-1 are then computed:
red_s = floor(red_c / 2^(exp_shared - B - N) + 0.5)
green_s = floor(green_c / 2^(exp_shared - B - N) + 0.5)
blue_s = floor(blue_c / 2^(exp_shared - B - N) + 0.5)
Then red_s, green_s, and blue_s are stored along with exp_shared in
the red, green, blue, and shared bits respectively of the texture
image.
An implementation accepting pixel data of type
UNSIGNED_INT_5_9_9_9_REV_EXT with a format of RGB is allowed to store
the components "as is" if the implementation can determine the current
pixel transfer state act as an identity transform on the components."
Add a new row and the "shared bits" column (blank for all existing
rows) to Table 3.16 (page 154).
Sized Base R G B A L I D shared
Internal Format Internal Format bits bits bits bits bits bits bits bits
--------------------- --------------- ---- ---- ---- ---- ---- ---- ---- ------
RGB9_E5_EXT RGB 9 9 9 5
-- Section 3.8.x, Shared Exponent Texture Color Conversion
Insert this section AFTER section 3.8.14 Texture Comparison Modes
and BEFORE section 3.8.15 Texture Application (and after the "sRGB
Texture Color Conversion" if EXT_texture_sRGB is supported).
"If the currently bound texture's internal format is RGB9_E5_EXT, the
red, green, blue, and shared bits are converted to color components
(prior to filtering) using the following shared exponent decoding.
The components red_s, green_s, blue_s, and exp_shared values (see
section 3.8.1) are treated as unsigned integers and are converted
to red, green, blue as follows:
red = red_s * 2^(exp_shared - B)
green = green_s * 2^(exp_shared - B)
blue = blue_s * 2^(exp_shared - B)"
Additions to Chapter 4 of the 2.0 Specification (Per-Fragment Operations
and the Frame Buffer)
-- Section 4.3.2, Reading Pixels
Add a row to table 4.7 (page 224);
Component
type Parameter GL Data Type Conversion Formula
----------------------------- ------------ ------------------
UNSIGNED_INT_5_9_9_9_REV_EXT uint special
Replace second paragraph of "Final Conversion" (page 222) to read:
For an RGBA color, if is not FLOAT or
UNSIGNED_INT_5_9_9_9_REV_EXT, or if the CLAMP_READ_COLOR_ARB is
TRUE, or CLAMP_READ_COLOR_ARB is FIXED_ONLY_ARB and the selected
color (or texture) buffer is a fixed-point buffer, each component
is first clamped to [0,1]. Then the appropriate conversion formula
from table 4.7 is applied the component.
In the special case when calling ReadPixels with a type of
UNSIGNED_INT_5_9_9_9_REV_EXT and format of RGB, the conversion
is done as follows: The returned data are packed into a series of
GL uint values. The red, green, and blue components are converted
to red_s, green_s, blue_s, and exp_shared integers as described in
section 3.8.1 when the internalformat is RGB9_E5_EXT. The red_s,
green_s, blue_s, and exp_shared are then packed as the 1st, 2nd,
3rd, and 4th components of the UNSIGNED_INT_5_9_9_9_REV_EXT format
as shown in table 3.11."
Additions to Chapter 5 of the 2.0 Specification (Special Functions)
None
Additions to Chapter 6 of the 2.0 Specification (State and State Requests)
-- Section 6.1.3, Enumerated Queries
Add TEXTURE_SHARED_SIZE_EXT to the list of queries in the first
sentence of the fifth paragraph (page 247) so it reads:
"For texture images with uncompressed internal formats, queries of
value of TEXTURE_RED_SIZE, TEXTURE_GREEN_SIZE, TEXTURE_BLUE_SIZE,
TEXTURE_ALPHA_SIZE, TEXTURE_LUMINANCE_SIZE, TEXTURE_DEPTH_SIZE,
TEXTURE_SHARED_SIZE_EXTT, and TEXTURE_INTENSITY_SIZE return the
actual resolutions of the stored image array components, not the
resolutions specified when the image array was defined."
Additions to the OpenGL Shading Language specification
None
Additions to the GLX Specification
None
GLX Protocol
None.
Dependencies on ARB_color_buffer_float
If ARB_color_buffer_float is not supported, replace this amended
sentence from 4.3.2 above
"For an RGBA color, if is not FLOAT or
UNSIGNED_INT_5_9_9_9_REV_EXT, or if the CLAMP_READ_COLOR_ARB is TRUE, or
CLAMP_READ_COLOR_ARB is FIXED_ONLY_ARB and the selected color buffer
(or texture image for GetTexImage) is a fixed-point buffer (or texture
image for GetTexImage), each component is first clamped to [0,1]."
with
"For an RGBA color, if is not FLOAT or
UNSIGNED_INT_5_9_9_9_REV_EXT and the selected color buffer (or
texture image for GetTexImage) is a fixed-point buffer (or texture
image for GetTexImage), each component is first clamped to [0,1]."
Dependencies on EXT_framebuffer_object
If EXT_framebuffer_object is not supported, then
RenderbufferStorageEXT is not supported and the RGB9_E5_EXT
internalformat is therefore not supported by RenderbufferStorageEXT.
Errors
Relaxation of INVALID_ENUM errors
---------------------------------
TexImage1D, TexImage2D, TexImage3D, CopyTexImage1D, CopyTexImage2D,
and RenderbufferStorageEXT accept the new RGB9_E5_EXT token for
internalformat.
DrawPixels, ReadPixels, TexImage1D, TexImage2D, GetTexImage,
TexImage3D, TexSubImage1D, TexSubImage2D, TexSubImage3D,
GetHistogram, GetMinmax, ConvolutionFilter1D, ConvolutionFilter2D,
ConvolutionFilter3D, GetConvolutionFilter, SeparableFilter2D,
GetSeparableFilter, ColorTable, ColorSubTable, and GetColorTable
accept the new UNSIGNED_INT_5_9_9_9_REV_EXT token for type.
GetTexLevelParameterfv and GetTexLevelParameteriv accept the new
TEXTURE_SHARED_SIZE_EXT token for .
New errors
----------
INVALID_OPERATION is generated by DrawPixels, ReadPixels, TexImage1D,
TexImage2D, GetTexImage, TexImage3D, TexSubImage1D, TexSubImage2D,
TexSubImage3D, GetHistogram, GetMinmax, ConvolutionFilter1D,
ConvolutionFilter2D, ConvolutionFilter3D, GetConvolutionFilter,
SeparableFilter2D, GetSeparableFilter, ColorTable, ColorSubTable,
and GetColorTable if is UNSIGNED_INT_5_9_9_9_REV_EXT
and is not RGB.
New State
In table 6.17, Textures (page 278), increment the 42 in "n x Z42*"
by 1 for the RGB9_E5_EXT format.
[NOTE: The OpenGL 2.0 specification actually should read "n x Z48*"
because of the 6 generic compressed internal formats in table 3.18.]
Add the following entry to table 6.17:
Get Value Type Get Command Value Description Sec. Attribute
----------------------- ------ -------------------- ------- ------------------------------------ ---- ---------
TEXTURE_SHARED_SIZE_EXT n x Z+ GetTexLevelParameter 0 xD texture image i's shared exponent 3.8 -
field size
New Implementation Dependent State
None
Appendix
This source code provides ANSI C routines. It assumes the C "float"
data type is stored with the IEEE 754 32-bit floating-point format.
Make sure you define __LITTLE_ENDIAN or __BIG_ENDIAN appropriate
for your target system.
XXX: code below not tested on big-endian platform...
------------------- start of source code ------------------------
#include
#include
#include
#include
#define __LITTLE_ENDIAN 1
#define __BIG_ENDIAN 2
#ifdef _WIN32
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#define RGB9E5_EXPONENT_BITS 5
#define RGB9E5_MANTISSA_BITS 9
#define RGB9E5_EXP_BIAS 15
#define RGB9E5_MAX_VALID_BIASED_EXP 31
#define MAX_RGB9E5_EXP (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS)
#define RGB9E5_MANTISSA_VALUES (1< 0.0) {
if (x >= MAX_RGB9E5) {
return MAX_RGB9E5;
} else {
return x;
}
} else {
/* NaN gets here too since comparisons with NaN always fail! */
return 0.0;
}
}
float MaxOf3(float x, float y, float z)
{
if (x > y) {
if (x > z) {
return x;
} else {
return z;
}
} else {
if (y > z) {
return y;
} else {
return z;
}
}
}
/* Ok, FloorLog2 is not correct for the denorm and zero values, but we
are going to do a max of this value with the minimum rgb9e5 exponent
that will hide these problem cases. */
int FloorLog2(float x)
{
float754 f;
f.value = x;
return (f.field.biasedexponent - 127);
}
int Max(int x, int y)
{
if (x > y) {
return x;
} else {
return y;
}
}
rgb9e5 float3_to_rgb9e5(const float rgb[3])
{
rgb9e5 retval;
float maxrgb;
int rm, gm, bm;
float rc, gc, bc;
int exp_shared;
double denom;
rc = ClampRange_for_rgb9e5(rgb[0]);
gc = ClampRange_for_rgb9e5(rgb[1]);
bc = ClampRange_for_rgb9e5(rgb[2]);
maxrgb = MaxOf3(rc, gc, bc);
exp_shared = Max(-RGB9E5_EXP_BIAS-1, FloorLog2(maxrgb)) + 1 + RGB9E5_EXP_BIAS;
assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP);
assert(exp_shared >= 0);
/* This pow function could be replaced by a table. */
denom = pow(2, exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS);
maxm = (int) floor(maxrgb / denom + 0.5);
if (maxm == MAX_RGB9E5_MANTISSA+1) {
denom *= 2;
exp_shared += 1;
assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP);
} else {
assert(maxm <= MAX_RGB9E5_MANTISSA);
}
rm = (int) floor(rc / denom + 0.5);
gm = (int) floor(gc / denom + 0.5);
bm = (int) floor(bc / denom + 0.5);
assert(rm <= MAX_RGB9E5_MANTISSA);
assert(gm <= MAX_RGB9E5_MANTISSA);
assert(bm <= MAX_RGB9E5_MANTISSA);
assert(rm >= 0);
assert(gm >= 0);
assert(bm >= 0);
retval.field.r = rm;
retval.field.g = gm;
retval.field.b = bm;
retval.field.biasedexponent = exp_shared;
return retval;
}
void rgb9e5_to_float3(rgb9e5 v, float retval[3])
{
int exponent = v.field.biasedexponent - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS;
float scale = (float) pow(2, exponent);
retval[0] = v.field.r * scale;
retval[1] = v.field.g * scale;
retval[2] = v.field.b * scale;
}
------------------- end of source code ------------------------
Issues
1) What should this extension be called?
RESOLVED: EXT_texture_shared_exponent
The "EXT_texture" part indicates the extension is in the texture
domain and "shared_exponent" indicates the extension is adding
a new shared exponent formats.
EXT_texture_rgb9e5 was considered but there's no precedent for
extension names to be so explicit (or cryptic?) about format
specifics in the extension name.
2) There are many possible encodings for a shared exponent format.
Which encoding does this extension specify?
RESOLVED: A single 5-bit exponent stored as an unsigned
value biased by 15 and three 9-bit mantissas for each of 3
components. There are no sign bits so all three components
must be non-negative. The fractional mantissas assume an implied
0 left of the decimal point because having an implied leading
1 is inconsistent with sharing the exponent. Neither Infinity
nor Not-a-Number (NaN) are representable in this shared exponent
format.
We chose this format because it closely matches the range and
precision of the s10e5 half-precision floating-point described
in the ARB_half_float_pixel and ARB_texture_float specifications.
3) Why not an 8-bit shared exponent?
RESOLVED: Greg Ward's RGBE shared exponent encoding uses an
8-bit exponent (same as a single-precision IEEE value) but we
believe the rgb9e5 is more generally useful than rgb8e8.
An 8-bit exponent provides far more range than is typically
required for graphics applications. However, an extra bit
of precision for each component helps in situations where a
high magnitude component dominates a low magnitude component.
Having an 8-bit shared exponent and 8-bit mantissas are amenable
to CPUs that facilitate 8-bit sized reads and writes over non-byte
aligned fields, but GPUs do not suffer from this issue.
Indeed GPUs with s10e5 texture filtering can use that same
filtering hardware for rgb9e5 textures.
However, future extensions could add other shared exponent formats
so we name the tokens to indicate the
4) Should there be an external format and type for rgb9e5?
RESOLVED: Yes, hence the external format GL_RGB9_E5_EXT and
type GL_UNSIGNED_INT_5_9_9_9_REV_EXT. This makes it fast to load
GL_RGB9_E5_EXT textures without any translation by the driver.
5) Why is the exponent bias 15?
RESOLVED: The best technical choice of 15. Hopefully, this
discussion sheds insight into the numerics of the shared exponent
format in general.
With conventional floating-point formats, the number corresponding
to a finite, non-denorm, non-zero floating-point value is
value = -1^sgn * 2^(exp-bias) * 1.frac
where sgn is the sign bit (so 1 for sgn negative because -1^-1
== -1 and 0 means positive because -1^0 == +1), exp is an
(unsigned) BIASED exponent and bias is the format's constant bias
to subtract to get the unbiased (possibly negative) exponent;
and frac is the fractional portion of the mantissa with the
"1." indicating an implied leading 1.
An exp value of zero indicates so-called denormalized values
(denorms). With conventional floating-point formats, the number
corresponding to a denorm floating-point value is
value = -1^sgn * 2^(exp-bias+1) * 0.frac
where the only difference between the denorm and non-denorm case
is the bias is one greater in the denorm case and the implied
leading digit is a zero instead of a one.
Ideally, the rgb9e5 shared exponent format would represent
roughly the same range of finite values as the s10e5 format
specified by the ARB_texture_float extension. The s10e5 format
has an exponent bias of 15.
While conventional floating-point formats cleverly use an implied
leading 1 for non-denorm, finite values, a shared exponent format
cannot use an implied leading 1 because each component may have
a different magnitude for its most-significant binary digit.
The implied leading 1 assumes we have the flexibility to adjust
the mantissa and exponent together to ensure an implied leading 1.
That flexibility is not present when the exponent is shared.
So the rgb9e5 format cannot assume an implied leading one.
Instead, an implied leading zero is assumed (much like the
conventional denorm case).
The rgb9e5 format eliminate support representing negative,
Infinite, not-a-number (NaN), and denorm values.
We've already discussed how the BIASED zero exponent is used to
encode denorm values (and zero) with conventional floating-point
formats. The largest BIASED exponent (31 for s10e5, 127 for
s23e8) for conventional floating-point fomats indicates Infinity
and NaN values. This means these two extrema exponent values are
"off limits" for run-of-the-mill values.
The numbers corresponding to a shared exponent format value are:
value_r = 2^(exp-bias) * 0.frac_r
value_g = 2^(exp-bias) * 0.frac_g
value_b = 2^(exp-bias) * 0.frac_b
where there is no sgn since all values are non-negative, exp is
the (unsigned) BIASED exponent and bias is the format's constant
bias to subtract to get the unbiased (possibly negative) exponent;
and frac_r, frac_g, and frac_b are the fractional portion of
the mantissas of the r, g, and b components respectively with
"0." indicating an implied leading 0.
There should be no "off limits" exponents for the shared exponent
format since there is no requirement for representing Infinity
or NaN values and denorm is not a special case. Because of
the implied leading zero, any component with all zeros for its
mantissa is zero, no matter the shared exponent's value.
So the run-of-the-mill BIASED range of exponents for s10e5 is
1 to 30. But the rgb9e5 shared exponent format consistently
uses the same rule for all exponents from 0 to 31.
What exponent bias best allows us to represent the range of
s10e5 with the rgb9e5 format? 15.
Consider the maximum representable finite s10e5 magnitude.
The exponent would be 30 (31 would encode an Infinite or NaN
value) and the binary mantissa would be 1 followed by ten
fractional 1's. Effectively:
s10e5_max = 1.1111111111 * 2^(30-15)
= 1.1111111111 * 2^15
For an rgb9e5 value with a bias of 15, the largest representable
value is:
rgb9e5_max = 0.111111111 * 2^(31-15)
= 0.111111111 * 2^16
= 1.11111111 * 2^15
If you ignore two LSBs, these values are nearly identical.
The rgb9e5_max value is exactly representable as an s10e5 value.
For an rgb9e5 value with a bias of 15, the smallest non-zero
representable value is:
rgb9e5_min = 0.000000001 * 2^(0-15)
rgb9e5_min = 0.000000001 * 2^-15
rgb9e5_min = 0.0000000001 * 2^-14
So the s10e5_min and rgb9e5_min values exactly match (of course,
this assumes the shared exponent bias is 15 which might not be
the case if other components demand higher exponents).
8) Should there be an rgb9e5 framebuffer format?
RESOLVED: No. Rendering to rgb9e5 is better left to another
extension and would require the hardware to convert from a
(floating-point) RGBA value into an rgb9e5 encoding.
Interactions with EXT_framebuffer_object are specified,
but the expectation is this is not a renderable
format and glCheckFramebufferStatusEXT would return
GL_FRAMEBUFFER_UNSUPPORTED_EXT.
An implementation certainly could make this texture internal
format renderable when used with a framebuffer object. Note that
the shared exponent means masked components may be lossy in
their masking. For example, a very small but non-zero value in
a masked component could get flushed to zero if a large enough
value is written into an unmasked component.
9) Should automatic mipmap generation be supported for rgb9e5
textures?
RESOLVED: Yes.
10) Should non-texture and non-framebuffer commands for loading
pixel data accept the GL_UNSIGNED_INT_5_9_9_9_REV_EXT type?
RESOLVED: Yes.
Once the pixel path has to support the new type/format combination
of GL_UNSIGNED_INT_5_9_9_9_REV_EXT / GL_RGB for specifying and
querying texture images, it might as well be supported for all
commands that pack and unpack RGB pixel data.
The specification is written such that the glDrawPixels
type/format parameters are accepted by glReadPixels,
glTexGetImage, glTexImage2D, and other commands that are specified
in terms of glDrawPixels.
11) Should non-texture internal formats (such as for color tables,
convolution kernels, histogram bins, and min/max tables) accept
GL_RGB9_E5_EXT format?
RESOLVED: No.
That's pointless. No hardware is ever likely to support
GL_RGB9_E5_EXT internalformats for anything other than textures
and maybe color buffers in the future. This format is not
interesting for color tables, convolution kernels, etc.
12) Should a format be supported with sign bits for each component?
RESOLVED: No.
An srgb8e5 format with a sign bit per component could be useful
but is better left to another extension.
13) The rgb9e5 allows two 32-bit values encoded as rgb9e5 to
correspond to the exact same 3 components when expanded to
floating-point. Is this a problem?
RESOLVED: No, there's no problem here.
An encoder is likely to always pack components so at least
one mantissa will have an explicit leading one, but there's no
requirement for that.
Applications might be able to take advantage of this by quickly
dividing all three components by a power-of-two by simply
subtracting log2 of the power-of-two from the shared exponent (as
long as the exponent is greater than zero prior to the subtract).
Arguably, the shared exponent format could maintain a slight
amount of extra precision (one bit per mantissa) if the format
said if the most significant bits of all three mantissas are
either all one or all zero and the biased shared exponent was not
zero, then an implied leading 1 should be assumed and the shared
exponent should be treated as one smaller than it really is.
While this would preserve an extra least-significant bit of
mantissa precision for components of approximately the same
magnitude, it would complicate the encoding and decoding of
shared exponent values.
14) Can you provide some C code for encoding three floating-point
values into the rgb9e5 format?
RESOLVED: Sure. See the Appendix.
15) Should we support a non-REV version of the
GL_UNSIGNED_INT_5_9_9_9_REV_EXT token?
RESOLVED: No. The shared exponent is always the 5 most
significant bits of the 32 bit word. The first (red) mantissa
is in the least significant 9 bits, followed by 9 bits for the
second (green) mantissa, followed by 9 bits for the third (blue)
mantissa. We don't want to promote different arrangements of
the bitfields for rgb9e5 values.
16) Can you use the GL_UNSIGNED_INT_5_9_9_9_REV_EXT format with
just any format?
RESOLVED: You can only use the GL_UNSIGNED_INT_5_9_9_9_REV_EXT
format with GL_RGB. Otherwise, the GL generates
an GL_INVALID_OPERATION error. Conceptually,
GL_UNSIGNED_INT_5_9_9_9_REV_EXT is a 3-component format
that just happens to have 5 shared bits too. Just as the
GL_UNSIGNED_BYTE_3_3_2 format just works with GL_RGB (or else
the GL generates an GL_INVALID_OPERATION error), so should
GL_UNSIGNED_INT_5_9_9_9_REV_EXT.
17) What should GL_TEXTURE_SHARED_SIZE_EXT return when queried with
GetTexLevelParameter?
RESOLVED: Return 5 for the RGB9_E5_EXT internal format and 0
for all other existing formats.
This is a count of the number of bits in the shared exponent.
18) What should GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, and
GL_TEXTURE_BLUE_SIZE return when queried with GetTexLevelParameter
for a GL_RGB9_E5_EXT texture?
RESOLVED: Return 9 for each.
Revision History
Rev. Date Author Changes
---- -------- -------- --------------------------------------------
0.5 02/18/07 mjk Initial public version
1.0 07/18/08 mjk correct significant errors in spec language
and C code