Chapter 12. Miscellaneous OpenGL Extensions

This chapter explains how to use several extensions that are not easily grouped with texturing, imaging, or GLX extensions. Example code is provided as needed. The following extensions are described:

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 function:

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

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

    
    

    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 a 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.The userData is a copy of the pointer that was specified at the last call to gluNurbsCallbackDataEXT().

The callbacks have the following formats:

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 12-1 provides additional information on each callback.

Table 12-1. NURBS Tessellator Callbacks and Their Description

Callback

Description

GLU_NURBS_BEGIN_EXT

GLU_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.

GLU_NURBS_VERTEX_EXT GLU_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.

GLU_NURBS_NORMAL_EXT GLU_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 you provide 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.

GLU_NURBS_COLOR_EXT GLU_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 you provide a color map (GL_MAP1_COLOR_4 or GL_MAP2_COLOR_4). The color value contains four components: R, G, B, or A.The default color() and colorData() callback functions are NULL.

GLU_NURBS_TEXCOORD_EXT GLU_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.

GLU_NURBS_END_EXT GLU_NURBS_END_DATA_EXT

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

GLU_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 of the following:

  • GLU_PATH_LENGTH

  • GLU_PARAMETRIC_ERROR

  • GLU_DOMAIN_DISTANCE

  • GLU_OBJECT_PATH_LENGTH_EXT

  • 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 12-2 contrasts the methods provided by the extension with the existing methods.

Table 12-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


Note: This extension is only supported on Fuel, Tezro, InfinitePerformance, and InfiniteReality systems.

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 format:

glListParameterfSGIX(uint list, enum pname, float params)

The parameters are defined as follows:

list 

The display list

pname 

GL_LIST_PRIORITY_SGIX

params 

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  glGetListParameterivSGIX(), which has the following format:

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

The parameters are defined as follows:

list 

The display list

pname 

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

The SGIX_list_priority extension introduces the following functions:

  • glListParameterSGIX()

  • glGetListParameterSGIX()

SGIX_instruments—The Instruments Extension


Note: This extension is only supported on InfiniteReality systems.

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

Why Use 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 the following:

    • 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 functions 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 describes 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 format:

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 formats:

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 the following 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 man page for glInstrumentsSGIX(). Currently, only InfiniteReality systems support any instruments.

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 format:

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 markerp. 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 format:

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 12-1 provides pseudo code for using the instruments extension.

Example 12-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

The SGIX_instruments extension introduces the following functions:

glInstrumentsBufferSGIX()

glStartInstrumentsSGIX()

glStopInstrumentsSGIX()

glReadInstrumentsSGIX()

glPollInstrumentsSGIX()

glGetInstrumentsSGIX()