Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a better way of debugging OpenGL than calling glGetError after each command?

I'm experimenting with some OpenGL on Android, and I don't have any previous experience with 3D programming. So obviously I made quite a few mistakes in my program.

When I encountered a problem and found that glGetError produced an error code, I just added calls to glGetError after each call to an OpenGL command in my drawing code. While this worked and I found my errors this way, my drawing code is now twice as big and harder to read in my opinion.

Is there a way to get rid of all these explicit calls to glGetError and just call it automatically? Preferably, my app should just abort with an error indicating which command is responsible if an OpenGL error occurs.

like image 291
Mad Scientist Avatar asked May 16 '13 18:05

Mad Scientist


People also ask

What is OpenGL debugging?

Debug Output is an OpenGL feature that makes debugging and optimizing OpenGL applications easier. Briefly, this feature provides a method for the driver to provide textual message information back to the application.

How do I check OpenGL errors?

The errors are stored using the data type GLenum . GL_NO_ERROR always has the value 0 and you need to call glGetError() multiple times (one for each error that has occurred) until it returns GL_NO_ERROR . A general rule of thumb is to check for error at least once in a rendering cycle.

How do I use 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.


3 Answers

As of version 4.2 Android offers an option called "Enable OpenGL traces" in the phone's developer options. If you set this to "Call stack on glGetError" you'll get an output like

07-15 15:44:43.045: D/libEGL(14251): [glEnableClientState] 0x500
07-15 15:44:43.068: D/CallStack(14251): glGetError:glEnableClientState#00  pc 00019388  /system/lib/libEGL.so
07-15 15:44:43.076: D/CallStack(14251): glGetError:glEnableClientState#01  pc 0001e290  /system/lib/libdvm.so (dvmPlatformInvoke+112)
07-15 15:44:43.076: D/CallStack(14251): glGetError:glEnableClientState#02  pc 0004d410  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+395)
07-15 15:44:43.076: D/CallStack(14251): glGetError:glEnableClientState#03  pc 000276e4  /system/lib/libdvm.so

in the log. In this case, I was passing a wrong enum / int to glEnableClientState() to trigger the error. Note that the error will be "consumed" by enabling this option and further glGetError() checks will not report this anymore. Instead, you can now save the time putting glGetError() calls in your code and just grep the log output for "glGetError:".

like image 138
sschuberth Avatar answered Nov 07 '22 04:11

sschuberth


On OpenGL ES you cannot do much better, if you are targeting OpenGL ES 2.0 you should also be using some vendor tools (depending on your reference/target device) to aid you in shader development and performance tuning.

You must call glError in a loop, for example in java:

public void checkGLError(String op) {
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e("MyApp", op + ": glError " + error);
    }
}

But leaving production code with those check is a bad idea, glError is slow. Best option is to encapsulate inside a logging class that disables glError unless an error was found in the previous frame.

like image 41
Trax Avatar answered Nov 07 '22 04:11

Trax


Desktop OpenGL 4.3+ has extended debugging and callback functionalities (though I don't have any experience with those). But in ES there isn't really anything better. Sadly the best solution is still to not write any glGetErrors (or maybe only at some selected important points, like the end of each frame or something) and only introduce them en masse when something "doesn't work".

Other than that you could also make some wrapper like

template<typename F> void checked(F fn)
{
    fn();
    auto error = glGetError();
    if(error != GL_NO_ERROR)
        throw std::runtime_error("OpenGL error: "+std::to_string(error));
}

...
checked([&]() { glDrawElements(...); });

(assuming C++11, but other languages should have similar facilities)

But I think such solutions still cannot be made perfectly equivalent to no glGetErrors at all, regarding readability and conciseness.

like image 45
Christian Rau Avatar answered Nov 07 '22 05:11

Christian Rau