diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp index b2e0427ee..9dd6a868e 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp @@ -59,10 +59,14 @@ namespace Nz::GL protected: virtual const Loader& GetLoader() = 0; - virtual bool ImplementFallback(const std::string_view& function) = 0; + virtual bool ImplementFallback(const std::string_view& function); std::unordered_set m_supportedExtensions; ContextParams m_params; + + private: + void GL_APIENTRY HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const; + }; } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp index b7794db79..20057430b 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp @@ -8,10 +8,12 @@ #define NAZARA_OPENGLRENDERER_COREFUNCTIONS_HPP #define GL_GLES_PROTOTYPES 0 -#include +#include +#include + // OpenGL core -#define NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(cb) \ +#define NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(cb, extCb) \ cb(glActiveTexture, PFNGLACTIVETEXTUREPROC) \ cb(glAttachShader, PFNGLATTACHSHADERPROC) \ cb(glBeginQuery, PFNGLBEGINQUERYPROC) \ @@ -139,5 +141,7 @@ cb(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) \ cb(glVertexAttribIPointer, PFNGLVERTEXATTRIBIPOINTERPROC) \ cb(glViewport, PFNGLVIEWPORTPROC) \ + \ + extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ #endif diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 8c651ff33..a431a9c72 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -32,8 +32,10 @@ namespace Nz::GL try { -#define NAZARA_OPENGLRENDERER_FUNC(name, sig) LoadSymbol(name, #name); - NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC) +#define NAZARA_OPENGLRENDERER_FUNC(name, sig) LoadSymbol(name, #name, true); +#define NAZARA_OPENGLRENDERER_EXT_FUNC(name, sig) //< Do nothing + NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_EXT_FUNC) +#undef NAZARA_OPENGLRENDERER_EXT_FUNC #undef NAZARA_OPENGLRENDERER_FUNC } catch (const std::exception& e) @@ -68,6 +70,12 @@ namespace Nz::GL return true; }); +#define NAZARA_OPENGLRENDERER_FUNC(name, sig) +#define NAZARA_OPENGLRENDERER_EXT_FUNC(name, sig) LoadSymbol(name, #name, false); + NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_EXT_FUNC) +#undef NAZARA_OPENGLRENDERER_EXT_FUNC +#undef NAZARA_OPENGLRENDERER_FUNC + // If we requested an OpenGL ES context but cannot create one, check for some compatibility extensions if (params.type == ContextType::OpenGL_ES && m_params.type != params.type) { @@ -93,6 +101,136 @@ namespace Nz::GL NazaraWarning("desktop support for OpenGL ES is missing, falling back to OpenGL..."); } + // Set debug callback (if supported) + if (glDebugMessageCallback) + { + glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) + { + const Context* context = static_cast(userParam); + context->HandleDebugMessage(source, type, id, severity, length, message); + }, this); + } + return true; } + + bool Context::ImplementFallback(const std::string_view& function) + { + const Loader& loader = GetLoader(); + + auto LoadSymbol = [&](auto& func, const char* funcName) -> bool + { + func = reinterpret_cast>(loader.LoadFunction(funcName)); + return func; + }; + + if (function == "glDebugMessageCallback") + { + if (!LoadSymbol(glDebugMessageCallback, "glDebugMessageCallbackARB")) + return LoadSymbol(glDebugMessageCallback, "DebugMessageCallbackAMD"); + + return true; + } + + return false; + } + + void Context::HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const + { + std::stringstream ss; + ss << "OpenGL debug message (ID: 0x" << std::to_string(id) << "):\n"; + ss << "Sent by context: " << this; + ss << "\n-Source: "; + switch (source) + { + case GL_DEBUG_SOURCE_API: + ss << "OpenGL API"; + break; + + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + ss << "Operating system"; + break; + + case GL_DEBUG_SOURCE_SHADER_COMPILER: + ss << "Shader compiler"; + break; + + case GL_DEBUG_SOURCE_THIRD_PARTY: + ss << "Third party"; + break; + + case GL_DEBUG_SOURCE_APPLICATION: + ss << "Application"; + break; + + case GL_DEBUG_SOURCE_OTHER: + ss << "Other"; + break; + + default: + // Peut être rajouté par une extension + ss << "Unknown"; + break; + } + ss << '\n'; + + ss << "-Type: "; + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + ss << "Error"; + break; + + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + ss << "Deprecated behavior"; + break; + + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + ss << "Undefined behavior"; + break; + + case GL_DEBUG_TYPE_PORTABILITY: + ss << "Portability"; + break; + + case GL_DEBUG_TYPE_PERFORMANCE: + ss << "Performance"; + break; + + case GL_DEBUG_TYPE_OTHER: + ss << "Other"; + break; + + default: + // Peut être rajouté par une extension + ss << "Unknown"; + break; + } + ss << '\n'; + + ss << "-Severity: "; + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + ss << "High"; + break; + + case GL_DEBUG_SEVERITY_MEDIUM: + ss << "Medium"; + break; + + case GL_DEBUG_SEVERITY_LOW: + ss << "Low"; + break; + + default: + ss << "Unknown"; + break; + } + ss << '\n'; + + ss << "Message: " << std::string_view(message, length) << '\n'; + + NazaraNotice(ss.str()); + } } diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp index b46d38e28..c354032db 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp @@ -229,6 +229,9 @@ namespace Nz::GL bool WGLContext::ImplementFallback(const std::string_view& function) { + if (Context::ImplementFallback(function)) + return true; + if (m_params.type == ContextType::OpenGL_ES) return false; //< Implement fallback only for OpenGL (when emulating OpenGL ES)