I’ll here describe how to debug OpenGL using the glGetError() function in OpenGL 3.x core profile or higher where the gluErrorString() is no longer available.
Debugging with glGetError()
Most people are used to work with a programming language that supports exceptions. This means that whenever you call a function with some illegal parameters, the function are capable of throwing a runtime exception telling the programmer what he did wrong. OpenGL is a C-based API, which means that there is no support for exceptions. Instead of exceptions OpenGL simply ignores the function call and set an exception flag. The programmer need to query the OpenGL error state when one or more OpenGL calls have been made – this is done using the glGetError function.
Let’s look at an example:
void display() { glClearColor(1.,0.,0.,1.); glClear(GL_COLOR); // error - should be GL_COLOR_BUFFER_BIT // check OpenGL error GLenum err; while ((err = glGetError()) != GL_NO_ERROR) { cerr << "OpenGL error: " << err << endl; } glutSwapBuffers(); // Glut specific swap }
The code above has an invalid use of glClear where the parameter should be GL_COLOR_BUFFER_BIT instead of GL_COLOR. The result of running the program is a black screen and the error message “OpenGL error: 1281” is printed to the console. The error check must be in a loop since many errors can be have happened since last error check. It is certainly nice that the program now tells that an error occurred but what we really want is a more descriptive error message telling us the name of the OpenGL error enum instead of the value. It would also be nice having a single error check call instead of using a loop. Finally the error message should include where in your code the error occurred (in case your OpenGL program contains many error checks.
To support these requirements I have create a small function and a macro which let you check for OpenGL errors using a single command. The code is also available as a Gist on GitHub [Link].
GLError.h
#ifndef GLERROR_H #define GLERROR_H void _check_gl_error(const char *file, int line); /// /// Usage /// [... some opengl calls] /// glCheckError(); /// #define check_gl_error() _check_gl_error(__FILE__,__LINE__) #endif // GLERROR_H
GLError.cpp
#include "GLError.h" #include #ifdef WIN32 # include <GL/glew.h> #elif __APPLE__ # include <OpenGL/gl3.h> #else # include <GL3/gl3.h> #endif using namespace std; void _check_gl_error(const char *file, int line) { GLenum err (glGetError()); while(err!=GL_NO_ERROR) { string error; switch(err) { case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break; case GL_INVALID_ENUM: error="INVALID_ENUM"; break; case GL_INVALID_VALUE: error="INVALID_VALUE"; break; case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break; } cerr << "GL_" << error.c_str() <<" - "<<file<<":"<<line<<endl; err=glGetError(); } }
When this header file is included, checking for for OpenGL errors can be done using check_gl_error(). The example program can now be reduced to something much more readable:
#include "GLError.h" // ... void display() { glClearColor(1.,0.,0.,1.); glClear(GL_COLOR); // error - should be GL_COLOR_BUFFER_BIT check_gl_error(); glutSwapBuffers(); // Glut specific swap }
The program now output the error enum name as well as the file name and line number:
GL_INVALID_VALUE - sample_program.cpp:31
You may encounter errors after the OpenGL context initialization such as when using GLEW. These errors can usually be ignored.
But wait … there is more
This blog post explained the fundamentals of debugging OpenGL. In the following posts, I’ll explain some smarter ways of debugging OpenGL, which does not clutter up your code with error checks.
Leave a Reply