Index: libraries/win32/opengl/include/GL/glext.h =================================================================== --- libraries/win32/opengl/include/GL/glext.h +++ libraries/win32/opengl/include/GL/glext.h @@ -7,7 +7,7 @@ /* ** Copyright (c) 2007-2010 The Khronos Group Inc. -** +** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including @@ -15,10 +15,10 @@ ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are 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 Materials. -** +** ** THE MATERIALS ARE 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. @@ -2126,6 +2126,29 @@ #define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 #endif +#ifndef GL_debug_output +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_DEBUG_TYPE_OTHER 0x8251 +#endif + #ifndef GL_ARB_robustness /* reuse GL_NO_ERROR */ #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 Index: source/gui/CGUIText.cpp =================================================================== --- source/gui/CGUIText.cpp +++ source/gui/CGUIText.cpp @@ -429,6 +429,8 @@ void CGUIText::Draw(CGUI& pGUI, const CGUIColor& DefaultColor, const CPos& pos, const float z, const CRect& clipping) const { + ogl_DebugGroup group("Draw GUI text"); + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); tech->BeginPass(); Index: source/gui/GUIRenderer.cpp =================================================================== --- source/gui/GUIRenderer.cpp +++ source/gui/GUIRenderer.cpp @@ -337,6 +337,8 @@ // TODO: batching by shader/texture/etc would be nice + ogl_DebugGroup group("Draw GUI element"); + CMatrix3D matrix = GetDefaultGuiMatrix(); glDisable(GL_BLEND); Index: source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- source/gui/ObjectTypes/CMiniMap.cpp +++ source/gui/ObjectTypes/CMiniMap.cpp @@ -382,6 +382,7 @@ void CMiniMap::Draw() { PROFILE3("render minimap"); + ogl_DebugGroup group("Render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. Index: source/lib/external_libraries/glext_funcs.h =================================================================== --- source/lib/external_libraries/glext_funcs.h +++ source/lib/external_libraries/glext_funcs.h @@ -142,10 +142,25 @@ typedef GLuint GLhandleARB; +// GL_KHR_debug / GLES3.2 +typedef void (GL_APIENTRY *GLDEBUGPROCKHR)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam); +FUNC2(void, glDebugMessageCallbackKHR, glDebugMessageCallback, "3.2", (GLDEBUGPROCKHR callback, const GLvoid* userParam)) +FUNC2(void, glDebugMessageControlKHR, glDebugMessageControl, "3.2", (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled)) +FUNC2(void, glPushDebugGroupKHR, glPushDebugGroup, "3.2", (GLenum source, GLuint id, GLsizei length, const GLchar* message)) +FUNC2(void, glPopDebugGroupKHR, glPopDebugGroup, "3.2", (void)) +FUNC2(void, glObjectLabelKHR, glObjectLabel, "3.2", (GLenum identifier, GLuint name, GLsizei length, const GLchar* label)) #else // were these defined as real functions in gl.h already? +// GL_KHR_debug / GL4.3 +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam); +FUNC2(void, glDebugMessageCallbackKHR, glDebugMessageCallback, "4.3", (GLDEBUGPROC callback, const GLvoid* userParam)) +FUNC2(void, glDebugMessageControlKHR, glDebugMessageControl, "4.3", (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled)) +FUNC2(void, glPushDebugGroupKHR, glPushDebugGroup, "4.3", (GLenum source, GLuint id, GLsizei length, const GLchar* message)) +FUNC2(void, glPopDebugGroupKHR, glPopDebugGroup, "4.3", (void)) +FUNC2(void, glObjectLabelKHR, glObjectLabel, "4.3", (GLenum identifier, GLuint name, GLsizei length, const GLchar *label)) + // GL_EXT_draw_range_elements / GL1.2: FUNC2(void, glDrawRangeElementsEXT, glDrawRangeElements, "1.2", (GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoid*)) Index: source/lib/ogl.h =================================================================== --- source/lib/ogl.h +++ source/lib/ogl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -191,4 +191,29 @@ extern GLint ogl_max_tex_size; /// [pixels] extern GLint ogl_max_tex_units; /// limit on GL_TEXTUREn +#ifndef NDEBUG +/** + * RAII for glPushDebugGroupKHR() and pglPopDebugGroupKHR(). + */ +struct ogl_DebugGroup +{ + ogl_DebugGroup(const char* message) + { + pglPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 0x0ad, -1, message); + } + + ~ogl_DebugGroup() + { + pglPopDebugGroupKHR(); + } +}; +#else +// Fallback when we’re not debugging. +struct ogl_DebugGroup +{ + ogl_DebugGroup(const char* UNUSED(message)) {} + ~ogl_DebugGroup() {} +}; +#endif + #endif // #ifndef INCLUDED_OGL Index: source/lib/ogl.cpp =================================================================== --- source/lib/ogl.cpp +++ source/lib/ogl.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -421,6 +421,84 @@ debug_printf("%s:%d: OpenGL error(s) occurred: %s (%04x)\n", file, line, ogl_GetErrorName(first_error), (unsigned int)first_error); } +void APIENTRY ogl_OnDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei UNUSED(length), const GLchar* message, const void* UNUSED(user_param)) +{ + std::string str_source = "unknown"; + std::string str_type = "unknown"; + std::string str_severity = "unknown"; + + switch (source) + { + case GL_DEBUG_SOURCE_API: + str_source = "the API"; + break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + str_source = "the window system"; + break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + str_source = "the shader compiler"; + break; + case GL_DEBUG_SOURCE_THIRD_PARTY: + str_source = "a third party"; + break; + case GL_DEBUG_SOURCE_APPLICATION: + str_source = "the application"; + break; + case GL_DEBUG_SOURCE_OTHER: + str_source = "somewhere"; + break; + } + + switch (type) + { + case GL_DEBUG_TYPE_ERROR: + str_type = "error"; + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + str_type = "deprecated behaviour"; + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + str_type = "undefined behaviour"; + break; + case GL_DEBUG_TYPE_PORTABILITY: + str_type = "portability"; + break; + case GL_DEBUG_TYPE_PERFORMANCE: + str_type = "performance"; + break; + case GL_DEBUG_TYPE_OTHER: + str_type = "other"; + break; + case GL_DEBUG_TYPE_MARKER: + str_type = "marker"; + break; + case GL_DEBUG_TYPE_PUSH_GROUP: + str_type = "push group"; + break; + case GL_DEBUG_TYPE_POP_GROUP: + str_type = "pop group"; + break; + } + + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH: + str_severity = "high"; + break; + case GL_DEBUG_SEVERITY_MEDIUM: + str_severity = "medium"; + break; + case GL_DEBUG_SEVERITY_LOW: + str_severity = "low"; + break; + case GL_DEBUG_SEVERITY_NOTIFICATION: + str_severity = "notification"; + break; + } + + debug_printf("OpenGL %s of severity %s from %s id %d: %s\n", str_type.c_str(), str_severity.c_str(), str_source.c_str(), id, message); +} + // ignore and reset the specified error (as returned by glGetError). // any other errors that have occurred are reported as ogl_WarnIfError would. @@ -492,4 +570,22 @@ #if !CONFIG2_GLES glGetIntegerv(GL_MAX_TEXTURE_UNITS, &ogl_max_tex_units); #endif + +#ifndef NDEBUG +#if CONFIG2_GLES + bool is_core = ogl_HaveVersion("3.2"); +#else + bool is_core = ogl_HaveVersion("4.3"); +#endif + if (is_core || ogl_HaveExtension("GL_KHR_debug")) + { + glEnable(GL_DEBUG_OUTPUT); + pglDebugMessageCallbackKHR(ogl_OnDebugMessage, nullptr); + + // Filter out our own debug group messages + GLuint id = 0x0ad; + pglDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, GL_DONT_CARE, 1, &id, GL_FALSE); + pglDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, GL_DONT_CARE, 1, &id, GL_FALSE); + } +#endif } Index: source/lib/res/graphics/ogl_tex.cpp =================================================================== --- source/lib/res/graphics/ogl_tex.cpp +++ source/lib/res/graphics/ogl_tex.cpp @@ -480,6 +480,12 @@ if(ot->flags & OT_NEED_AUTO_UPLOAD) (void)ogl_tex_upload(h); +#ifndef NDEBUG + std::string name = pathname.string8(); + glBindTexture(GL_TEXTURE_2D, ot->id); + pglObjectLabelKHR(GL_TEXTURE, ot->id, name.size(), name.c_str()); +#endif + return INFO::OK; } Index: source/ps/CLogger.cpp =================================================================== --- source/ps/CLogger.cpp +++ source/ps/CLogger.cpp @@ -203,6 +203,7 @@ void CLogger::Render() { PROFILE3_GPU("logger"); + ogl_DebugGroup group("Draw CLogger messages"); CleanupRenderQueue(); Index: source/renderer/Renderer.cpp =================================================================== --- source/renderer/Renderer.cpp +++ source/renderer/Renderer.cpp @@ -719,6 +719,7 @@ void CRenderer::RenderShadowMap(const CShaderDefines& context) { PROFILE3_GPU("shadow map"); + ogl_DebugGroup group("Render shadow map"); m->shadow.BeginRender(); @@ -754,6 +755,7 @@ void CRenderer::RenderPatches(const CShaderDefines& context, int cullGroup) { PROFILE3_GPU("patches"); + ogl_DebugGroup group("Render patches"); #if CONFIG2_GLES #warning TODO: implement wireface/edged rendering mode GLES @@ -810,6 +812,7 @@ void CRenderer::RenderModels(const CShaderDefines& context, int cullGroup) { PROFILE3_GPU("models"); + ogl_DebugGroup group("Render models"); int flags = 0; @@ -845,6 +848,7 @@ void CRenderer::RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling) { PROFILE3_GPU("transparent models"); + ogl_DebugGroup group("Render transparent models"); int flags = 0; @@ -1014,6 +1018,7 @@ void CRenderer::RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor) { PROFILE3_GPU("water reflections"); + ogl_DebugGroup group("Render water reflections"); WaterManager& wm = m->waterManager; @@ -1246,6 +1251,7 @@ return; PROFILE3_GPU("particles"); + ogl_DebugGroup group("Render particles"); m->particleRenderer.RenderParticles(cullGroup); @@ -1279,6 +1285,7 @@ void CRenderer::RenderSubmissions(const CBoundingBoxAligned& waterScissor) { PROFILE3("render submissions"); + ogl_DebugGroup group("Render submissions"); GetScene().GetLOSTexture().InterpolateLOS(); @@ -1432,7 +1439,6 @@ // render overlays that should appear on top of all other objects m->overlayRenderer.RenderForegroundOverlays(m_ViewCamera); ogl_WarnIfError(); - } /////////////////////////////////////////////////////////////////////////////////////////////////// Index: source/renderer/SkyManager.cpp =================================================================== --- source/renderer/SkyManager.cpp +++ source/renderer/SkyManager.cpp @@ -58,6 +58,9 @@ L"top", L"top" }; + + ogl_DebugGroup group("Load sky textures"); + /*for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i) { VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds"); @@ -144,7 +147,6 @@ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); #endif glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - /////////////////////////////////////////////////////////////////////////// } @@ -193,6 +195,8 @@ // Render sky void SkyManager::RenderSky() { + ogl_DebugGroup group("Render sky"); + #if CONFIG2_GLES #warning TODO: implement SkyManager::RenderSky for GLES #else Index: source/renderer/TerrainRenderer.cpp =================================================================== --- source/renderer/TerrainRenderer.cpp +++ source/renderer/TerrainRenderer.cpp @@ -631,6 +631,7 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { PROFILE3_GPU("fancy water"); + ogl_DebugGroup group("Render fancy water"); WaterManager* WaterMgr = g_Renderer.GetWaterManager(); CShaderDefines defines = context; @@ -842,6 +843,8 @@ void TerrainRenderer::RenderSimpleWater(int cullGroup) { + ogl_DebugGroup group("Render simple water"); + #if CONFIG2_GLES UNUSED2(cullGroup); #else Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -481,6 +481,8 @@ // This requires m_DistanceHeightmap to be defined properly. void WaterManager::CreateWaveMeshes() { + ogl_DebugGroup group("Create wave meshes"); + if (m_MapSize == 0) return; @@ -876,6 +878,8 @@ if (g_Renderer.m_SkipSubmit || !m_WaterFancyEffects) return; + ogl_DebugGroup group("Render waves"); + pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); GLuint attachments[2] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };