Debugging OpenGL has always been a bit painful. In most cases an OpenGL error will just result in the offending call being ignored (unless the problem was too little memory, in which case anything could happen). To get informed of the problem, the application had to query an error number for OpenGL to get the last type of error that happened (using glGetError). This had two problems: on the one hand this will force GL to actually finish all calls triggered previously (and normally OpenGL runs asynchronously from the main application) and on the other hand you only got the last error that happened: if there were multiple GL calls since your last check you had no clue which of them did something wrong!
To ensure you get the problematic GL call every time right you had to call glGetError after every GL call. This of course slows down the application and the code becomes a pain to read and write.
In 2010 AMD had some great ideas of how to provide a better way of debugging: AMD_debug_output. It enhanced the old way of querying errors in a number of new ways:
- You can query a human readable error message.
- You can query more than one error.
- You can provide a callback function and the GL will call you as soon as something goes wrong!
- You don’t only get errors reported, but also compatibility warnings, performance warnings etc. You can also mute messages depending on the kind of the message.
- Applications and 3rd party libraries can even insert own messages.
The idea lived on in ARB_debug_output which added a way to ensure the callback being called synchronously and got support from multiple vendors. Now instead of polluting your code with glGetError calls, you can just define a callback function, register it in one line of code and force GL to call it synchronously, put a breakpoint inside of your callback and you will instantly see which GL call triggered an error at which position of your code and you can even inspect the state of your variables during that moment…
The latest iteration of this extension is KHR_debug which is also available for OpenGL ES. This will also most likely be the final form of the new debug functionality as KHR_debug is in fact part of OpenGL 4.3. This means that on all OpenGL 4.3 or later systems we will always have this functionality and can finally ditch glGetError. KHR_debug can also get implemented for older GL versions and gets growing support from AMD, Intel, NVidia and Mesa!
But, there are two problems: First, even if the extension is supported, unless your code runs in an OpenGL debug context you are not guaranteed to get any debug messages out of it! If for any reasons you can not control how the OpenGL context was created you might have to live without this functionality even if your drivers support KHR_debug. The functions will be present but your callback will never get called… QT before version 5.1 might be such a case. The second (and probably worse) problem is MacOS X – even the next version to be released (10.9, codename Mavericks) will only support OpenGL 4.1 and there is no sign of a debug extension yet. This means at least another year, probably even more than that until we have KHR_debug everywhere natively. You can however use this trick to get the same debug functionality even on MacOS and other systems that do not support the debug extension natively ;-)
Getting started with this extension is quite simple, first request a debug context using the windowing toolkit of your choice. For GLFW the code looks as follows:
glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, true ); window = glfwCreateWindow( ... ); |
Then you can check if the KHR_debug extension is present (unless you know it is because you know you are on OpenGL 4.3 or later) and if you really got a debug context:
if (ogl_ext_KHR_debug) { cout << "KHR_debug supported" << endl; } GLint v; glGetIntegerv( GL_CONTEXT_FLAGS, &v ); if (v & GL_CONTEXT_FLAG_DEBUG_BIT) { cout << "OpenGL debug context present" << endl; } |
This code assumes you used the C pointer style GL function loader from glLoadGen, but you can use any other method to check for the extension if you like. Note that OpenGL 4.3 and later implementations don’t need to advertise the extension at all – MacOS X often does not claim to support the extensions that are in fact part of a core specification OS X supports.
Now you can define your debug callback and register it:
void myCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *msg, const void *data ) { cout << "debug call: " << msg << endl; } ... glDebugMessageCallback( myCallback, NULL ); |
More insights into debugging with this functionality is given in the book OpenGL Insights chapter 33 which is also available online for free. While this article describes the predecessor extension ARB_debug_output, the content is still relevant and a good introduction. KHR_debug supports in fact more features like naming objects and debug groups, but the killer-feature IMHO is the callback. Also note that you should use the callback instead of the message query function as the message queue is allowed to only contain one message…