Posted by: Morten Nobel-Jørgensen | February 17, 2013

Debugging OpenGL part 2 – using glDebugMessageCallback()


OpenGL DebuggingThe traditional way to debug OpenGL is to insert glGetError() after each OpenGL function call as described in the previous blog post Debugging OpenGL part 1 – using glGetError(). Using glGetError is both cumbersome and time consuming. One of the new features in OpenGL 4.3 is the ability to get a callback whenever an OpenGL-related error occur. In this blog I’ll give a short introduction to how to use this new functionality using FreeGLUT and GLEW.

Prerequisites

First of all, you need a graphics card and a graphics card driver, which either supports OpenGL 4.3 fully or have support for glDebugMessageCallback.

To use the glDebugMessageCallback, you need to create a OpenGL context in debug mode. In FreeGlut you create a debug context by passing the GLUT_DEBUG enum to the glutInitContextFlags function. Usually you only want a debug context in a debug build. The parameter should therefor be wrapped with the following preprocessor directive.

	glutInitContextFlags(GLUT_FORWARD_COMPATIBLE
#if _DEBUG
		| GLUT_DEBUG
#endif
	);

The callback function

The following shows a simple example how the actual callback function could look like:

void APIENTRY openglCallbackFunction(GLenum source,
                                           GLenum type,
                                           GLuint id,
                                           GLenum severity,
                                           GLsizei length,
                                           const GLchar* message,
                                           const void* userParam){

	cout << "---------------------opengl-callback-start------------" << endl;
	cout << "message: "<< message << endl;
	cout << "type: ";
	switch (type) {
	case GL_DEBUG_TYPE_ERROR:
		cout << "ERROR";
		break;
	case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
		cout << "DEPRECATED_BEHAVIOR";
		break;
	case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
		cout << "UNDEFINED_BEHAVIOR";
		break;
	case GL_DEBUG_TYPE_PORTABILITY:
		cout << "PORTABILITY";
		break;
	case GL_DEBUG_TYPE_PERFORMANCE:
		cout << "PERFORMANCE";
		break;
	case GL_DEBUG_TYPE_OTHER:
		cout << "OTHER";
		break;
	}
	cout << endl;

	cout << "id: " << id << endl;
	cout << "severity: ";
	switch (severity){
	case GL_DEBUG_SEVERITY_LOW:
		cout << "LOW";
		break;
	case GL_DEBUG_SEVERITY_MEDIUM:
		cout << "MEDIUM";
		break;
	case GL_DEBUG_SEVERITY_HIGH:
		cout << "HIGH";
		break;
	}
	cout << endl;
	cout << "---------------------opengl-callback-end--------------" << endl;
}

An important thing to notice: The function must be a C method with the same calling convention as the GL API functions; here this is done using APIENTRY function prefix.

Subscribing for callbacks

The only missing piece is to configure OpenGL to use the callback function after the OpenGL Context has been created. This works like many other logging libraries, where you can subscribe for certain events. In our case we want to get all possible events and therefor use GL_DONT_CARE as filter. An important detail is to enable GL_DEBUG_OUTPUT_SYNCHRONOUS, which allows us to see the origin of each error, simply by setting a breakpoint inside the callback function.

#if _DEBUG
	if(glDebugMessageCallback){
		cout << "Register OpenGL debug callback " << endl;
		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
		glDebugMessageCallback(openglCallbackFunction, nullptr);
		GLuint unusedIds = 0;
		glDebugMessageControl(GL_DONT_CARE,
 			GL_DONT_CARE,
 			GL_DONT_CARE,
 			0,
 			&unusedIds,
 			true);
	}
	else
		cout << "glDebugMessageCallback not available" << endl;
#endif

Source code

A full running example of this is available at GitHub: https://github.com/mortennobel/OpenGL_4.3_VS_2010_freeglut

API documentation:


Responses

  1. Martin Leo Erik Lundgren's avatar

    Hey, very helpful post. Just wanted to note two things.

    1. The last argument in openglCallbackFunction should be const void * userParam, not void * userParam.

    For some reason VS2012 is really picky about the difference between const void * and void *. When I used VS2010 I never had a problem with this.

    2. Small typo in the debug function, line 34. I guess it should be cout << "id: " << id << endl;
    cout << "severity: ";

  2. Morten Nobel-Jørgensen's avatar

    Thanks for the corrections and the kind words 🙂 I have updated the post 🙂

  3. […] if you’re lucky. Morten Nobel’s blog here shows the usage of glDebugMessageCallback which can do the same sorts of things, but without the […]


Leave a reply to Martin Leo Erik Lundgren Cancel reply

Categories