Chapter 11. Miscellaneous OpenGL Extensions

This chapter explains how to use several extensions that are not easily grouped with texturing, imaging, or GLX extensions, providing example code as needed. You learn about:

GLU_EXT_NURBS_tessellator—The NURBS Tessellator Extension

The NURBS tessellator extension, GLU_EXT_nurbs_tessellator, is a GLU extension that allows applications to retrieve the results of a tessellation. The NURBS tessellator is similar to the GLU polygon tessellator; see “Polygon Tessellation,” starting on page 410 of the OpenGL Programming Guide, Second Edition.

NURBS tessellation consists of OpenGL Begin, End, Color, Normal, Texture, and Vertex data. This feature is useful for applications that need to cache the primitives to use their own advanced shading model, or to accelerate frame rate or perform other computations on the tessellated surface or curve data.

Using the NURBS Tessellator Extension

To use the extension, follow these steps:

  1. Define a set of callbacks for a NURBS object using this command:

    void gluNurbsCallback(GLUnurbsObj *nurbsObj, GLenum which,
                         void (*fn)()); 
    

    The parameter which can be either GLU_ERROR or a data parameter or nondata parameter, one of the following:

    
    

    GLU_NURBS_BEGIN_EXT

    GLU_NURBS_BEGIN_DATA_EXT

    GLU_NURBS_VERTEX_EXT

    GLU_NURBS_VERTEX_DATA_EXT

    GLU_NORMAL_EXT

    GLU_NORMAL_DATA_EXT

    GLU_NURBS_COLOR_EXT

    GLU_NURBS_COLOR_DATA_EXT

    GLU_NURBS_TEXTURE_COORD_EXT

    GLU_NURBS_TEXTURE_COORD_DATA _EXT

    GLU_END_EXT

    GLU_END_DATA_EXT


  2. Call gluNurbsProperty() with a property parameter of GLU_NURBS_MODE_EXT and value parameter of GLU_NURBS_TESSELLATOR_EXT or GLU_NURBS_RENDERER_EXT.

    In rendering mode, the objects are converted or tessellated to a sequence of OpenGL primitives, such as evaluators and triangles, and sent to the OpenGL pipeline for rendering. In tessellation mode, objects are converted to a sequence of triangles and triangle strips and returned to the application through a callback interface for further processing. The decomposition algorithms used for rendering and for returning tessellations are not guaranteed to produce identical results.

  3. Execute your OpenGL code to generate the NURBS curve or surface (see “A Simple NURBS Example” on page 455 of the OpenGL Programming Guide, Second Edition.)

  4. During tessellation, your callback functions are called by OpenGL, with the tessellation information defining the NURBS curve or surface.

Callbacks Defined by the Extension

There are two forms of each callback defined by the extension: one with a pointer to application supplied data and one without. If both versions of a particular callback are specified, the callback with userData will be used. userData is a copy of the pointer that was specified at the last call to gluNurbsCallbackDataEXT().

The callbacks have the following prototypes:

void begin(GLenum type);
void vertex(GLfloat *vertex);
void normal(GLfloat *normal);
void color(GLfloat *color);
void texCoord(GLfloat *texCoord);
void end(void);
void beginData(GLenum type, void* userData);
void vertexData(GLfloat *vertex, void* userData);
void normalData(GLfloat *normal, void* userData);
void colorData(GLfloat *color, void* userData);
void texCoordData(GLfloat *texCoord, void* userData);
void endData(void* userData);
void error(GLenum errno);

The first 12 callbacks allows applications to get primitives back from the NURBS tessellator when GLU_NURBS_MODE_EXT is set to GLU_NURBS_TESSELLATOR_EXT.

These callbacks are not made when GLU_NURBS_MODE_EXT is set to GLU_NURBS_RENDERER_EXT.

All callback functions can be set to NULL even when GLU_NURBS_MODE_EXT is set to GLU_NURBS_TESSELLATOR_EXT. When a callback function is set to NULL, this function will not be invoked and the related data, if any, will be lost.

Table 11-1 provides additional information on each callback.

Table 11-1. NURBS Tessellator Callbacks and Their Description

Callback

Description

GL_NURBS_BEGIN_EXT

GL_NURBS_BEGIN_DATA_ EXT

Indicates the start of a primitive. type is one of GL_LINES, GL_LINE_STRIPS, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP, GL_TRIANGLES, or GL_QUAD_STRIP.

The default begin() and beginData() callback functions are NULL.

GL_NURBS_VERTEX_EXT GL_NURBS_VERTEX_DATA_ EXT

Indicates a vertex of the primitive. The coordinates of the vertex are stored in the parameter vertex. All the generated vertices have dimension 3, that is, homogeneous coordinates have been transformed into affine coordinates.

The default vertex() and vertexData() callback functions are NULL.

GL_NURBS_NORMAL_EXT GL_NURBS_NORMAL_DATA_ EXT

Is invoked as the vertex normal is generated. The components of the normal are stored in the parameter normal. In the case of a NURBS curve, the callback function is effective only when the user provides a normal map (GLU_MAP1_NORMAL). In the case of a NURBS surface, if a normal map (GLU_MAP2_NORMAL) is provided, then the generated normal is computed from the normal map. If a normal map is not provided, then a surface normal is computed in a manner similar to that described for evaluators when GL_AUTO_NORMAL is enabled. The default normal() and normalData() callback functions are NULL.

GL_NURBS_COLOR_EXT GL_NURBS_COLOR_DATA_ EXT

Is invoked as the color of a vertex is generated. The components of the color are stored in the parameter color. This callback is effective only when the user provides a color map (GL_MAP1_COLOR_4 or GL_MAP2_COLOR_4). color contains four components: R, G, B, or A.The default color() and colorData() callback functions are NULL.

GL_NURBS_TEXCOORD_EXT GL_NURBS_TEXCOORD_ DATA_EXT

Is invoked as the texture coordinates of a vertex are generated. These coordinates are stored in the parameter tex_coord. The number of texture coordinates can be 1, 2, 3, or 4 depending on which type of texture map is specified (GL_MAP*_TEXTURE_COORD_1, GL_MAP*_TEXTURE_COORD_2, GL_MAP*_TEXTURE_COORD_3, GL_MAP*_TEXTURE_COORD_4 where * can be either 1 or 2). If no texture map is specified, this callback function will not be called.

The default texCoord() and texCoordData() callback functions are NULL.

GL_NURBS_END_EXT GL_NURBS_END_DATA_EXT

Is invoked at the end of a primitive. The default end() and endData() callback functions are NULL.

GL_NURBS_ERROR_EXT

Is invoked when a NURBS function detects an error condition. There are 37 errors specific to NURBS functions. They are named GLU_NURBS_ERROR1 through GLU_NURBS_ERROR37. Strings describing the meaning of these error codes can be retrieved with gluErrorString().


GLU_EXT_object_space—The Object Space Tess Extension

The object space tess extension, GLU_EXT_object_space_tess, adds two object space tessellation methods for GLU nurbs surfaces. NURBS are discussed in the section “The GLU NURBS Interface” on page 455 of the OpenGL Programming Guide, Second Edition.

The existing tessellation methods GLU_PATH_LENGTH and GLU_PARAMETRIC_ERROR are view dependent because the error tolerance is measured in the screen space (in pixels). The extension provides corresponding object space tessellation methods that are view-independent in that the error tolerance measurement is in the object space.

GLU_SAMPLING_METHOD specifies how a NURBS surface should be tessellated. The value parameter may be set to one of GLU_PATH_LENGTH, GLU_PARAMETRIC_ERROR, GLU_DOMAIN_DISTANCE, GLU_OBJECT_PATH_LENGTH_EXT, or GLU_OBJECT_PARAMETRIC_ERROR_EXT.

To use the extension, call gluNurbsProperty() with an argument of GLU_OBJECT_PATH_LENGTH_EXT or GLU_OBJECT_PARAMETRIC_ERROR_EXT. Table 11-2 contrasts the methods provided by the extension with the existing methods.

Table 11-2. Tessellation Methods

Method

Description

GLU_PATH_LENGTH

The surface is rendered so that the maximum length, in pixels, of edges of the tessellation polygons is no greater than what is specified by GLU_SAMPLING_TOLERANCE.

GLU_PARAMETRIC_ERROR

The surface is rendered in such a way that the value specified by GLU_PARAMETRIC_TOLERANCE describes the maximum distance, in pixels, between the tessellation polygons and the surfaces they approximate.

GLU_DOMAIN_DISTANCE

Allows you to specify, in parametric coordinates, how many sample points per unit length are taken in u, v dimension.

GLU_OBJECT_PATH_LENGTH_ EXT

Similar to GLU_PATH_LENGTH except that it is view independent; that is, it specifies that the surface is rendered so that the maximum length, in object space, of edges of the tessellation polygons is no greater than what is specified by GLU_SAMPLING_TOLERANCE.

GLU_OBJECT_PARAMETRIC_ ERROR_EXT

Similar to GLU_PARAMETRIC_ERROR except that it is view independent; that is, it specifies that the surface is rendered in such a way that the value specified by GLU_PARAMETRIC_TOLERANCE describes the maximum distance, in object space, between the tessellation polygons and the surfaces they approximate.

The default value of GLU_SAMPLING_METHOD is GLU_PATH_LENGTH.

GLU_SAMPLING_TOLERANCE specifies the maximum distance, in pixels or in object space when the sampling method is set to GLU_PATH_LENGTH or GLU_OBJECT_PATH_LENGTH_EXT. The default value for GLU_SAMPLING_TOLERANCE is 50.0.

GLU_PARAMETRIC_TOLERANCE specifies the maximum distance, in pixels or in object space when the sampling method is set to GLU_PARAMETRIC_ERROR or GLU_OBJECT_PARAMETRIC_ERROR_EXT. The default value for GLU_PARAMETRIC_TOLERANCE is 0.5.

SGIX_list_priority—The List Priority Extension

The list priority extension, SGIX_list_priority, provides a mechanism for specifying the relative importance of display lists. This information can be used by an OpenGL implementation to guide the placement of display list data in a storage hierarchy, that is, lists that have higher priority reside in “faster” memory and are less likely to be swapped out to make space for other lists.

Using the List Priority Extension

To guide the OpenGL implementation in determining which display lists should be favored for fast executions, applications call glListParameter*SGIX(), which has the following prototype:

glListParameterfSGIX(uint list, enum pname, float params)

where

  • list is set to the display list.

  • pname is set to GL_LIST_PRIORITY_SGIX.

  • params is set to the priority value.

The priority value is clamped to the range [0.0, 1.0] before it is assigned. Zero indicates the lowest priority, and hence the least likelihood of optimal execution. One indicates the highest priority, and hence the greatest likelihood of optimal execution.

Attempts to prioritize nonlists are silently ignored. Attempts to prioritize list 0 generates a GL_INVALID_VALUE error.

To query the priority of a list, call glGetListParameterfvSGIX(), which has the following prototype:

glGetListParameterivSGIX(uint list, enum pname, int *params)

where:

  • list is set to the list.

  • pname is set to GL_LIST_PRIORITY_SGIX.

If list is not defined, then the value returned is undefined.


Note: On InfiniteReality systems, it makes sense to give higher priority to those display lists that are changed frequently.


New Functions

glListParameterSGIX, glGetListParameterSGIX

SGIX_instruments—The Instruments Extension

The instruments extension, SGIX_instruments, allows applications to gather and return performance measurements from within the graphics pipeline by adding instrumentation.

About SGIX_instruments

There are two reasons for using the instruments extension:

  • Load monitoring. If you know that the pipeline is stalled or struggling to process the amount of data passed to it so far, you can take appropriate steps, such as these:

    • Reduce the level of detail of the remaining objects in the current frame or the next frame.

    • Adjust the framebuffer resolution for the next frame if video resize capability is available.

  • Tuning. The instrumentation may give you tuning information; for example, it may provide information on how many triangles were culled or clipped before being rasterized.

Load monitoring requires that the instrumentation and the access of the measurements be efficient, otherwise the instrumentation itself will reduce performance more than any load-management scheme could hope to offset. Tuning does not have the same requirements.

The instruments extension provides a call to set up a measurements return buffer, similar to the feedback buffer. However, unlike feedback and selection (see glSelectBuffer() and glFeedbackBuffer()), the instruments extension provides commands that allow measurements to be delivered asynchronously, so that the graphics pipeline need not be stalled while measurements are returned to the client.

Note that the extension provides an instrumentation framework, but no instruments. The set of available instruments varies between OpenGL implementations, and can be determined by querying the GL_EXTENSIONS string returned by glGetString() for the names of the extensions that implement the instruments.

Using the Extension

This section discusses using the extension in the following subsections:

Specifying the Buffer

To specify a buffer in which to collect instrument measurements, call glInstrumentsBufferSGIX() with size set to the size of the buffer as a count of GLints. The function has the following prototype:

void glInstrumentsBufferSGIX( GLsizei size, GLint *buffer )

The buffer will be prepared in a way that allows it to be written asynchronously by the graphics pipeline.

If the same buffer was specified on a previous call, the buffer is reset; that is, measurements taken after the call to glInstrumentsBufferSGIX() are written to the start of the buffer.

If buffer is zero, then any resources allocated by a previous call to prepare the buffer for writing will be freed. If buffer is non-zero, but is different from a previous call, the old buffer is replaced by the new buffer and any allocated resources involved in preparing the old buffer for writing are freed.

The buffer address can be queried with glGetPointerv() using the argument GL_INSTRUMENT_BUFFER_POINTER_SGIX (note that glGetPointerv() is an OpenGL 1.1 function).

Enabling, Starting, and Stopping Instruments

To enable an instrument, call glEnable() with an argument that specifies the instrument. The argument to use for a particular instrument is determined by the OpenGL extension that supports that instrument. (See “Instruments Example Pseudo Code”.)

To start the currently enabled instrument(s), call glStartInstrumentsSGIX(). To take a measurement, call glReadInstrumentsSGIX(). To stop the currently-enabled instruments and take a final measurement call glStopInstrumentsSGIX(). The three functions have the following prototypes:

void glStartInstrumentsSGIX( void )
void glReadInstrumentsSGIX( GLint marker )
void glStopInstrumentsSGIX( GLint marker )

The marker parameter is passed through the pipe and written to the buffer to ease the task of interpreting it.

If no instruments are enabled executing glStartInstrumentsSGIX(), glStopInstrumentsSGIX(), or glReadInstruments() will not write measurements to the buffer.

Measurement Format

The format of any instrument measurement in the buffer obeys certain conventions:

  • The first word of the measurement is the glEnable() enum for the instrument itself.

  • The second word of the measurement is the size in GLints of the entire measurement. This allows any parser to step over measurements with which it is unfamiliar. Currently there are no implementation-independent instruments to describe.

    Implementation-dependent instruments are described in the Machine Dependencies section of the reference page for glInstrumentsSGIX. Currently, only InfiniteReality systems support any extensions.

In a single measurement, if multiple instruments are enabled, the data for those instruments can appear in the buffer in any order.

Retrieving Information

To query the number of measurements taken since the buffer was reset, call glGet() using GL_INSTRUMENT_MEASUREMENTS_SGIX.

To determine whether a measurement has been written to the buffer, call glPollInstrumentsSGIX(), which has the following prototype:

GLint glPollInstrumentsSGIX( GLint *markerp )

If a new measurement has appeared in the buffer since the last call to glPollInstrumentsSGIX(), 1 is returned, and the value of marker associated with the measurement by glStopInstrumentsSGIX() or glReadInstrumentsSGIX() is written into the variable referenced by marker_p. The measurements appear in the buffer in the order in which they were requested. If the buffer overflows, glPollInstrumentsSGIX() may return -1 as soon as the overflow is detected, even if the measurement being polled did not cause the overflow. (An implementation may also choose to delay reporting the overflow until the measurement that caused the overflow is the one being polled.) If no new measurement has been written to the buffer, and overflow has not occurred, glPollInstrumentsSGIX() returns 0.

Note that while in practice an implementation of the extension is likely to return markers in order, this functionality is not explicitly required by the specification for the extension.

To get a count of the number of new valid GLints written to the buffer, call glGetInstrumentsSGIX(), which has the following prototype:

GLint glGetInstrumentsSGIX( void )

The value returned is the number of GLints that have been written to the buffer since the last call to glGetInstrumentsSGIX() or glInstrumentsBufferSGIX(). If the buffer has overflowed since the last call to glGetInstrumentsSGIX(), -1 is returned for the count. Note that glGetInstrumentsSGIX() can be used independently of glPollInstrumentsSGIX().

Instruments Example Pseudo Code

Example 11-1. Instruments Example Pseudo Code


#ifdef GL_SGIX_instruments
          #define MARKER1 1001
          #define MARKER2 1002
          {
             static GLint buffer[64];
             GLvoid *bufp;
             int id, count0, count1, r;

             /* define the buffer to hold the measurements */
             glInstrumentsBufferSGIX(sizeof(buffer)/sizeof(GLint), buffer);

             /* enable the instruments from which to take measurements */
             glEnable(<an enum for a supported instrument, such as
                      GL_IR_INSTRUMENT1_SGIX>);

             glStartInstrumentsSGIX();
             /* insert GL commands here */
             glReadInstrumentsSGIX(MARKER1);
             /* insert GL commands here */
             glStopInstrumentsSGIX(MARKER2);

             /* query the number of measurements since the buffer was specified*/
             glGetIntegerv(GL_INSTRUMENT_MEASUREMENTS_SGIX,&r);
                 /* now r should equal 2 */

             /* query the pointer to the instrument buffer */
             glGetPointervEXT(GL_INSTRUMENT_BUFFER_SGIX,&bufp);
                 /* now bufp should be equal to buffer */

             /*
              * we can call glGetInstrumentsSGIX before or after the calls to
              * glPollInstrumentsSGIX but to be sure of exactly what
              * measurements are in the buffer, we can use PollInstrumentsSGIX.
              */
             count0 = glGetInstrumentsSGIX();
             /* Since 0, 1, or 2 measurements might have been returned to
              * the buffer at this point, count0 will be 0, 1, or 2 times
              * the size in GLints of the records returned from the
              * currently-enabled instruments.
              * If the buffer overflowed, count0 will be -1.
              */

             while (!(r = glPollInstrumentsSGIX(&id))) ;
             /* if r is -1, we have overflowed.  If it is 1, id will
              * have the value of the marker passed in with the first
              * measurement request (should be MARKER1).  While it is 0,
              * no measurement has been returned (yet).
              */

             while (!(r = glPollInstrumentsSGIX(&id))) ;
             /* see the note on the first poll; id now should equal MARKER2 */


             count1 = glGetInstrumentsSGIX();
             /* the sum of count0 and count1 should be 2 times the size in GLints
              * of the records returned for all instruments that we have enabled.
              */
          }
          #endif

New Functions

glInstrumentsBufferSGIX, glStartInstrumentsSGIX, glStopInstrumentsSGIX, glReadInstrumentsSGIX, glPollInstrumentsSGIX, glGetInstrumentsSGIX