If we decide to stick a large number of these glCheckError calls in our codebase it's helpful to more precisely know which glCheckError call returned the error. In case you're unaware of what the preprocessor directives _FILE_ and _LINE_ are: these variables get replaced during compile time with the respective file and line they were compiled in. #define glCheckError() glCheckError_(_FILE_, _LINE_) While ((errorCode = glGetError()) != GL_NO_ERROR)Ĭase GL_INVALID_ENUM: error = "INVALID_ENUM" break Ĭase GL_INVALID_VALUE: error = "INVALID_VALUE" break Ĭase GL_INVALID_OPERATION: error = "INVALID_OPERATION" break Ĭase GL_STACK_OVERFLOW: error = "STACK_OVERFLOW" break Ĭase GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW" break Ĭase GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY" break Ĭase GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION" break
GLenum glCheckError_(const char *file, int line) It often makes sense to write a small helper function to easily print out the error strings together with where the error check function was called: Let's say you get a black screen and you have no idea what's causing it: is the framebuffer not properly set? Did I forget to bind a texture? By calling glGetError all over your codebase, you can quickly catch the first place an OpenGL error starts showing up.īy default glGetError only prints error numbers, which isn't easy to understand unless you've memorized the error codes. The great thing about glGetError is that it makes it relatively easy to pinpoint where any error may be and to validate the proper use of OpenGL. Std::cout << glGetError() << std::endl // returns 1281 (invalid value) Std::cout << glGetError() << std::endl // returns 1280 (invalid enum) GlTexImage2D(GL_TEXTURE_3D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, data) Std::cout << glGetError() << std::endl // returns 0 (no error) Because of this, it is recommended to call glGetError inside a loop.
Calling glGetError then only resets one of the error code flags instead of all of them. Note that when OpenGL runs distributedly like frequently found on X11 systems, other user error codes can still be generated as long as they have different error codes. This means that if you call glGetError once at the end of each frame and it returns an error, you can't conclude this was the only error, and the source of the error could've been anywhere in the frame. Furthermore, the moment glGetError is called it clears all error flags (or only one if on a distributed system, see note below). The moment an error flag is set, no other error flags will be reported. For instance, if you take a look at the documentation of glBindTexture function, you can find all the user error codes it could generate under the Errors section. Within OpenGL's function documentation you can always find the error codes a function generates the moment it is incorrectly used. Set when reading or writing to a framebuffer that is not complete. Set when a memory allocation operation cannot allocate (enough) memory. Set when a stack popping operation occurs while the stack is at its lowest point. Set when a stack pushing operation causes a stack overflow. Set when the state for a command is not legal for its given parameters. Set when an enumeration parameter is not legal.
No user error reported since the last call to glGetError.
The error codes that glGetError can return are listed below:
The moment glGetError is called, it returns either an error flag or no error at all. We can query these error flags using a function named glGetError that checks the error flag(s) set and returns an error value if OpenGL got misused: The moment you incorrectly use OpenGL (like configuring a buffer without first binding any) it will take notice and generate one or more user error flags behind the scenes. Debugging in OpenGL is not too difficult to do and getting a grasp of its techniques definitely pays out in the long run. In this chapter we'll look into several techniques and tricks of debugging your OpenGL program. We have no console to output text to, no breakpoints to set on GLSL code, and no way of easily checking the state of GPU execution. Debugging these kinds of visual errors is different than what you're used to when debugging errors on the CPU. Graphics programming can be a lot of fun, but it can also be a large source of frustration whenever something isn't rendering just right, or perhaps not even rendering at all! Seeing as most of what we do involves manipulating pixels, it can be difficult to figure out the cause of error whenever something doesn't work the way it's supposed to.