What is the best way to debug OpenGL?

OpenglDebugging

Opengl Problem Overview


I find that a lot of the time, OpenGL will show you it failed by not drawing anything. I'm trying to find ways to debug OpenGL programs, by inspecting the transformation matrix stack and so on. What is the best way to debug OpenGL? If the code looks and feels like the vertices are in the right place, how can you be sure they are?

Opengl Solutions


Solution 1 - Opengl

There is no straight answer. It all depends on what you are trying to understand. Since OpenGL is a state machine, sometimes it does not do what you expect as the required state is not set or things like that.

In general, use tools like glTrace / glIntercept (to look at the OpenGL call trace), gDebugger (to visualize textures, shaders, OGL state etc.) and paper/pencil :). Sometimes it helps to understand how you have setup the camera and where it is looking, what is being clipped etc. I have personally relied more to the last than the previous two approaches. But when I can argue that the depth is wrong then it helps to look at the trace. gDebugger is also the only tool that can be used effectively for profiling and optimization of your OpenGL app.

Apart from this tool, most of the time it is the math that people get wrong and it can't be understood using any tool. Post on the OpenGL.org newsgroup for code specific comments, you will be never disappointed.

Solution 2 - Opengl

> What is the best way to debug OpenGL?

Without considering additional and external tools (which other answers already do).

Then the general way is to extensively call glGetError(). However a better alternative is to use Debug Output (KHR_debug, ARB_debug_output). This provides you with the functionality of setting a callback for messages of varying severity level.

In order to use debug output, the context must be created with the WGL/GLX_DEBUG_CONTEXT_BIT flag. With GLFW this can be set with the GLFW_OPENGL_DEBUG_CONTEXT window hint.

glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

Note that if the context isn't a debug context, then receiving all or even any messages aren't guaranteed.

Whether you have a debug context or not can be detected by checking GL_CONTEXT_FLAGS:

GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);

if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
    // It's a debug context

You would then go ahead and specify a callback:

void debugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
                  const GLchar *message, const void *userParam)
{
    // Print, log, whatever based on the enums and message
}

Each possible value for the enums can be seen on here. Especially remember to check the severity, as some messages might just be notifications and not errors.

You can now do ahead and register the callback.

glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(debugMessage, NULL);

glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);

You can even inject your own messages using glDebugMessageInsert().

glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0,
                     GL_DEBUG_SEVERITY_NOTIFICATION, -1, "Vary dangerous error");

When it comes to shaders and programs you always want to be checking GL_COMPILE_STATUS, GL_LINK_STATUS and GL_VALIDATE_STATUS. If any of them reflects that something is wrong, then additionally always check glGetShaderInfoLog() / glGetProgramInfoLog().

GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);

if (!linkStatus)
{
    GLchar *infoLog = new GLchar[infoLogLength + 1];
    glGetProgramInfoLog(program, infoLogLength * sizeof(GLchar), NULL, infoLog); 

    ...

    delete[] infoLog;
}

The string returned by glGetProgramInfoLog() will be null terminated.


You can also go a bit more extreme and utilize a few debug macros in a debug build. Thus using glIs*() functions to check if the expected type is the actual type as well.

assert(glIsProgram(program) == GL_TRUE);
glUseProgram(program);

If debug output isn't available and you just want to use glGetError(), then you're of course free to do so.

GLenum err;
while ((err = glGetError()) != GL_NO_ERROR)
    printf("OpenGL Error: %u\n", err);

Since a numeric error code isn't that helpful, we could make it a bit more human readable by mapping the numeric error codes to a message.

const char* glGetErrorString(GLenum error)
{
	switch (error)
	{
	case GL_NO_ERROR:          return "No Error";
	case GL_INVALID_ENUM:      return "Invalid Enum";
	case GL_INVALID_VALUE:     return "Invalid Value";
	case GL_INVALID_OPERATION: return "Invalid Operation";
	case GL_INVALID_FRAMEBUFFER_OPERATION: return "Invalid Framebuffer Operation";
	case GL_OUT_OF_MEMORY:     return "Out of Memory";
	case GL_STACK_UNDERFLOW:   return "Stack Underflow";
	case GL_STACK_OVERFLOW:    return "Stack Overflow";
	case GL_CONTEXT_LOST:      return "Context Lost";
	default:                   return "Unknown Error";
	}
}

Then checking it like this:

printf("OpenGL Error: [%u] %s\n", err, glGetErrorString(err));

That still isn't very helpful or better said intuitive, as if you have sprinkled a few glGetError() here and there. Then locating which one logged an error can be troublesome.

Again macros come to the rescue.

void _glCheckErrors(const char *filename, int line)
{
    GLenum err;
    while ((err = glGetError()) != GL_NO_ERROR)
        printf("OpenGL Error: %s (%d) [%u] %s\n", filename, line, err, glGetErrorString(err));
}

Now simply define a macro like this:

#define glCheckErrors() _glCheckErrors(__FILE__, __LINE__)

and voila now you can call glCheckErrors() after everything you want, and in case of errors it will tell you the exact file and line it was detected at.

Solution 3 - Opengl

https://github.com/dtrebilco/glintercept/">GLIntercept</a> is your best bet. From their web page:

  • Save all OpenGL function calls to text or XML format with the option to log individual frames.
  • Free camera. Fly around the geometry sent to the graphics card and enable/disable wireframe/backface-culling/view frustum render
  • Save and track display lists. Saving of the OpenGL frame buffer (color/depth/stencil) pre and post render calls. The ability to save the "diff" of pre and post images is also available.

Solution 4 - Opengl

Apitrace is a relatively new tool from some folks at Valve, but It works great! Give it a try: https://github.com/apitrace/apitrace

Solution 5 - Opengl

I found you can check using glGetError after every line of code your suspect will be wrong, but after do it, the code looks not very clean but it works.

Solution 6 - Opengl

For those on Mac, the buit in OpenGL debugger is great as well. It lets you inspect buffers, states, and helps in finding performance issues.

Solution 7 - Opengl

The gDebugger is an excellent free tool, but no longer supported. However, AMD has picked up its development, and this debugger is now known as CodeXL. It is available both as a standalone application or as a Visual Studio plugin - works both for native C++ applications, or Java/Python applications using OpenGL bindings, both on NVidia and AMD GPUs. It's one hell of a tool.

Solution 8 - Opengl

There is also the free glslDevil: http://www.vis.uni-stuttgart.de/glsldevil/

It allows you to debug glsl shaders extensively. It also shows failed OpenGL calls.

However it's missing features to inspect textures and off screen buffers.

Solution 9 - Opengl

Nsight is good debugging tool if you have an NVidia card.

Solution 10 - Opengl

Updating the window title dynamically is convenient for me.

Example (use GLFW, C++11):

glfwSetWindowTitle(window, ("Now Time is " + to_string(glfwGetTime())).c_str());

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondreamlaxView Question on Stackoverflow
Solution 1 - OpenglKetanView Answer on Stackoverflow
Solution 2 - OpenglvallentinView Answer on Stackoverflow
Solution 3 - OpenglDavid SegondsView Answer on Stackoverflow
Solution 4 - OpenglFoxorView Answer on Stackoverflow
Solution 5 - OpenglFrank ChengView Answer on Stackoverflow
Solution 6 - OpenglSijmen MulderView Answer on Stackoverflow
Solution 7 - Openglaxel22View Answer on Stackoverflow
Solution 8 - OpenglheeenView Answer on Stackoverflow
Solution 9 - OpenglaedmView Answer on Stackoverflow
Solution 10 - OpenglBaiJiFeiLongView Answer on Stackoverflow