Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
46 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Extensions and OpenGL 1.2 and 1.3, and the Future

Back at the beginning of this article, I said that OpenGL 1.2 and 1.3 features can be accessed using the extensions mechanism, which I've spent the last several pages explaining. The question, then, is how you go about doing that. The answer, as you may have guessed, is to treat 1.2 and 1.3 features as extensions. When it comes right down to it, that's really what they are, since nearly every feature that has been added to OpenGL originated as an extension. The only real difference between 1.2 and 1.3 features and "normal" extensions is that the former tend to be more widely supported in hardware, because, after all, they are part of the standard.

Sometimes, an extension that has been added to the OpenGL 1.2 or 1.3 core specification will undergo slight changes, causing the semantics and/or behavior to be somewhat different from what is documented in the extension's specification. You should check the latest OpenGL specification to find out about these changes.

The next update to OpenGL will probably be 1.4. It will most likely continue the trend of promoting successful extensions to become part of the standard, and you should be able to continue to use the extension mechanism to access those features. After that, OpenGL 2.0 will hopefully make its appearance, introducing some radical changes to the standard. Once 2.0 is released, new headers and libraries may be released as well, possibly provided by the ARB members. These will make it easier to use new features.

What You Get

As you can see, using OpenGL 1.2 and 1.3, and extensions in general, isn't a terribly difficult process, but it does take some extra effort. You may be wondering what you can gain by using them, so lets take a closer look at them. The following sections list the features added by OpenGL 1.2 and 1.3, as well as some of the more useful extensions currently available. With each feature, I've included the extension you can use to access it.

OpenGL 1.2

3D Textures allow you to do some really cool volumetric effects. Unfortunately, they require a significant amount of memory. To give you an idea, a single 256x256x256 16 bit texture will use 32 MB! For this reason, hardware support for them is relatively limited, and because they are also slower than 2D textures, they may not always provide the best solution. They can, however, be useful if used judiciously. 3D textures correspond to the EXT_texture3D extension.

BGRA Pixel Formats make it easier to work with file formats which use blue-green-red color component ordering rather than red-green-blue. Bitmaps and Targas are two examples that fall in this category. BGRA pixel formats correspond to the EXT_bgra extension.

Packed Pixel Formats provide support for packed pixels in host memory, allowing you to completely represent a pixel using a single unsigned byte, short, or int. Packet pixel formats correspond to the EXT_packed_pixels extension, with some additions for reversed component order.

Normally, since texture mapping happens after lighting, modulating a texture with a lit surface will "wash out" specular highlights. To help avoid this affect, the Separate Specular Color feature has been added. This causes OpenGL to track the specular color separately and apply it after texture mapping. Separate specular color corresponds to the EXT_separate_specular_color extension.

Texture Coordinate Edge Clamping addresses a problem with filtering at the edges of textures. When you select GL_CLAMP as your texture wrap mode and use a linear filtering mode, the border will get sampled along with edge texels. Texture coordinate edge clamping causes only the texels which are actually part of the texture to be sampled. This corresponds to the SGIS_texture_edge_clamp extension (which normally shows up as EXT_texture_edge_clamp in the GL_EXTENSIONS string).

Normal Rescaling allows you to automatically scale normals by a value you specify, which can be faster than renormalization in some cases, although it requires uniform scaling to be useful. This corresponds to the EXT_rescale_normal extension.

Texture LOD Control allows you to specify certain parameters related to the texture level of detail used in mipmapping to avoid popping in certain situations. It can also be used to increase texture transfer performance, since the extension can be used to upload only the mipmap levels visible in the current frame, instead of uploading the entire mipmap hierarchy. This matches the SGIS_texture_lod extension.

The Draw Element Range feature adds a new function to be used with vertex arrays. glDrawRangeElements() is similar to glDrawElements(), but it lets you indicate the range of indicies within the arrays that you are using, allowing the hardware to process the data more efficiently. This corresponds to the EXT_draw_range_elements extension.

The Imaging Subset is not fully present in all OpenGL implementations, since it's primarily intended for image processing applications. It's actually a collection of several extensions. The following are the ones that may be of interest to game developers.

  • EXT_blend_color allows you to specify a constant color which is used to define blend weighting factors.
  • SGI_color_matrix introduces a new matrix stack to the pixel pipeline, causing the RGBA components of each pixel to be multiplied by a 4x4 matrix.
  • EXT_blend_subtract gives you two ways to use the difference between two blended surfaces (rather than the sum).
  • EXT_blend_minmax lets you keep either the minimum or maximum color components of the source and destination colors.

OpenGL 1.3

The Multitexturing extension was promoted to ARB status with OpenGL 1.2.1 (the only real change in that release), and in 1.3, it was made part of the standard. Multitexturing allows you to apply more than one texture to a surface in a single pass, which is useful in many things, such as lightmapping and detail texturing. It was promoted from the ARB_multitexture extension.

Texture Compression allows you to either provide OpenGL with precompressed data for your textures, or to have the driver compress the data for you. The advantage in doing so is that you save both texture memory and bandwidth, thereby improving performance. Compressed textures were promoted from the ARB_compressed_textures extension.

Cube Map Textures provide a new type of texture consisting of six two-dimensional textures in the shape of a cube. Texture coordinates act like a vector from the center of the cube, indicating which face and which texels to use. Cube mapping is useful in environment mapping and texture-based diffuse lighting. It is also important for pixel-perfect dot3 bumpmapping, as a normalization lookup for interpolated fragment normals. It was promoted from the ARB_texture_cube_map extension.

Multisampling allows for automatic antialiasing by sampling all geometry several times for each pixel. When it's supported, and extra buffer is created which contains color, depth, and stencil values. Multisampling is, of course, expensive, and you need to be sure to request a rendering context that supports it. It was promoted from the ARB_multisampling extension.

The Texture Add Environment Mode adds a new enumerant which can be passed to glTexEnv(). It causes the texture to be additively combined with the incoming fragment. This was promoted from the ARB_texture_env_add extension.

Texture Combine Environment Modes add a lot of new options for the way textures are combined. In addition to the texture color and the incoming fragment, you can also include a constant texture color and the results of the previous texture environment stage as parameters. These parameters can be combined using passthrough, multiplication, addition, biased addition, subtraction, and linear interpolation. You can select combiner operations for the RGB and alpha components separately. You can also scale the final result. As you can see, this addition gives you a great deal of flexibility. Texture combine environment modes were promoted from the ARB_texture_env_combine extension.

The Texture Dot3 Environment Mode adds a new enumerant to the texture combine environment modes. The dot3 environment mode allows you to take the dot product of two specified components and place the results in the RGB or RGBA components of the output color. This can be used for per-pixel lighting or bump mapping. The dot3 environment mode was promoted from the ARB_texture_env_dot3 extension.

Texture Border Clamp is similar to texture edge clamp, except that it causes texture coordinates that straddle the edge to sample from border texels only, rather than from edge texels. This was promoted from the ARB_texture_border_clamp extension.

Transpose Matrices allow you to pass row major matrices to OpenGL, which normally uses column major matrices. This is useful not only because it is how C stores two dimensional arrays, but because it is how Direct3D stores matricies, which saves conversion work when you're writing a rendering engine that uses both APIs. This addition only adds to the interface; it does not change the way OpenGL works internally. Transpose matrices were promoted from the ARB_transpose_matrix extension.

Useful Extensions

At the time of writing, there are 269 extensions listed in the Extension Registry. Even if I focused on the ones actually being used, I couldn't hope to cover them all, even briefly. Instead, I'll focus on a few that seem to be the most important for use in games.

Programmable Vertex and Pixel Shaders
It's generally agreed that shaders are the future of graphics, so let's start with them. First of all, the terms "vertex shader" and "pixel shader" are in common usage because of the attention they received with the launch of DirectX 8. However, the OpenGL extensions that you use for them have different names. On NVIDIA cards, vertex shaders are called vertex programs, which are available through the NV_vertex_program extension. Pixel shaders are called register combiners, and are available through the NV_register_combiners and NV_texture_shader extensions. On ATI cards, vertex shaders are still called vertex shaders, and are available through the EXT_vertex_shader extension. Pixel shaders are called fragment shaders, and are available through the ATI_fragment_shader extension.

If you're unfamiliar with shaders, then a quick overview is in order. Vertex shaders allow you to customize the geometry transformation pipeline. Pixel shaders work later in the pipeline, and allow you to control how the final pixel color is determined. Together, the two provide incredible functionality. I recommend that you download NVIDIA's Effects Browser to see examples of the things you can do with shaders.

Using shaders can be somewhat problematic right now due to the fact that NVIDIA and ATI both handle them very differently. If you want your game to take advantage of shaders, you'll have to write a lot of special case code to use each vendor's method. At the ARB's last several meetings, this has been a major discussion point. There is a great deal of pressure to create a common shader interface. In fact, it is at the core of 3D Labs' OpenGL 2.0 proposal. Hopefully, the 1.4 specification will address this issue, but the ARB seems to be split as to whether a common shader interface should be a necessary component of 1.4.

Compiled Vertex Arrays
The EXT_compiled_vertex_arrays extension adds two functions which allow you to lock and unlock your vertex arrays. When the vertex arrays are locked, OpenGL assumes that their contents will not be changed. This allows OpenGL to make certain optimizations, such as caching the results of vertex transformation. This is especially useful if your data contains large numbers of shared vertices, or if you are using multipass rendering. When a vertex needs to be transformed, the cache is checked to see if the results of the transformation are already available. If they are, the cached results are used instead of recalculating the transformation.

The benefits gained by using CVAs depend on the data set, the video card, and the drivers. Although you generally won't see a decrease in performance when using CVAs, it's quite possible that you won't see much of an increase either. In any case, the fact that they are fairly widely supported makes them worth looking into.

WGL Extensions
There are a number of extensions available that add to the way Windows interfaces with OpenGL. Here are some of the main ones.

  • ARB_pixel_format augments the standard pixel format functions (i.e. DescribePixelFormat, ChoosePixelFormat, SetPixelFormat, and GetPixelFormat), giving you more control over which pixel format is used. The functions allow you to query individual pixel format attributes, and allow for the addition of new attributes that are not included in the pixel format descriptor structure. Many other WGL extensions are dependent on this extension.
  • ARB_pbuffer adds pixel buffers, which are off-screen (non-visible) rendering buffers. On most cards, these buffers are in video memory, and the operation is hardware accelerated. They are often useful for creating dynamic textures, especially when used with the render texture extension.
  • ARB_render_texture depends on the pbuffer extension. It is specifically designed to provide buffers that can be rendered to and be used as texture data. These buffers are the perfect solution for dynamic texturing.
  • ARB_buffer_region allows you to save portions of the color, depth, or stencil buffers to either system or video memory. This region can then be quickly restored to the OpenGL window.

Fences and Ranges
NVIDIA has created two extensions, NV_fence and NV_vertex_array_range, that can make video cards based on NVIDIA chipsets use vertex data much more efficiently than they normally would.

On NVIDIA hardware, the vertex array range extension is currently the fastest way to transfer data from the application to the GPU. Its speed comes from the fact that it allows the developer to allocate and access memory that normally can only be accessed by the GPU.

Although not directly related to the vertex array range extension, the fence extension can help make it even more efficient. When a fence is added to the OpenGL command stream, it can then be queried at any time. Usually, it is queried to determine whether or not it has been completed yet. In addition, you can force the application to wait for the fence to be completed. Fences can be used with vertex array range when there is not enough memory to hold all of your vertex data at once. In this situation, you can fill up available memory, insert a fence, and when the fence has completed, repeat the process.

Shadows
There are two extensions, SGIX_shadow and SGIX_depth_texture, which work together to allow for hardware-accelerated shadow mapping techniques. The main reason I mention these is that there are currently proposals in place to promote these extensions to ARB status. In addition, NVIDIA is recommending that they be included in the OpenGL 1.4 core specification. Because they may change somewhat if they are promoted, I won't go into detail about how these extensions work. They may prove to be a very attractive alternative to the stencil shadow techniques presently in use.



Writing Well-Behaved Programs

Contents
  Introduction
  OpenGL Extensions
  Using Extensions
  OpenGL 1.2 and 1.3
  Writing Well-Behaved Programs
  Demo & Conclusion

  Source code
  Printable version
  Discuss this article