Chapter 13. Shaders

This chapter describes the OpenGL Shader, a mechanism which allows complex rendering equations to be applied to OpenGL Performer objects. See Chapter 14, “Using Scalable Graphics Hardware” for the use of fragment and vertex programs.

OpenGL Performer 3.0 introduces a completely new dynamic shader implementation. The OpenGL Performer 3.0 approach is provide a minimal wrapping of the OpenGL Shader API and to use OpenGL Shader to directly render shaded pfGeoSets.

The following description of the new API assumes an understanding of the OpenGL Shader API. OpenGL Shader is available at no charge at the following URL: http://www.sgi.com/software/shader. OpenGL Shader documentation is installed in the directory /usr/share/shader/doc/developer on IRIX and Linux and in %PFROOT\shader\doc\developer on Microsoft Windows.

The OpenGL Performer and OpenGL Shader integration is documented in the following OpenGL Performer man pages:

Setting Up Shaded pfGeoSets

In the OpenGL Shader API, an islAppearance embodies the complete description of the appearance of an object and that appearance can be applied to a pfGeoSet. A pfGeoSet gains the following functions:

pfGeoSet::setAppearance(islAppearance *appearance); 
islAppearance* pfGeoSet::getAppearance(); 

These functions set and query the appearance that renders a pfGeoSet. The islAppearances are mutually exclusive with pfGeoStates; hence, only one of the two can be used to define the appearance of the pfGeoSet. To preserve the pfGeoSet cache-line behavior, the islAppearance and the pfGeoState share the same pointer. Hence, adding an appearance to a pfGeoSet removes the pfGeoState and conversely so.

Because OpenGL Performer only minimally wraps the OpenGL shader API, OpenGL Performer cannot indicate when run-time parameters are changed on any islShaders contained within the islAppearance. Shader changes cannot be propagated in the APP process to the DRAW without knowing run-time parameters. Therefore, the following two functions are available to solve this problem:

pfAppearanceChanged(islAppearance *appearance); 
pfShaderChanged(islAppearance *appearance, islShader *shader);

The pfShaderChanged() function tells OpenGL Performer that the parameters of the specified shader within the specified appearance have changed. The function pfAppearanceChanged() tells OpenGL Performer that the specified appearance has changed (that is, that shaders have been added or removed

Textures and Texture Coordinates

OpenGL Shader is a callback-based API that calls user-supplied functions to apply textures and to draw geometry with specific texture coordinates. OpenGL Performer supplies its own internal functions for these callbacks in order to render shaded pfGeoSets and perform internal bookkeeping of the resources that OpenGL Shader uses. As a result, when using OpenGL Shader within OpenGL Performer, you must use callbacks "friendly" to OpenGL Performer in order to specify textures and texture coordinates. The following API allows you to do this:

pfShaderTexCoordFunc(islAppearance *a, pfTexCoordCallbackType *func, void *udata)
pfShaderTexApplyFunc(islAppearance *a, pfTexApplyCallbackType *func, void *udata)
pfShaderTexComputeFunc(islAppearance *a, int where, pfTexComputeCallbackType *func, void *udata)
typedef int (*pfTexApplyCallbackType)(const islAppearance *app, const char *texName,void *userData);
typedef void (*pfTexComputeCallbackType)(pfISLTexCoordData *d, const char *texName, void *userData);
typedef pfVec2* (*pfTexCoordCallbackType)(pfISLTexCoordData *d, const float texCoordID, void *userData);					 

The function pfShaderTexCoordFunc() allows you to specify a callback to invoke whenever the specified islAppearance requests geometry to be drawn with specific texture coordinates. This callback is analogous to the islShape::setDrawGeometryFunc() OpenGL Shader function

One of the parameters that OpenGL Performer passes into your callback is a pointer to a pfISLTexCoordData class. This class holds data that is useful in computing the requested texture coordinates such as the pfGeoSet that is being rendered, the islAppearance that triggered the callback, the modelview matrix, and others. See the pfISLTexCoordData man page for a description of this class.

Your callback will return a set of texture coordinates for OpenGL Performer to use in place of those already on the pfGeoSet. When allocating new coordinates per-frame, allocate the memory with the pfISLTexCoordData class that OpenGL Performer passed in. This memory is automatically deallocated when OpenGL Performer finishes with it.

The function pfShaderTexComputeFunc() allows you to set an optional callback that is invoked to compute the specified texture. This callback offloads the work of generating procedural textures from the DRAW process if possible. OpenGL Performer queries the OpenGL Shader ahead of time about which textures it will request in the DRAW process and will try to call your callback in the CULL process. The parameters that are passed into this callback are the same as for the pfShaderTexCoordFunc() function described in the preceding paragraph.

The function pfShaderTexApplyFunc() is called whenever OpenGL Shader asks for a texture to be applied. This callback is analogous to the islDrawAction::setLoadTextureFunc() OpenGL Shader function. When invoking this callback, OpenGL Performer passes in the islAppearance that requested the texture, the name of the texture, and whatever user data specified to pfShaderTexApplyFunc(). This function returns the number of texture dimensions (1, 2, or 3). When calling this function, OpenGL Performer attempts to do so in the CULL process.

OpenGL Shader and OpenGL Performer

As of OpenGL Performer 3.0, the OpenGL Shader library performs all of the rendering state management for pfGeoSets that have been assigned an islAppearance; OpenGL Performer draws the appropriate pfGeoSets when the OpenGL Shader library calls the OpenGL Performer DrawGeometry callback.

The rendering of a shaded pfGeoSet has the following flow through OpenGL Performer:

  1. A new islAppearance is created and compiled.

    For more details, see the OpenGL Shader documentation installed in the directory /usr/share/shader/doc/developer on IRIX and Linux and in %PFROOT\shader\doc\developer on Microsoft Windows.

  2. The newly created islAppearance is assigned to a pfGeoSet.

    OpenGL Performer uses an OpenGL Shader islCopyAction to create a shared-memory representation of the islAppearance, which can be used in processes other than the APP process.

  3. In the CULL process, OpenGL Performer computes the correct shader matrix and passes it to each islShader that comprises the islAppearanceCopy that was just created.

  4. OpenGL Performer uses the OpenGL Shader islSnapshotAction to create an islAppearanceSnapshot from the islAppearanceCopy in the previous step.

    The islSnapshotAction tells OpenGL Performer which sets of texture coordinates will be required at DRAW time so that OpenGL Performer can call any callbacks that have been registered with the pfShaderTexComputeFunc() and pfShaderTexCoordFunc() functions.

  5. At DRAW time, OpenGL Performer creates an islShape and an islDrawAction and invoke  islShape::draw().

    Each time islDrawAction requests that the shaded objects be drawn, OpenGL Performer draws the corresponding pfGeoSets using any data that was computed using the user callbacks invoked in the previous step. If the islDrawAction requests that any textures be applied, OpenGL Performer calls any functions registered by using the pfShaderTexApplyFunc() function to do the job.