From 8a972ee5fb9818aa2492d2e64f648010f44992d6 Mon Sep 17 00:00:00 2001 From: LHoG <1476261+lhog@users.noreply.github.com> Date: Fri, 7 Feb 2025 23:53:31 +0100 Subject: [PATCH 1/4] Allow adding debug annotations to OpenGL objects, as well as defining GPU zones to achieve functionality very similar to Tracy, but on the GPU. V2 --- rts/Lua/LuaConstGL.cpp | 28 ++++++++++++ rts/Lua/LuaOpenGL.cpp | 75 ++++++++++++++++++++++++++++++++ rts/Lua/LuaOpenGL.h | 4 ++ rts/Lua/LuaShaders.cpp | 4 +- rts/Lua/LuaVBO.cpp | 3 +- rts/Lua/LuaVBOImpl.cpp | 11 +++++ rts/Lua/LuaVBOImpl.h | 1 + rts/lib/headlessStubs/gladstub.h | 2 + rts/lib/headlessStubs/glstub.c | 4 ++ 9 files changed, 130 insertions(+), 2 deletions(-) diff --git a/rts/Lua/LuaConstGL.cpp b/rts/Lua/LuaConstGL.cpp index 495947b744..042858508e 100644 --- a/rts/Lua/LuaConstGL.cpp +++ b/rts/Lua/LuaConstGL.cpp @@ -704,9 +704,37 @@ bool LuaConstGL::PushEntries(lua_State* L) PUSH_GL(STENCIL_ATTACHMENT_EXT); return true; + + /****************************************************************************** + * OpenGL Object Types + * @section objecttypes + ******************************************************************************/ + + /// @field GL_BUFFER 0x82E0 + PUSH_GL(BUFFER); + /// @field GL_SHADER 0x82E1 + PUSH_GL(SHADER); + /// @field GL_PROGRAM 0x82E2 + PUSH_GL(PROGRAM); + /// @field GL_VERTEX_ARRAY 0x8074 + PUSH_GL(VERTEX_ARRAY); + /// @field GL_QUERY 0x82E3 + PUSH_GL(QUERY); + /// @field GL_PROGRAM_PIPELINE 0x82E4 + PUSH_GL(PROGRAM_PIPELINE); + /// @field GL_TRANSFORM_FEEDBACK 0x8E22 + PUSH_GL(TRANSFORM_FEEDBACK); + /// @field GL_RENDERBUFFER 0x8D41 + PUSH_GL(RENDERBUFFER); + /// @field GL_FRAMEBUFFER 0x8D40 + PUSH_GL(FRAMEBUFFER); + + return true; } + + /****************************************************************************** * Not included, but useful texture Formats * @section textureformats diff --git a/rts/Lua/LuaOpenGL.cpp b/rts/Lua/LuaOpenGL.cpp index 70f45a9a98..f7bd6a49fa 100644 --- a/rts/Lua/LuaOpenGL.cpp +++ b/rts/Lua/LuaOpenGL.cpp @@ -470,6 +470,12 @@ bool LuaOpenGL::PushEntries(lua_State* L) REGISTER_LUA_CFUNC(GetWaterRendering); REGISTER_LUA_CFUNC(GetMapRendering); + if (GLAD_GL_KHR_debug) { + REGISTER_LUA_CFUNC(ObjectLabel); + REGISTER_LUA_CFUNC(PushDebugGroup); + REGISTER_LUA_CFUNC(PopDebugGroup); + } + if (canUseShaders) LuaShaders::PushEntries(L); @@ -5667,5 +5673,74 @@ int LuaOpenGL::GetMapRendering(lua_State* L) return 0; } +/** + * @function gl.ObjectLabel labels an object for use with debugging tools + * @param objectTypeIdentifier GLenum Specifies the type of object being labeled. + * @param objectID GLuint Specifies the name or ID of the object to label. + * @param label string A string containing the label to be assigned to the object. + * @treturn nil + */ +int LuaOpenGL::ObjectLabel(lua_State* L) { + const auto identifier = static_cast(luaL_checkinteger(L, 1)); + + switch (identifier) { + case GL_BUFFER: [[fallthrough]]; + case GL_SHADER: [[fallthrough]]; + case GL_PROGRAM: [[fallthrough]]; + case GL_VERTEX_ARRAY: [[fallthrough]]; + case GL_QUERY: [[fallthrough]]; + case GL_PROGRAM_PIPELINE: [[fallthrough]]; + case GL_TRANSFORM_FEEDBACK: [[fallthrough]]; + case GL_TEXTURE: [[fallthrough]]; + case GL_RENDERBUFFER: [[fallthrough]]; + case GL_FRAMEBUFFER: + break; + default: { // something else + LOG_L(L_ERROR, "gl.%s: invalid identifier (%u)", __func__, identifier); + return 0; + } + } + + const auto objectID = static_cast(luaL_checkinteger(L, 2)); + const auto* label = luaL_checkstring(L, 3); + glObjectLabel(identifier, objectID, -1, label); + + return 0; +} + +// https://registry.khronos.org/OpenGL-Refpages/gl4/html/glPushDebugGroup.xhtml +/** + * @function gl.PushDebugGroup pushes a debug marker for nVidia nSight 2024.04, does not seem to work when FBO's are raw bound + * @param id GLuint A numeric identifier for the group. + * @param message string A human-readable string describing the debug group. + * @param source boolean true for GL_DEBUG_SOURCE_APPLICATION, false for GL_DEBUG_SOURCE_THIRD_PARTY. default false + * @treturn nil + */ +int LuaOpenGL::PushDebugGroup(lua_State* L) { + const auto id = static_cast(luaL_checkinteger(L, 1)); + const auto* message = luaL_checkstring(L, 2); + const bool source = luaL_optboolean(L, 3, false); + + GLint maxLength = 0; + glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &maxLength); + + if (strlen(message) >= maxLength) { + LOG_L(L_ERROR, "gl.%s: Message length exceeds GL_MAX_DEBUG_MESSAGE_LENGTH (%u)", __func__, maxLength); + return 0; + } + + glPushDebugGroup((source ? GL_DEBUG_SOURCE_APPLICATION : GL_DEBUG_SOURCE_THIRD_PARTY), id, -1, message); + return 0; +} + +/** + * @function gl.PopDebugGroup + * @treturn nil + */ +int LuaOpenGL::PopDebugGroup(lua_State* L) { + glPopDebugGroup(); + return 0; +} + /******************************************************************************/ /******************************************************************************/ diff --git a/rts/Lua/LuaOpenGL.h b/rts/Lua/LuaOpenGL.h index 8a9630f84c..0fbcbb57e5 100644 --- a/rts/Lua/LuaOpenGL.h +++ b/rts/Lua/LuaOpenGL.h @@ -353,6 +353,10 @@ class LuaOpenGL { static int GetSun(lua_State* L); static int GetWaterRendering(lua_State* L); static int GetMapRendering(lua_State* L); + + static int ObjectLabel(lua_State* L); + static int PushDebugGroup(lua_State* L); + static int PopDebugGroup(lua_State* L); }; inline void LuaOpenGL::InitMatrixState(lua_State* L, const char* fn) { diff --git a/rts/Lua/LuaShaders.cpp b/rts/Lua/LuaShaders.cpp index 37f64b568d..e2caad1131 100644 --- a/rts/Lua/LuaShaders.cpp +++ b/rts/Lua/LuaShaders.cpp @@ -780,7 +780,9 @@ int LuaShaders::CreateShader(lua_State* L) // note: index, not raw ID lua_pushnumber(L, shaders.AddProgram(p)); - return 1; + // also push the program ID + lua_pushnumber(L, (int)prog); + return 2; } diff --git a/rts/Lua/LuaVBO.cpp b/rts/Lua/LuaVBO.cpp index 9a725c5d87..63f6afaeba 100644 --- a/rts/Lua/LuaVBO.cpp +++ b/rts/Lua/LuaVBO.cpp @@ -63,7 +63,8 @@ bool LuaVBOs::PushEntries(lua_State* L) "UnbindBufferRange", &LuaVBOImpl::UnbindBufferRange, "DumpDefinition", &LuaVBOImpl::DumpDefinition, - "GetBufferSize", &LuaVBOImpl::GetBufferSize + "GetBufferSize", &LuaVBOImpl::GetBufferSize, + "GetID", & LuaVBOImpl::GetID ); gl.set("VBO", sol::lua_nil); // don't want this to be accessible directly without gl.GetVBO diff --git a/rts/Lua/LuaVBOImpl.cpp b/rts/Lua/LuaVBOImpl.cpp index 0d4793ac14..4655fcffd5 100644 --- a/rts/Lua/LuaVBOImpl.cpp +++ b/rts/Lua/LuaVBOImpl.cpp @@ -1486,6 +1486,17 @@ void LuaVBOImpl::DumpDefinition() LOG("%s", ss.str().c_str()); } +/*** Gets the OpenGL Buffer ID + * + * @function VBO:GetID + * @treturn number buffer ID + */ +uint32_t LuaVBOImpl::GetID() const +{ + VBOExistenceCheck(vbo, __func__); + return vbo->GetId(); +} + void LuaVBOImpl::AllocGLBuffer(size_t byteSize) { if (defTarget == GL_UNIFORM_BUFFER && bufferSizeInBytes > UBO_SAFE_SIZE_BYTES) { diff --git a/rts/Lua/LuaVBOImpl.h b/rts/Lua/LuaVBOImpl.h index 8c6ca3d996..95d3c4ddd1 100644 --- a/rts/Lua/LuaVBOImpl.h +++ b/rts/Lua/LuaVBOImpl.h @@ -52,6 +52,7 @@ class LuaVBOImpl { int UnbindBufferRange(const GLuint index, const sol::optional elemOffsetOpt, const sol::optional elemCountOpt, const sol::optional targetOpt); void DumpDefinition(); + uint32_t GetID() const; public: static bool Supported(GLenum target); private: diff --git a/rts/lib/headlessStubs/gladstub.h b/rts/lib/headlessStubs/gladstub.h index 1056e6ece0..b8c1169d8c 100644 --- a/rts/lib/headlessStubs/gladstub.h +++ b/rts/lib/headlessStubs/gladstub.h @@ -107,6 +107,8 @@ extern "C" { #define GLAD_GL_ARB_base_instance GL_FALSE #define GLAD_GL_ARB_sample_shading GL_FALSE +#define GLAD_GL_KHR_debug GL_FALSE + #define GLXEW_SGI_video_sync GL_FALSE int gladLoadGL(void); diff --git a/rts/lib/headlessStubs/glstub.c b/rts/lib/headlessStubs/glstub.c index e1e3820264..85651deca1 100644 --- a/rts/lib/headlessStubs/glstub.c +++ b/rts/lib/headlessStubs/glstub.c @@ -605,6 +605,10 @@ GLAPI void APIENTRY glDepthRange(GLdouble nearVal, GLdouble farVal) {} GLAPI void APIENTRY glBeginConditionalRender(GLuint id, GLenum mode) {} GLAPI void APIENTRY glEndConditionalRender(void) {} +GLAPI void APIENTRY glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar* label) {} +GLAPI void APIENTRY glPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar* message) {} +GLAPI void APIENTRY glPopDebugGroup() {} + #ifdef __cplusplus } // extern "C" #endif From 1753461e893b760c7e28d5c8d81dc8257c535ec6 Mon Sep 17 00:00:00 2001 From: LHoG <1476261+lhog@users.noreply.github.com> Date: Fri, 7 Feb 2025 23:57:53 +0100 Subject: [PATCH 2/4] Misc --- rts/Lua/LuaShaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rts/Lua/LuaShaders.cpp b/rts/Lua/LuaShaders.cpp index e2caad1131..2bbed6e037 100644 --- a/rts/Lua/LuaShaders.cpp +++ b/rts/Lua/LuaShaders.cpp @@ -781,7 +781,7 @@ int LuaShaders::CreateShader(lua_State* L) // note: index, not raw ID lua_pushnumber(L, shaders.AddProgram(p)); // also push the program ID - lua_pushnumber(L, (int)prog); + lua_pushnumber(L, prog); return 2; } From b6191c1fdc1ff3a39137d531c0a9259ee9438be6 Mon Sep 17 00:00:00 2001 From: lhog <1476261+lhog@users.noreply.github.com> Date: Mon, 10 Feb 2025 15:24:57 +0100 Subject: [PATCH 3/4] Update rts/Lua/LuaOpenGL.cpp Co-authored-by: sprunk --- rts/Lua/LuaOpenGL.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/rts/Lua/LuaOpenGL.cpp b/rts/Lua/LuaOpenGL.cpp index f7bd6a49fa..2d1977d8cc 100644 --- a/rts/Lua/LuaOpenGL.cpp +++ b/rts/Lua/LuaOpenGL.cpp @@ -5718,18 +5718,22 @@ int LuaOpenGL::ObjectLabel(lua_State* L) { */ int LuaOpenGL::PushDebugGroup(lua_State* L) { const auto id = static_cast(luaL_checkinteger(L, 1)); - const auto* message = luaL_checkstring(L, 2); + std::string message = luaL_checkstring(L, 2); const bool source = luaL_optboolean(L, 3, false); GLint maxLength = 0; glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &maxLength); - - if (strlen(message) >= maxLength) { - LOG_L(L_ERROR, "gl.%s: Message length exceeds GL_MAX_DEBUG_MESSAGE_LENGTH (%u)", __func__, maxLength); + if (maxLength <= 0) return 0; + + if (message.length() >= maxLength) { + static constexpr std::string_view TRIM = "(...)"; + message.resize(maxLength - TRIM.length() - 1); + message += TRIM; + assert(message.length() < maxLength); } - glPushDebugGroup((source ? GL_DEBUG_SOURCE_APPLICATION : GL_DEBUG_SOURCE_THIRD_PARTY), id, -1, message); + glPushDebugGroup((source ? GL_DEBUG_SOURCE_APPLICATION : GL_DEBUG_SOURCE_THIRD_PARTY), id, -1, message.c_str()); return 0; } From 0dec6ee92e9383d24757d64636ac3a839c3c7f13 Mon Sep 17 00:00:00 2001 From: sprunk Date: Tue, 11 Feb 2025 17:36:35 +0100 Subject: [PATCH 4/4] glPushDebugGroup: default to source APPLICATION --- rts/Lua/LuaOpenGL.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rts/Lua/LuaOpenGL.cpp b/rts/Lua/LuaOpenGL.cpp index 2d1977d8cc..7cbef72bff 100644 --- a/rts/Lua/LuaOpenGL.cpp +++ b/rts/Lua/LuaOpenGL.cpp @@ -5713,13 +5713,13 @@ int LuaOpenGL::ObjectLabel(lua_State* L) { * @function gl.PushDebugGroup pushes a debug marker for nVidia nSight 2024.04, does not seem to work when FBO's are raw bound * @param id GLuint A numeric identifier for the group. * @param message string A human-readable string describing the debug group. - * @param source boolean true for GL_DEBUG_SOURCE_APPLICATION, false for GL_DEBUG_SOURCE_THIRD_PARTY. default false + * @param sourceIsThirdParty boolean Set the source tag, true for GL_DEBUG_SOURCE_THIRD_PARTY, false for GL_DEBUG_SOURCE_APPLICATION. default false * @treturn nil */ int LuaOpenGL::PushDebugGroup(lua_State* L) { const auto id = static_cast(luaL_checkinteger(L, 1)); std::string message = luaL_checkstring(L, 2); - const bool source = luaL_optboolean(L, 3, false); + const bool sourceIsThirdParty = luaL_optboolean(L, 3, false); GLint maxLength = 0; glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &maxLength); @@ -5733,7 +5733,7 @@ int LuaOpenGL::PushDebugGroup(lua_State* L) { assert(message.length() < maxLength); } - glPushDebugGroup((source ? GL_DEBUG_SOURCE_APPLICATION : GL_DEBUG_SOURCE_THIRD_PARTY), id, -1, message.c_str()); + glPushDebugGroup((sourceIsThirdParty ? GL_DEBUG_SOURCE_THIRD_PARTY : GL_DEBUG_SOURCE_APPLICATION), id, -1, message.c_str()); return 0; }