XXX - Not complete yet!!! Name EXT_display_color_table Name Strings WGL_EXT_display_color_table Version $Date: 1999/04/03 08:41:11 $ $Revision: 1.3 $ Number 167 Dependencies None Overview 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. Issues * 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 precise?) * 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 separately? New Procedures and Functions GLboolean wglCreateDisplayColorTableEXT(GLushort id); GLboolean wglLoadDisplayColorTableEXT(GLushort *table, GLuint length); GLboolean wglBindDisplayColorTableEXT(GLushort id); void wglDestroyDisplayColorTableEXT(GLushort id); New Tokens None 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); 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 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); 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); points to an array of 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); 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 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 WGL_INVALID_OPERATION is returned. [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 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; } Errors TBD New State Initial Get Value Get Command Type Value Attrib --------- ----------- ---- ------- ------ - - N*Z+ 2 - [table size] - - N*table 0,0,0 - [tables] 65535,65535,65535 New Implementation Dependent State None