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:
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:
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().
|