OpenGL Debug API

28.08.2010 03:16 in OpenGL

Recently we've got a nice extension: ARB_debug_output.

It allows OpenGL implementations to provide more detailed errors and warnings. To be honest, person that invented glGetError (and consided it a reasonable debugging method) must have been mad or completely drunk. Am I over exaggerating? If you think so, try to fix your car using only one six-color LED diode. And I'll repeat once more: software engineering, and specifically graphics programming is not a goddamn MasterMind game.

If you're not familiar with current error handling system (good for you), I'll explain:

If you want to be sure that your graphics code is error-free, you need to check glGetError after every OpenGL call. It returns a single enum value. One goddamn integer is all you're given. And, most of the time there are only 3 values in play: GL_INVALID_ENUM , GL_INVALID_VALUE and GL_INVALID_OPERATION . Every OpenGL call has its own error codes and a single value (like GL_INVALID_OPERATION ) can indicate several different errors in single GL call.

Well, actually it's not such a big problem because as you probably know, most bugs in graphics programming manifests as black screens or -- if you're lucky -- some more sophisticated artifacts (like colorful rainbows or ominous circles).

Anyway I've been quite enthusiastic seeing ARB_debug_output . Basically it allows you to bind your own callback function after every OpenGL warning/error. You are provided with error code, message (char*), severity, type (error/warning) and source (OpenGL/shader compiler/WGL/etc). Sounds great, doesn't it?

So, I've quickly added new extension functions, coded suitable handler, broke one GL call and run my engine.

What I've got was this:

OpenGL message 1280: GL_INVALID_ENUM error generated. [source: API] [type: error] [severity: high]

FFFFFUUUUUU!

So instead of simple yet useless glGetError, we have quite complicated mechanism with a lot of additional functions which provides the same dumb information. But wait, it's getting worse.

If you want to know at least which call failed, you could add checks in code like this:

glBindTexture(...); CHECK;
glTexImage2D(...); CHECK;

Of course, this is not as pretty as one would wish. So I wrapped all GL functions:

static void gl::BindTexture(...)
{
glBindTexture(...);
CHECK;
}

But creating such a wrapper is probably not the most fascinating job on the planet. So you could think that this can be eliminated with debug_output. Call some functions and get error message only when its real -- actually ARB_debug_output advertises like this.

But it's wrong.

There are 2 methods of using callback -- synchronous and asynchronous. Every sane coder would guess that synchronous method ensures that callback would have been call after buggy GL call. Miss! Synchronous only ensures that callback will be called from the same thread. But most of the time it will be called after SwapBuffers. On the other hand, asynchronous calls can be made from random thread in a random moment. As you know, surprise is good.

So it's not possible to get rid of all that CHECKs. I was initially going to completely crush this ridiculous extension, but after several tries I've finally managed to get some extra info:

GL_INVALID_ENUM error generated. Framebuffer <target> is invalid.

GL_INVALID_OPERATION error generated. <texture> does not name a layered texture.

So it's not that bad after all. We can hope that future driver releases will provide more and more info, maybe even promised performance warnings.

PS. Remember that this extension is only available in Debug context.

Comments:

  1. Groovounet

    Groovounet:

    "Remember that this extension is only available in Debug context."

    Is potentially only available in the debug profile.

    28.08.2010 11:35:48

  2. Gynvael Coldwind

    Gynvael Coldwind:

    Ahahaha I had fun reading this post :)
    Well written, and you're absolutely right about the drawbacks ;)

    28.08.2010 12:38:16

  3. Tomasz Dabrowski

    Tomasz Dabrowski:

    Gynvael Coldwind: glad to hear that :)

    Groovounet: hmm, is there really something like debug profile? Of course, technically speaking there is also no such thing as debug context (but I guess that my readers got the idea), but I think that there are Core and Compatibility profiles -- and debug is only a additional flag that can be applied to both. So to sum this up, I guess that correct name is "core profile with debug flag". Am I wrong?

    My engine code:

    int attribs[] =
    {
    WGL_CONTEXT_MAJOR_VERSION,
    3,

    WGL_CONTEXT_MINOR_VERSION,
    3,

    WGL_CONTEXT_FLAGS,
    WGL_CONTEXT_FORWARD_COMPATIBLE_BIT | WGL_CONTEXT_DEBUG_BIT,

    GL_CONTEXT_PROFILE_MASK,
    GL_CONTEXT_CORE_PROFILE_BIT,

    0
    };

    wglCreateContextAttribs(hdc, NULL, attribs);

    28.08.2010 13:29:39

  4. Xion

    Xion:

    I place a seal of approval on this post. Additionally, I hereby express my pity for every OpenGL developer as they are unable to witness the awesomeness of DirectX Debug Output Levels :)

    29.08.2010 01:17:20

  5. .c41x

    .c41x:

    debug_output is not perfect, but is way much better than glError :) On ATI hd4* card i have more detailed info (using ATI not ARB extension):

    glBufferData failed because nothing is bound to one or more of the refere (GL_INVALID_OPERATION)
    glDrawRangeElements failed because the vertex data for the operation can not fit in available video memory
    glDisable has an invalid enum '0x6' (GL_INVALID_ENUM

    20.10.2010 11:27:27

  6. maxest

    maxest:

    I use GLIntercept. Not a perfect tool but at least you don't have to call glGetError after every GL call. GLIntercept will do that :)

    08.11.2011 22:11:54

Leave comment: