Skip to content

Instantly share code, notes, and snippets.

@Journeyman1337
Last active January 4, 2021 15:54
Show Gist options
  • Save Journeyman1337/b113a2ba2155bae39c4d5375e709a07b to your computer and use it in GitHub Desktop.
Save Journeyman1337/b113a2ba2155bae39c4d5375e709a07b to your computer and use it in GitHub Desktop.
An opengl debugging header only library I made a while back.
/*
MIT License
Copyright (c) 2020 Daniel Valcour
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/* glDebug.h - MIT Licensed OpenGL Debuging Library
This is a header only library. You need to do this in a cpp file somewhere in your project (only once)
to implment the library.
#define GLD_IMPLEMENTATION
#include <glDebug.h>
glDebug is useful for producing verbose debug messages for OpenGL. Unlike the debug callback system,
glDebug works with OpenGL versions older than 4.3. Also, glDebug works on the same thread as your OpenGL
calls. This allows for you to manually add debug breaks to your debug callback function, so finding the
exact location of an error is as easy as looking at the call stack. Without tools like this libarary, that
kind of debugging is hard to do, and I often found myself confused as to what was wrong with my OpenGL code.
The OpenGL debugging techniques used in this library may be helpful for development, but they are also very
perforamance heavy. Because of this, this library is designed with macros which only call debugging
related code if your project is in debug configuration. In release configuration, glDebug.h has no impact
at all, and your code will compile as if it wasn't there in the first place. Furthermore, you can define
the macro GLD_ACTIVE as 0 before including glDebug.h to disable all library features in a region of
your code even in debug configuration. If you want more control you can include glDebug.h multiple times
in a single code file, and then define GLD_ACTIVE to be 1 to enable or 0 to disable the library in
different sections of your code. This way, you can specify to only debug the OpenGL calls you are currently
working on without having to add and remove the macros often.
You are meant to write glDebug macros in your code like they are functions with semicolons following them.
I have found this helpful when using the library in certain IDEs like Visual Studio, where if you don't use
semicolons the editor will try to unindent every macro call, making the code hard/annoying to keep tidy.
glDebug.h has 5 macros that provide debbugging functionality:
GLD_CLEAR() - Call this macro once at the top of every block of OpenGL functions you
wish to debug. This function clears all opengl errors that are already enqueued in
the state machine. If you don't call this first before using other error checking
macros, you may get errors reported that were actually in completley different parts of your code.
GLD_SET_CALLBACK() - Call this macro only once, and do it before you call any of the
other debug macros in this library. Pass in a pointer to a function (a function pointer) that
returns void and takes in two const char* arguments. In this function you are meant to write
code you want to execute whenever an error occurs. The first argument is the type of error in
textual form, and the second argument is a stringified version of the entire line where the error occured.
GLD_CALL(glFunc) - Pass in entire programming statments into this macro (without the semicolon)
to test any OpenGL calls in it for errors. You are meant to pass in entire statements, including
both the rvalue and lvalue, but not the semicolon (though you should still add a semicolon after the macro).
GLD_COMPILE(shaderHandleVar) - Instead of calling glCompileShader(), call this instead to compile
and then check for compile errors.
GLD_LINK(programHandleVar) - Instead of calling glLinkProgram(), call this instead to link and
then check for linking errors.
*/
#ifdef __cplusplus //extern C guard
extern "C" {
#endif
#ifndef NDEBUG
#ifndef GLD_ACTIVE
#define GLD_ACTIVE 1
#endif
#else
#define GLD_ACTIVE 0
#endif
#if GLD_ACTIVE == 1
#ifndef GLD_PROTOTYPES
#define GLD_PROTOTYPES
void glDebug_ClearErrors();
void glDebug_SetCallback(void (*callback)(const char*, const char*));
void glDebug_ErrorCheck(const char* glFunc);
void glDebug_CheckShaderCompile(const char* identifier, int handle);
void glDebug_CheckProgramLink(const char* identifier, int handle);
#endif
#define GLD_CLEAR() glDebug_ClearErrors();
#define GLD_SET_CALLBACK(callback) glDebug_SetCallback(callback);
#define GLD_CALL(glFunc) glFunc; glDebug_ErrorCheck( #glFunc );
#define GLD_COMPILE(shaderHandleVar) glCompileShader(shaderHandleVar); glDebug_CheckShaderCompile( #shaderHandleVar , shaderHandleVar);
#define GLD_LINK(programHandleVar) glLinkProgram(programHandleVar); glDebug_CheckProgramLink( #programHandleVar, programHandleVar );
#else
#define GLD_CLEAR()
#define GLD_SET_CALLBACK(callback)
#define GLD_CALL(x) x;
#define GLD_COMPILE(shaderHandleVar) glCompileShader(shaderHandleVar);
#define GLD_LINK(programHandleVar) glLinkProgram(programHandleVar);
#endif
#ifdef GLD_IMPLEMENTATION
#ifndef GLD_IMPLEMENTED
#define GLD_IMPLEMENTED
#if GLD_ACTIVE != 0
static void (*sGL_DEBUG_CALLBACK) (const char*, const char*) = NULL;
void glDebug_SetCallback(void (*callback) (const char*, const char*))
{
sGL_DEBUG_CALLBACK = callback;
}
void glDebug_ClearErrors()
{
while (glGetError() != GL_NO_ERROR);
}
void glDebug_ErrorCheck(const char* glFunc)
{
if (!sGL_DEBUG_CALLBACK)
{
return;
}
GLenum err = glGetError();
switch (err)
{
case GL_NO_ERROR:
break;
//case GL_INVALID_ENUN:
// sGL_DEBUG_CALLBACK("glError: GL_INVALID_ENUM", glFunc);
// break;
case GL_INVALID_VALUE:
sGL_DEBUG_CALLBACK("glError: GL_INVALID_VALUE", glFunc);
break;
case GL_INVALID_OPERATION:
sGL_DEBUG_CALLBACK("glError: GL_INVALID_OPERATION", glFunc);
break;
//case GL_STACK_OVERFLOW:
// sGL_DEBUG_CALLBACK("glError: GL_STACK_OVERFLOW", glFunc);
// break;
case GL_OUT_OF_MEMORY:
sGL_DEBUG_CALLBACK("glError: GL_OUT_OF_MEMORY", glFunc);
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
sGL_DEBUG_CALLBACK("glError: GL_INVALID_FRAMEBUFFER_OPERATION", glFunc);
break;
//case GL_CONTEXT_LOST:
// sGL_DEBUG_CALLBACK("glError: GL_CONTEXT_LOST", glFunc);
// break;
//case GL_TABLE_TOO_LARGE:
// sGL_DEBUG_CALLBACK("glError: GL_TABLE_TOO_LARGE", glFunc);
// break;
default:
sGL_DEBUG_CALLBACK("glError: unknown", glFunc);
break;
}
}
void glDebug_CheckShaderCompile(const char* identifier, int handle)
{
GLint compiled;
GLD_CALL(glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled));
if (compiled != GL_TRUE && sGL_DEBUG_CALLBACK)
{
GLsizei log_length = 0;
GLchar message[1024];
GLD_CALL(glGetShaderInfoLog(handle, 1024, &log_length, message))
if (log_length < 1024)
{
message[log_length] = '\0';
}
else
{
message[log_length-1] = '\0';
}
sGL_DEBUG_CALLBACK((const char*)&message, identifier);
}
}
void glDebug_CheckProgramLink(const char* identifier, int handle)
{
GLint program_linked;
GLD_CALL(glGetProgramiv(handle, GL_LINK_STATUS, &program_linked));
if (program_linked != GL_TRUE)
{
GLsizei log_length = 0;
GLchar message[1024];
GLD_CALL(glGetProgramInfoLog(handle, 1024, &log_length, message));
if (log_length < 1024)
{
message[log_length] = '\0';
}
else
{
message[log_length-1] = '\0';
}
sGL_DEBUG_CALLBACK((const char*)&message, identifier);
}
}
#endif
#endif
#endif
#ifdef __cplusplus //extern C guard
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment