OpenGL Distilled

7.1. Extensions

OpenGL provides an extension mechanism to expose new graphics features that aren't part of the OpenGL core standard. Each OpenGL extension has a unique name that identifies it at both compile time and runtime. An extension specification defines the extension behavior. Applications usually interact with an extension using a set of new enumerants and commands. It's common for applications to access nonstandard functionality using the extension mechanism.

OpenGL features three types of extensions:

  • OpenGL vendors create vendor-specific extensions to expose functionality specific to their OpenGL implementation. Typically, the extension is available only in implementations from a single vendor.

    Vendor-specific extension enumerants and commands are suffixed with a brief sequence of characters, which serve both to identify the vendor and to indicate that they are part of an extension interface. For example, the ATI bump mapping extension, GL_ATI_envmap_bumpmap, contains enumerants like GL_BUMP_ENVMAP_ATI and GL_BUMP_TARGET_ATI, and commands such as glTexBumpParameterivATI().

  • EXT extensions are vendor extensions adopted by more than one vendor. If the EXT extension evolved from a vendor-specific extension, its specification typically is more refined and generalized. EXT extension enumerants and command names are suffixed with EXT.

  • Extensions approved by the OpenGL ARB are called ARB extensions. They typically are available in a wide range of OpenGL implementations. A working group of interested ARB members creates ARB extension specifications, which must be approved by a majority vote of ARB voting members. ARB extension enumerants and command names are suffixed with ARB.

Vendor-specific, EXT, and ARB extensions differ only in their implied availability. ARB extensions are expected to be more widely supported than EXT extensions, which are more widely supported than vendor-specific extensions. Applications use the same method to access all extensions, regardless of the extension type.

The OpenGL extension mechanism is intended to be a refinement process for new OpenGL features. Typically, an OpenGL vendor develops a new feature and exposes it as a vendor-specific extension. If the feature is well received by developers, it evolves to EXT status and then to ARB status, and perhaps eventually becomes part of the OpenGL core in a new OpenGL version. After an extension is added to the core, the enumerant and command names are stripped of their extension-specific suffixes.

For backward compatibility, OpenGL implementations often expose the same feature through several different interfaces. It's not uncommon, for example, for an OpenGL implementation to support cube mapping through the core 1.3 interface, the GL_ARB_texture_cube_map ARB extension interface, and the GL_EXT_texture_cube_map EXT extension interface.

Ideally, you should use the latest available interface for a given feature. The latest interface might not be available on all platforms, however. As an application developer, you need to choose which of several interfaces to use. If your application runs on multiple platforms, and not all platforms support a given OpenGL feature with the latest interface, your application should fall back to an older interface to access the same functionality or fall back to a code path that doesn't use the feature.

Specifications for several OpenGL extensions are available at the OpenGL Extension Registry Web site (http://oss.sgi.com/projects/ogl-sample/registry/). Like The OpenGL Graphics System, extension specifications are written for OpenGL vendors but also provide valuable information for application developers. Typically, OpenGL vendors provide extension documentation geared to developers as part of their development environment package.

To build an application that uses a specific extension, you need the extension enumerant definitions and command prototypes in your development environment. Typically, OpenGL vendors provide these definitions and declarations in a platform-specific OpenGL development environment package, sometimes referred to as a software development kit (SDK). Optionally, you can create your own development environment using the glext.h header file available from the OpenGL Extension Registry.

To access an extension, you need to do the following:

  • To determine whether you can use an extension, query the OpenGL implementation at runtime for extension support.

  • Obtain and call function pointers for extension-specific commands. Use extension-specific commands and enumerants only if the extension is supported at runtime.

The following sections cover these topics.

7.1.1. Querying for an Extension

Use glGetString( GL_EXTENSIONS ) to obtain a list of supported extensions. As covered in Chapter 1, "An Introduction to OpenGL," glGetString() returns a GLubyte*a C-style string. When called with the GL_EXTENSIONS parameter, glGetString() returns a space-separated list of extension names, one for each extension supported at runtime by the underlying OpenGL implementation. To determine whether a specific extension is supported, search for the extension name in the returned extension string. Because an extension name could be a substring of another extension name, your application should parse the extension string into individual names and look for an exact match.

The following function demonstrates how to parse an OpenGL extension string correctly. The first parameter is the name of an extension to search for; the second parameter is an extension string as obtained with a call to glGetString( GL_EXTENSION ). The function returns true or false to indicate whether the extension is supported. It uses the C++ Standard Template Library std::string class to facilitate parsing the extension string.

bool isExtensionSupported( const std::string& name, const GLubyte* extensions ) { std::string extStr( extensions ); while ( !extStr.empty() ) { int idx = extStr.find_first_of( ' ' ); std::string ext = extStr.substr( 0, idx ); if (name == ext) return true; extStr.erase( 0, idx+1 ); } return false; }

Call this function with the extension name as the first parameter and the OpenGL extension string as the second parameter. The following code, for example, shows how to search for the presence of the GL_ARB_pixel_buffer_object extension:

const bool usePBO = isExtensionSupported( Std::string( "GL_ARB_pixel_buffer_object" ), glGetString( GL_EXTENSIONS ) );

If an extension is supported in the underlying OpenGL implementation, your application is free to use the extension enumerants and commands. If the extension isn't supported, using an extension enumerant generates an OpenGL error (use glGetError() to catch it), and using extension commands could cause an application crash.

Note

If your application needs to make a copy of the entire extension string, avoid copying the string to a fixed-size buffer (by using strcpy(), for example). The extension string varies widely in size from one implementation to the next. As a result, the copy operation could succeed on your development platform but overrun the fixed-size buffer when deployed to customers and cause an application crash.

7.1.2. Obtaining and Calling Extension Commands

As discussed in Chapter 1, "An Introduction to OpenGL," an OpenGL implementation typically is a library, and your application interacts with OpenGL by calling library entry points. In an ideal world, the OpenGL version and supported extensions would be identical in all end-user runtime environments, and would match the version and supported extensions in your build environment, but this is rarely the case for professional applications. Consider deploying a single OpenGL application on several end-user systems with OpenGL implementations from a variety of vendors. Because the set of supported extensions varies from one platform to the next, it's impossible to create an executable that resolves all entry points at link time.

Most OpenGL libraries support dynamic rather than static linking, however, and most platforms provide a mechanism to obtain the address of an entry point in a dynamically loaded library. This enables your application to obtain OpenGL function pointers at runtime rather than resolve all symbols at link time.

How you obtain extension entry points depends on your runtime platform. The next few sections describe how to obtain extension entry points for the Linux, Microsoft Windows, and Apple Mac OS X operating systems.

7.1.2.1. Obtaining Entry Points for Linux

Linux operating systems support a set of three functions for opening, obtaining symbols from, and closing a dynamic library. To open a dynamic library and obtain a handle to it, call dlopen(). After you have a handle, call dlsym() as needed to obtain the address of entry points. When you have obtained all the entry-point addresses required by your application, call dlclose(). Some applications use this interface to obtain extension entry points. For documentation on this interface, see the man pages for dlopen, dlsym, and dlclose.

Most Linux platforms, however, use Mesa, which provides GLX version 1.4 support. In GLX version 1.4, applications obtain an entry-point address with a single call to glXGetProcAddress().

typedef void (*GLfunction)( void );

extern GLfunction glXGetProcAddress( const GLubyte* procName );

Returns the address of an OpenGL entry point. procName specifies the name of the desired entry point. If the entry point doesn't exist (for example, the extension isn't supported at runtime), glXGetProcAddress() returns NULL.

You should typecast the return value to the appropriate function pointer type before calling through it.

Because glXGetProcAddress() is available in GLX version 1.4, you should use the C preprocessor symbol GLX_VERSION_1_4 to ensure that your development environment supports version 1.4 before using this command:

#ifdef GLX_VERSION_1_4 // OK to call glXGetProcAddress() #endif

If your Linux system doesn't support GLX version 1.4, you should download and install the latest version of Mesa. See the section "Extension- and Version-Safe Code" later in this chapter for more information on writing version-safe code.

7.1.2.2. Obtaining Entry Points for Microsoft Windows

Microsoft Windows supports an interface that is nearly identical to the Linux GLX_ARB_get_proc_address interface. To obtain an extension entry-point address for Microsoft Windows, call wglGetProcAddress().

WINGDIAPI PROC WINAPI wglGetProcAddress( LPCSTR procName );

Although the function prototype contains many Windows-specific symbols, the function works identically to glXGetProcAddress(); it takes a const char* enTRy-point name as a parameter and returns a void* function pointer.

wglGetProcAddress() returns NULL if the entry point doesn't exist. This usually occurs if the extension isn't supported at runtime, but beware of typographical errors when coding this function call; misspelling the entry-point name could also cause wglGetProcAddress() to return NULL.

Unlike glXGetProcAddress(), wglGetProcAddress() is part of the Windows operating system and has been available since Windows first supported OpenGL. Your application doesn't need to check for the correct WGL version at compile time.

7.1.2.3. Obtaining Entry Points for Apple Mac OS X

Under Mac OS X, if an extension name is listed in the OpenGL extension string at runtime, applications can use the extension entry points without having to obtain entry-point addresses. For any given version of Mac OS X, OpenGL exposes a common set of extensions supported by all underlying graphics hardware vendors. Rather than use a routine such as wglGetProcAddress(), applications statically link with extension entry points. For this reason, Mac OS X applications have a greatly reduced need to obtain entry-point addresses dynamically compared with other platforms.

Mac OS X does provide interfaces for obtaining entry-point addresses dynamically, however. Applications will need to use this interface to run in multiple releases of Mac OS X. If your application needs to use this interface, review Apple's documentation on the subject. The following Web site contains general information on querying OpenGL capabilities:

http://developer.apple.com/technotes/tn2002/tn2080.html

The following Web site is devoted specifically to obtaining entry-point addresses:

http://developer.apple.com/qa/qa2001/qa1188.html

If your application has no need to obtain entry-point addresses under Mac OS X, you can skip the following section.

7.1.2.4. Declaring and Typecasting Entry Points

As described in the preceding sections, the runtime platform typically returns an extension entry-point address to your application as a void* function pointer. Your application should typecast this return value to a function pointer of the appropriate type. Your development environment contains extension entry-point prototypes. As an example, the following code segment shows how to declare the single extension entry-point function pointer for the GL_ARB_multisample[1] extension, obtain its entry point for Microsoft Windows, and correctly typecast the return value:

[1] GL_ARB_multisample was folded into the OpenGL version 1.3 specification. Some applications still use the ARB extension interface for compatibility with older OpenGL implementations.

// Note: PFNGLSAMPLECOVERAGEARBPROC declared in platform-specific // dev environment header file (or glext.h). PFNGLSAMPLECOVERAGEARBPROC glSampleCoverageARB; const bool useARBmultisample = isExtensionSupported( std::string( "GL_ARB_multisample" ), glGetString( GL_EXTENSIONS ) ); if (useARBmultisample) glSampleCoverageARB = (PFNGLSAMPLECOVERAGEARBPROC) wglGetProcAddress( "glSampleCoverageARB" );

Perform the same declaration and typecast regardless of your runtime platform.

Категории

© amp.flylib.com,