Index: source/gui/CGUIText.cpp =================================================================== --- source/gui/CGUIText.cpp +++ source/gui/CGUIText.cpp @@ -429,6 +429,10 @@ void CGUIText::Draw(CGUI& pGUI, const CGUIColor& DefaultColor, const CPos& pos, const float z, const CRect& clipping) const { +#ifndef NDEBUG + ogl_DebugGroup group("Draw GUI text"); +#endif + 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,10 @@ // TODO: batching by shader/texture/etc would be nice +#ifndef NDEBUG + ogl_DebugGroup group("Draw GUI element"); +#endif + CMatrix3D matrix = GetDefaultGuiMatrix(); glDisable(GL_BLEND); Index: source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- source/gui/ObjectTypes/CMiniMap.cpp +++ source/gui/ObjectTypes/CMiniMap.cpp @@ -380,6 +380,9 @@ void CMiniMap::Draw() { PROFILE3("render minimap"); +#ifndef NDEBUG + ogl_DebugGroup group("Render minimap"); +#endif // 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 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 @@ -125,10 +125,26 @@ 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 @@ -191,4 +191,23 @@ extern GLint ogl_max_tex_size; /// [pixels] extern GLint ogl_max_tex_units; /// limit on GL_TEXTUREn +#ifndef NDEBUG +/** + * RAII for glPushDebugGroupKHR() and pglPopDebugGroupKHR(). + */ +class ogl_DebugGroup +{ +public: + ogl_DebugGroup(const char* message) + { + pglPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION, 0x0ad, -1, message); + } + + ~ogl_DebugGroup() + { + pglPopDebugGroupKHR(); + } +}; +#endif + #endif // #ifndef INCLUDED_OGL Index: source/lib/ogl.cpp =================================================================== --- source/lib/ogl.cpp +++ source/lib/ogl.cpp @@ -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 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 @@ -202,6 +202,9 @@ void CLogger::Render() { PROFILE3_GPU("logger"); +#ifndef NDEBUG + ogl_DebugGroup group("Draw CLogger messages"); +#endif CleanupRenderQueue(); Index: source/renderer/Renderer.cpp =================================================================== --- source/renderer/Renderer.cpp +++ source/renderer/Renderer.cpp @@ -724,6 +724,9 @@ void CRenderer::RenderShadowMap(const CShaderDefines& context) { PROFILE3_GPU("shadow map"); +#ifndef NDEBUG + ogl_DebugGroup group("Render shadow map"); +#endif m->shadow.BeginRender(); @@ -759,6 +762,9 @@ void CRenderer::RenderPatches(const CShaderDefines& context, int cullGroup) { PROFILE3_GPU("patches"); +#ifndef NDEBUG + ogl_DebugGroup group("Render patches"); +#endif #if CONFIG2_GLES #warning TODO: implement wireface/edged rendering mode GLES @@ -815,6 +821,9 @@ void CRenderer::RenderModels(const CShaderDefines& context, int cullGroup) { PROFILE3_GPU("models"); +#ifndef NDEBUG + ogl_DebugGroup group("Render models"); +#endif int flags = 0; @@ -850,6 +859,9 @@ void CRenderer::RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling) { PROFILE3_GPU("transparent models"); +#ifndef NDEBUG + ogl_DebugGroup group("Render transparent models"); +#endif int flags = 0; @@ -1019,6 +1031,9 @@ void CRenderer::RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor) { PROFILE3_GPU("water reflections"); +#ifndef NDEBUG + ogl_DebugGroup group("Render water reflections"); +#endif // Save the post-processing framebuffer. GLint fbo; @@ -1089,8 +1104,6 @@ // rebind post-processing frambuffer. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - - return; } @@ -1099,6 +1112,9 @@ void CRenderer::RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned &scissor) { PROFILE3_GPU("water refractions"); +#ifndef NDEBUG + ogl_DebugGroup group("Render water refractions"); +#endif // Save the post-processing framebuffer. GLint fbo; @@ -1153,13 +1169,14 @@ // rebind post-processing frambuffer. pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); - - return; } void CRenderer::RenderSilhouettes(const CShaderDefines& context) { PROFILE3_GPU("silhouettes"); +#ifndef NDEBUG + ogl_DebugGroup group("Render silhouettes"); +#endif CShaderDefines contextOccluder = context; contextOccluder.Add(str_MODE_SILHOUETTEOCCLUDER, str_1); @@ -1265,6 +1282,9 @@ return; PROFILE3_GPU("particles"); +#ifndef NDEBUG + ogl_DebugGroup group("Render particles"); +#endif m->particleRenderer.RenderParticles(cullGroup); @@ -1298,6 +1318,9 @@ void CRenderer::RenderSubmissions(const CBoundingBoxAligned& waterScissor) { PROFILE3("render submissions"); +#ifndef NDEBUG + ogl_DebugGroup group("Render submissions"); +#endif GetScene().GetLOSTexture().InterpolateLOS(); @@ -1454,7 +1477,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,11 @@ L"top", L"top" }; + +#ifndef NDEBUG + ogl_DebugGroup group("Load sky textures"); +#endif + /*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 +149,6 @@ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); #endif glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - /////////////////////////////////////////////////////////////////////////// } @@ -193,6 +197,10 @@ // Render sky void SkyManager::RenderSky() { +#ifndef NDEBUG + ogl_DebugGroup group("Render sky"); +#endif + #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,9 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { PROFILE3_GPU("fancy water"); +#ifndef NDEBUG + ogl_DebugGroup group("Render fancy water"); +#endif WaterManager* WaterMgr = g_Renderer.GetWaterManager(); CShaderDefines defines = context; @@ -842,6 +845,10 @@ void TerrainRenderer::RenderSimpleWater(int cullGroup) { +#ifndef NDEBUG + ogl_DebugGroup group("Render simple water"); +#endif + #if CONFIG2_GLES UNUSED2(cullGroup); #else Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -481,6 +481,10 @@ // This requires m_DistanceHeightmap to be defined properly. void WaterManager::CreateWaveMeshes() { +#ifndef NDEBUG + ogl_DebugGroup group("Create wave meshes"); +#endif + if (m_MapSize == 0) return; @@ -876,6 +880,10 @@ if (g_Renderer.m_SkipSubmit || !m_WaterFancyEffects) return; +#ifndef NDEBUG + ogl_DebugGroup group("Render waves"); +#endif + pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO); GLuint attachments[2] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };