Open GL Super Bible

Previous Table of Contents Next


Chapter 5
Errors and Other Messages from OpenGL

What you’ll learn in this chapter:

How To… Functions You’ll Use

Get the error code of the last OpenGL error glGetError
Convert an error code into a textual description of the problem gluErrorString
Get version and vendor information from OpenGL glGetString, gluGetString
Make implementation-dependent performance hints glHint

In any project, we want to write robust and well-behaved programs that respond politely to their users and have some amount of flexibility. Graphical programs that use OpenGL are no exception. Now we don’t want to turn this chapter into a course on software engineering and quality assurance, but if you want your programs to run smoothly, you need to account for errors and unexpected circumstances. OpenGL provides you with two different methods of performing an occasional sanity check in your code.

The first of OpenGL’s control mechanisms is error detection. If an error occurs, you need to be able to stop and say “Hey, an error occurred, and this is what it was.” This is the only way in code that will let you know your rendering of the Space Station Freedom is now the Space Station Melted Crayola.

The second OpenGL sanity check is a simple solution to a common problem— something of which every programmer, good and bad, is sometimes guilty. Let’s say you know that Microsoft’s implementation of the Generic GDI version of OpenGL lets you get away with drawing in a double-buffered window using GDI, as long as you draw in the front buffer. Then you buy one of those fancy, warp drive accelerator cards, and the vendor throws in a new rendering engine. Worse, suppose your customer buys one of these cards. Will your code still work? Will it eat your image and spit out psychedelic rainbows? You may have a good reason for using such optimization tricks; it’s certainly faster to use TextOut than to call wglUseFontBitmaps. (Of course, if you do have this fancy-dancy video card, TextOut may not be the fastest road to Rome anymore anyhow.) The simple way to guard against this type of catastrophe is to check the version and vendor of your OpenGL library. If your implementation is the generic Microsoft, cheat to your heart’s content; otherwise, better stick to the documented way of doing things.

In summary, if you want to take advantage of vendor or version specific behavior, you should check in your code to make sure that the vendor and version are the same as that you designed for. Later, we’ll discuss OpenGL Hints, which allow you to instruct the rendering engine to make tradeoffs for the sake of speed, or image quality. This would be the preferred means of using vendor specific optimizations.

When Bad Things Happen to Good Code

Internally, OpenGL maintains a set of six error status flags. Each flag represents a different type of error. Whenever one of these errors occurs, the corresponding flag is set. To see if any of these flags is set, call glGetError:

GLenum glGetError(void);

The glGetError function returns one of the values listed in Table 5-1, located in the Reference Section under glGetError. The GLU library defines three errors of its own, but these errors map exactly to two flags already present. If more than one of these flags is set, glGetError still returns only one distinct value. This value is then cleared when glGetError is called, and recalling glGetError will return either another error flag or GL_NO_ERROR. Usually, you will want to call glGetError in a loop that continues checking for error flags until the return value is GL_NO_ERROR.

Listing 5-1 is a section of code from the GLTELL example that loops, checking for error messages until there are none. Notice that the error string is placed in a control in a dialog box. You can see this in the output from the GLTELL program in Figure 5-1.


Figure 5-1  An About box describing the GL and GLU libraries, along with any recent errors

Listing 5-1 Code sample that retrieves errors until there are no more errors

// Display any recent error messages
        i = 0;
        do {
               glError = glGetError();

               SetDlgItemText(hDlg,IDC_ERROR1+i,gluErrorString(glError));
               i++;
               }
        while(i < 6 && glError != GL_NO_ERROR);

You can use another function in the GLU library, gluErrorString, to get a string describing the error flag:

const GLubyte* gluErrorString(GLenum errorCode);

This function takes as its only argument the error flag (returned from glGetError, or hand-coded), and returns a static string describing that error. For example, the error flag GL_INVALID_ENUM returns the string

invalid enumerant

You can take some peace of mind from the assurance that if an error is caused by an invalid call to an OpenGL function or command, that function or command is ignored. OpenGL may not behave as you intended, but it will continue to run. The only exception to this is GL_OUT_OF_MEMORY (or GLU_OUT_OF_MEMORY, which has the same value anyway). When this error occurs, the state of OpenGL is undefined—indeed, the state of your program may be undefined! With this error, it’s best to clean up as gracefully as possible and terminate the program.


Previous Table of Contents Next