blob: a080204134edf294ca67e83d3136f9f63941393e [file] [log] [blame]
XXX - Not complete yet!!!
Name Strings
$Date: 1999/04/03 08:41:11 $ $Revision: 1.3 $
This extension provides the means to define display color lookup tables
and associate them with rendering contexts. This is used primarily for
color gamut adjustment (e.g. gamma correction). It may also be used for
special effects like screen flashing, so it's important that creating
and binding tables be efficient.
Display color tables are an extension to the WGL window system interface
layer defined by Microsoft, not an OpenGL core extension. Because WGL
provides no built-in extension mechanism, the presence of the extension
is advertised through the OpenGL GL_EXTENSIONS string. Once the
extension is known to exist, the address of the entry points required
must be obtained via wglGetProcAddress().
There is an existing SetDeviceGammaRamp entry point in the Windows API.
It's apparently not implemented on NT, and only allows specifying 8-bit
LUT entries, which is inadequate for many applications. There may also
be concerns with the Windows API's ability to support secondary display
devices, like 3dfx Voodoo. Finally (as pointed out by Rendition),
putting gamma table definition in WGL allows the table updates to be
synchronized with the rest of the WGL/OpenGL command stream sent to
hardware, and to take place during vertical blanking.
* What do we do for devices that support the extension, but don't allow
changing their default ramp?
* We probably want LUT 0 to be whatever is defined by the system, not
default to a linear ramp.
* Are tables persistent (or would we like them to be persistent) across
application invocations, ala the XSGIvcSetChannelGammaMap calls?
* How do we signal errors in WGL? For the moment, I assume they return a
status value which is WGL_OK or an error indicating the problem.
* Use GL or Windows types for parameters? Consistency with
existing WGL calls indicates we should use Windows types.
* How are table IDs obtained (defined by the system or arbitrary app
choice)? How many tables are allowed?
* What should the format and mapping of table entries be? GLfloat (or
perhaps GLclampf?) would be easiest, but might present performance
issues. Rendition suggests that most devices use 8-bit LUTs, for
which unsigned byte entries is sufficient. It may make sense to
allow two formats (ubyte and ushort), like the XSGIvc GLX extension.
* Do we want some sort of enable/disable to make a drawable start using
the table?
* Do we need query functions to identify the table bound to the current
drawable and its contents?
* How much math describing the table lookup process is needed?
* What's the relative order of retrace, display table update, and buffer
swap? What happens when a drawable is rebound several times prior to
retrace (sure, the latest one takes effect, but should we be
* What happens when we have a frame buffer with different numbers of
bits for R, G, and B (e.g. 565 RGB)? Resampling as defined will
ensure that we get the right number of table entries, but the
definition implies that table entries for different color components
of the same intensity will actually be found at different indices!
This seems non-intuitive. Maybe specify tables for each component
New Procedures and Functions
GLboolean wglCreateDisplayColorTableEXT(GLushort id);
GLboolean wglLoadDisplayColorTableEXT(GLushort *table, GLuint length);
GLboolean wglBindDisplayColorTableEXT(GLushort id);
void wglDestroyDisplayColorTableEXT(GLushort id);
New Tokens
Additions to the WGL Specification (assuming WGL ever gets a spec)
wglStatus is an enumerated type representing success or failure codes
for WGL operations.
Display Color Tables
Display color tables provide a means for mapping color component
intensities in the video output hardware. Each RGB color component is
looked up in separate tables to produce a new output component.
Because display color tables are implemented in the output hardware,
they operate on the contents of the color buffer and do not appear in
the OpenGL state machine. They only operate on full-color pixel format
descriptors (PFDs).
Display color tables are associated with a drawable and ideally affect
only the pixels belonging to that drawable. However, hardware may be
restricted to a single global table, affecting all displayed pixels. In
this case, WGL is responsible for switching among multiple display color
tables so that the table corresponding to the currently selected
drawable is active. (We could definitely say more about how this
happens. Do we *want* to set policy, say by analogy to the GDI palette
manager? Does Windows let applications know when the focus has changed,
so that this is even possible?)
To create a display color table, call
wglStatus wglCreateDisplayColorTableEXT(GLuint id);
<id> is an identifier for the new table. If the table is successfully
created, TRUE is returned. The initial state of the table is a
two-element table with first element (0,0,0) and second element
(65535,65535,65535). This defines a linear table which has the effect of
passing frame buffer colors through unchanged.
WGL_OK is returned if the table is created. WGL_INVALID_VALUE is
returned if <id> refers to an existing color table, or if no more tables
can be created.
To bind a display color table, call
wglStatus wglBindDisplayColorTableEXT(GLuint id);
<id> is the identifier of a display color table created by
wglCreateDisplayColorTableEXT, or 0. If the table exists and can be
bound, WGL_OK is returned and the new table is bound to the drawable
associated with the current context. [The binding is *not* to the
context; this would make rebinding contexts to drawables very hairy.]
If the table does not exist, WGL_INVALID_VALUE is returned. If the table
cannot be bound, WGL_INVALID_OPERATION is returned. [What are the
failure modes? Color index PFDs? Drawables that are not Windows, like
printers and metafiles? Anything else?]
When a drawable is first created, display color table 0 is bound to it.
Table 0 is always present; its contents are the same two-element table
initially defined by wglCreateDisplayColorTableEXT. The contents of
table 0 cannot be changed. It may be rebound to a drawable at any time.
When a table is bound, it should take effect at the start of the next
vertical retrace interval. If the implementation cannot support this
behavior, the table should take effect immediately.
To redefine the contents of the display color table bound to the
drawable associated with the current rendering context, call
wglStatus wglLoadDisplayColorTableEXT(GLushort *table, GLuint length);
<table> points to an array of <length> 3-element entries. Each entry
defines color intensities for red, green, and blue components in that
order. The minimum display intensity (black) is represented by 0 and the
maximum display intensity is represented by the value 65535. [Say
something about nonlinearities in the output device? Probably not.]
When a table is redefined, the change takes effect in exactly the same
way as when a table is initially bound to a drawable.
WGL_OK is returned if the table is successfully reloaded. [Return
something if the table is unwriteable?]
To destroy a display color table, call
wglStatus wglDestroyDisplayColorTableEXT(GLushort id);
<id> is the identifier of a display color table. If the table exists and
is not bound to a drawable, it is removed and WGL_OK is returned. All
resources associated with the table are reclaimed.
If the table does not exist, or <id> is 0, no action is taken and
WGL_INVALID_VALUE is returned.
If the table exists but is bound to a drawable, no action is taken and
[Do we want to be able to destroy a bound table? Could just revert to
table 0. But this implies a search of all drawables, either at
destruction time or when they are made current or otherwise accessed.]
Mapping Display Color Table Entries To Hardware
Hardware table entries corresponding to the table specified by the
application are calculated whenever a table is created or reloaded with
wglLoadDisplayColorTableEXT. The size of hardware tables depends on the
bit resolution of the red, green, and blue color components, and may be
different than the number of table entries specified by the user.
The internal format of hardware tables is inaccessible. For purposes of
the abstract model presented here, it is assumed that table entries are
represented with the same number of bits as the corresponding color
buffer component.
In the remainder of this section, assume that B is a positive integer
defining the number of bits assigned to any one color component in the
frame buffer and N is the number of entries in the table (the <length>
parameter passed to wglLoadDisplayColorTableEXT). A color component C is
looked up by interpreting its binary bit pattern as an unsigned integer,
and using that value as an index into the appropriate red, green, or
blue hardware table. The hardware table entry at that index replaces C.
If 2**B == N, then there is a one-to-one correspondence between the
application table and the hardware table. Each element of the hardware
table is defined by rescaling the corresponding element of the
application table, according to the following algorithm:
for (i = 0; i < N; i++) {
for (c = 0; c < 3; c++)
hw_table[i][c] = app_table[i][c] * 2**B / 65535;
If 2**B != N, then there are more or fewer application table elements
than hardware table elements. Hardware elements are generated by
linearly interpolating the two closest application table elements
according to the following algorithm:
for (i = 0; i < 2**B; i++) {
float index = i * (N / (float)2**B);
float frac = index - floor(index);
for (c = 0; c < 3; c++)
hw_table[i][c] = app_table[floor(index)][c] * (1-frac) +
app_table[ceil(index)][c] * frac;
New State
Get Value Get Command Type Value Attrib
--------- ----------- ---- ------- ------
- - N*Z+ 2 - [table size]
- - N*table 0,0,0 - [tables]
New Implementation Dependent State