diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 51f849f96..42e67b2d1 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -210,6 +210,18 @@ bool Graphics::setMode(int width, int height) glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &matrixLimit); matrixLimit -= 5; + bool enabledebug = false; + + if (GLEE_VERSION_3_0) + { + // Enable OpenGL's debug output if a debug context has been created. + GLint flags = 0; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + enabledebug = (flags & GL_CONTEXT_FLAG_DEBUG_BIT) != 0; + } + + setDebug(enabledebug); + return true; } @@ -226,6 +238,58 @@ void Graphics::unSetMode() gl.deInitContext(); } +static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, GLvoid* /*usr*/) +{ + // Human-readable strings for the debug info. + const char *sourceStr = OpenGL::debugSourceString(source); + const char *typeStr = OpenGL::debugTypeString(type); + const char *severityStr = OpenGL::debugSeverityString(severity); + + const char *fmt = "OpenGL: %s [source=%s, type=%s, severity=%s, id=%d]\n"; + printf(fmt, msg, sourceStr, typeStr, severityStr, id); +} + +void Graphics::setDebug(bool enable) +{ + // Make sure debug output is supported. The AMD ext. is a bit different + // so we don't make use of it, since AMD drivers now support KHR_debug. + if (!(GLEE_VERSION_4_3 || GLEE_KHR_debug || GLEE_ARB_debug_output)) + return; + + // Ugly hack to reduce code duplication. + if (GLEE_ARB_debug_output && !(GLEE_VERSION_4_3 || GLEE_KHR_debug)) + { + glDebugMessageCallback = (GLEEPFNGLDEBUGMESSAGECALLBACKPROC) glDebugMessageCallbackARB; + glDebugMessageControl = (GLEEPFNGLDEBUGMESSAGECONTROLPROC) glDebugMessageControlARB; + } + + if (!enable) + { + // Disable the debug callback function. + glDebugMessageCallback(nullptr, nullptr); + + // We can disable debug output entirely with KHR_debug. + if (GLEE_VERSION_4_3 || GLEE_KHR_debug) + glDisable(GL_DEBUG_OUTPUT); + + return; + } + + // We don't want asynchronous debug output. + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + + glDebugMessageCallback(debugCB, nullptr); + + // Initially, enable everything. + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); + + // Disable messages about deprecated OpenGL functionality. + glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); + glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); + + ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)"); +} + void Graphics::reset() { DisplayState s; diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 070794941..ecba2806e 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -115,6 +115,8 @@ public: virtual bool setMode(int width, int height); virtual void unSetMode(); + void setDebug(bool enable); + /** * Resets the current color, background color, * line style, and so forth. (This will be called diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index f07120f65..ee501cc33 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -601,6 +601,67 @@ OpenGL::Vendor OpenGL::getVendor() const return vendor; } +const char *OpenGL::debugSeverityString(GLenum severity) +{ + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + return "high"; + case GL_DEBUG_SEVERITY_MEDIUM: + return "medium"; + case GL_DEBUG_SEVERITY_LOW: + return "low"; + default: + break; + } + return "unknown"; +} + +const char *OpenGL::debugSourceString(GLenum source) +{ + switch (source) + { + case GL_DEBUG_SOURCE_API: + return "API"; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + return "window"; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + return "shader"; + case GL_DEBUG_SOURCE_THIRD_PARTY: + return "external"; + case GL_DEBUG_SOURCE_APPLICATION: + return "LOVE"; + case GL_DEBUG_SOURCE_OTHER: + return "other"; + default: + break; + } + return "unknown"; +} + +const char *OpenGL::debugTypeString(GLenum type) +{ + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + return "error"; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + return "deprecated behavior"; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + return "undefined behavior"; + case GL_DEBUG_TYPE_PERFORMANCE: + return "performance"; + case GL_DEBUG_TYPE_PORTABILITY: + return "portability"; + case GL_DEBUG_TYPE_OTHER: + return "other"; + default: + break; + } + return "unknown"; +} + + // OpenGL class instance singleton. OpenGL gl; diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 8e61c012e..2fd253381 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -230,6 +230,11 @@ public: **/ Vendor getVendor() const; + // Get human-readable strings for debug info. + static const char *debugSeverityString(GLenum severity); + static const char *debugSourceString(GLenum source); + static const char *debugTypeString(GLenum type); + private: void initVendor(); diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 0c94c8624..6f5f0f6e1 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -250,6 +250,18 @@ bool Window::setContext(int fsaa, bool vsync) context = SDL_GL_CreateContext(window); } + if (!context) + { + int flags = 0; + SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &flags); + if (flags & SDL_GL_CONTEXT_DEBUG_FLAG) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); + context = SDL_GL_CreateContext(window); + } + } + if (!context) { std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl; @@ -291,6 +303,19 @@ void Window::setWindowGLAttributes(int fsaa) const // FSAA. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); + + // Do we want a debug context? + const char *debugenv = SDL_GetHint("LOVE_GRAPHICS_DEBUG"); + if (debugenv && *debugenv == '1') + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + } + else + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); + } } void Window::updateSettings(const WindowSettings &newsettings)