Add r_glDebugContext to enable OpenGL debug context and -callback

needs SDL2 and GL_ARB_debug_output
This commit is contained in:
Daniel Gibson 2024-06-16 01:41:46 +02:00
parent 47bd8afa91
commit 69e121727d
5 changed files with 122 additions and 3 deletions

View file

@ -78,6 +78,7 @@ typedef struct glconfig_s {
bool twoSidedStencilAvailable;
bool textureNonPowerOfTwoAvailable;
bool depthBoundsTestAvailable;
bool glDebugOutputAvailable;
// GL framebuffer size, see also winWidth and winHeight
int vidWidth, vidHeight; // passed to R_BeginFrame
@ -95,6 +96,8 @@ typedef struct glconfig_s {
bool shouldFillWindowAlpha;
bool isWayland; // DG: for other wayland-specific hacks.. (does *not* detect XWayland!)
bool haveDebugContext;
// For some reason people decided that we need displays with ultra small pixels,
// so everything rendered on them must be scaled up to be legible.
// unfortunately, this bullshit feature was "improved" upon by deciding that the best

View file

@ -239,6 +239,8 @@ idCVar r_screenshotPngCompression("r_screenshotPngCompression", "3", CVAR_RENDER
idCVar r_windowResizable("r_windowResizable", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Allow resizing (and maximizing) the window (needs SDL2; with 2.0.5 or newer it's applied immediately)" );
idCVar r_vidRestartAlwaysFull( "r_vidRestartAlwaysFull", 0, CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Always do a full vid_restart (ignore 'partial' argument), e.g. when changing window size" );
idCVar r_glDebugContext( "r_glDebugContext", "0", CVAR_RENDERER | CVAR_BOOL, "Enable OpenGL Debug context - requires vid_restart, needs SDL2" );
// define qgl functions
#define QGLPROC(name, rettype, args) rettype (APIENTRYP q##name) args;
#include "renderer/qgl_proc.h"
@ -288,6 +290,9 @@ PFNGLDEPTHBOUNDSEXTPROC qglDepthBoundsEXT;
// DG: couldn't find any extension for this, it's supported in GL2.0 and newer, incl OpenGL ES2.0
PFNGLSTENCILOPSEPARATEPROC qglStencilOpSeparate;
// GL_ARB_debug_output
PFNGLDEBUGMESSAGECALLBACKARBPROC qglDebugMessageCallbackARB;
// eez: This is a slight hack for letting us select the desired screenshot format in other functions
// This is a hack to avoid adding another function parameter to idRenderSystem::TakeScreenshot(),
// which would break the API of the dhewm3 SDK for mods.
@ -296,6 +301,60 @@ PFNGLSTENCILOPSEPARATEPROC qglStencilOpSeparate;
// it must set g_screenshotFormat accordingly before each call to TakeScreenshot().
int g_screenshotFormat = -1;
enum {
// Not all GL.h header know about GL_DEBUG_SEVERITY_NOTIFICATION_*.
QGL_DEBUG_SEVERITY_NOTIFICATION = 0x826B
};
/*
* Callback function for debug output.
*/
static void APIENTRY
DebugCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar *message, const void *userParam )
{
const char* sourceStr = "Source: Unknown";
const char* typeStr = "Type: Unknown";
const char* severityStr = "Severity: Unknown";
switch (severity)
{
#define SVRCASE(X, STR) case GL_DEBUG_SEVERITY_ ## X ## _ARB : severityStr = STR; break;
case QGL_DEBUG_SEVERITY_NOTIFICATION: return;
SVRCASE(HIGH, "Severity: High")
SVRCASE(MEDIUM, "Severity: Medium")
SVRCASE(LOW, "Severity: Low")
#undef SVRCASE
}
switch (source)
{
#define SRCCASE(X) case GL_DEBUG_SOURCE_ ## X ## _ARB: sourceStr = "Source: " #X; break;
SRCCASE(API);
SRCCASE(WINDOW_SYSTEM);
SRCCASE(SHADER_COMPILER);
SRCCASE(THIRD_PARTY);
SRCCASE(APPLICATION);
SRCCASE(OTHER);
#undef SRCCASE
}
switch(type)
{
#define TYPECASE(X) case GL_DEBUG_TYPE_ ## X ## _ARB: typeStr = "Type: " #X; break;
TYPECASE(ERROR);
TYPECASE(DEPRECATED_BEHAVIOR);
TYPECASE(UNDEFINED_BEHAVIOR);
TYPECASE(PORTABILITY);
TYPECASE(PERFORMANCE);
TYPECASE(OTHER);
#undef TYPECASE
}
common->Warning( "GLDBG %s %s %s: %s\n", sourceStr, typeStr, severityStr, message );
}
/*
=================
R_CheckExtension
@ -415,15 +474,15 @@ static void R_CheckPortableExtensions( void ) {
qglActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC)GLimp_ExtensionPointer( "glActiveStencilFaceEXT" );
if( glConfig.glVersion >= 2.0) {
common->Printf( "... got GL2.0+ glStencilOpSeparate()\n" );
common->Printf( "...got GL2.0+ glStencilOpSeparate()\n" );
qglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)GLimp_ExtensionPointer( "glStencilOpSeparate" );
} else if( R_CheckExtension( "GL_ATI_separate_stencil" ) ) {
common->Printf( "... got glStencilOpSeparateATI() (GL_ATI_separate_stencil)\n" );
common->Printf( "...got glStencilOpSeparateATI() (GL_ATI_separate_stencil)\n" );
// the ATI version of glStencilOpSeparate() has the same signature and should also
// behave identical to the GL2 version (in Mesa3D it's just an alias)
qglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)GLimp_ExtensionPointer( "glStencilOpSeparateATI" );
} else {
common->Printf( "... don't have glStencilOpSeparateATI() or (GL2.0+) glStencilOpSeparate()\n" );
common->Printf( "X..don't have glStencilOpSeparateATI() or (GL2.0+) glStencilOpSeparate()\n" );
qglStencilOpSeparate = NULL;
}
@ -482,6 +541,37 @@ static void R_CheckPortableExtensions( void ) {
qglDepthBoundsEXT = (PFNGLDEPTHBOUNDSEXTPROC)GLimp_ExtensionPointer( "glDepthBoundsEXT" );
}
// GL_ARB_debug_output
glConfig.glDebugOutputAvailable = false;
if ( glConfig.haveDebugContext ) {
if ( strstr( glConfig.extensions_string, "GL_ARB_debug_output" ) ) {
glConfig.glDebugOutputAvailable = true;
qglDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)GLimp_ExtensionPointer( "glDebugMessageCallbackARB" );
if ( r_glDebugContext.GetBool() ) {
common->Printf( "...using GL_ARB_debug_output (r_glDebugContext is set)\n" );
qglDebugMessageCallbackARB(DebugCallback, NULL);
qglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
} else {
common->Printf( "...found GL_ARB_debug_output, but not using it (r_glDebugContext is not set)\n" );
}
} else {
common->Printf( "X..GL_ARB_debug_output not found\n" );
qglDebugMessageCallbackARB = NULL;
if ( r_glDebugContext.GetBool() ) {
common->Warning( "r_glDebugContext is set, but can't be used because GL_ARB_debug_output is not supported" );
}
}
} else {
if ( strstr( glConfig.extensions_string, "GL_ARB_debug_output" ) ) {
if ( r_glDebugContext.GetBool() ) {
common->Printf( "...found GL_ARB_debug_output, but not using it (no debug context)\n" );
} else {
common->Printf( "...found GL_ARB_debug_output, but not using it (r_glDebugContext is not set)\n" );
}
} else {
common->Printf( "X..GL_ARB_debug_output not found\n" );
}
}
}

View file

@ -119,6 +119,9 @@ extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC qglProgramLocalParameter4fvARB;
// GL_EXT_depth_bounds_test
extern PFNGLDEPTHBOUNDSEXTPROC qglDepthBoundsEXT;
// GL_ARB_debug_output
extern PFNGLDEBUGMESSAGECALLBACKARBPROC qglDebugMessageCallbackARB;
#if defined( _WIN32 ) && defined(ID_ALLOW_TOOLS)
extern BOOL(WINAPI * qwglSwapBuffers)(HDC);

View file

@ -983,6 +983,8 @@ extern idCVar r_materialOverride; // override all materials
extern idCVar r_debugRenderToTexture;
extern idCVar r_glDebugContext;
/*
====================================================================

View file

@ -279,6 +279,11 @@ try_again:
#if SDL_VERSION_ATLEAST(2, 0, 0)
if ( r_glDebugContext.GetBool() ) {
common->Printf( "Requesting an OpenGL Debug Context (r_glDebugContext is enabled)\n" );
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
}
if ( parms.fullScreen && parms.fullScreenDesktop ) {
common->Printf( "Will create a pseudo-fullscreen window at the current desktop resolution\n" );
} else {
@ -435,6 +440,10 @@ try_again:
if (SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, r_swapInterval.GetInteger()) < 0)
common->Warning("SDL_GL_SWAP_CONTROL not supported");
if ( r_glDebugContext.GetBool() ) {
common->Warning( "r_glDebugContext is set, but not supported by SDL1.2!\n" );
}
r_swapInterval.ClearModified();
window = SDL_SetVideoMode(parms.width, parms.height, colorbits, flags);
@ -588,6 +597,18 @@ try_again:
}
#endif
glConfig.haveDebugContext = false;
#if SDL_VERSION_ATLEAST(2, 0, 0)
int cflags = 0;
if ( SDL_GL_GetAttribute( SDL_GL_CONTEXT_FLAGS, &cflags ) == 0 ) {
glConfig.haveDebugContext = (cflags & SDL_GL_CONTEXT_DEBUG_FLAG) != 0;
if ( glConfig.haveDebugContext )
common->Printf( "Got a debug context!\n" );
else if( r_glDebugContext.GetBool() ) {
common->Warning( "Requested a debug context, but didn't get one!\n" );
}
}
#endif
break;
}