| 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); |
| |
| <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 |
| 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 <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; |
| } |
| |
| 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 |