Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions rts/Game/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1436,7 +1436,7 @@ bool CGame::Draw() {
const spring_time currentTimePreDraw = spring_gettime();

SCOPED_SPECIAL_TIMER("Draw");
SCOPED_GL_DEBUGGROUP("Draw");
SCOPED_GL_GPU_ZONE("Draw");
globalRendering->SetGLTimeStamp(CGlobalRendering::FRAME_REF_TIME_QUERY_IDX);

SetDrawMode(gameNormalDraw);
Expand Down Expand Up @@ -1510,7 +1510,7 @@ bool CGame::Draw() {

{
SCOPED_TIMER("Draw::Screen");
SCOPED_GL_DEBUGGROUP("Draw::Screen");
SCOPED_GL_GPU_ZONE("Draw::Screen");
if (CUnitDrawer::UseScreenIcons())
unitDrawer->DrawUnitIconsScreen();

Expand Down Expand Up @@ -1566,12 +1566,12 @@ void CGame::DrawInputReceivers()
{
// this has MANUAL ordering, draw it last (front-most)
SCOPED_TIMER("Draw::Screen::DrawScreen");
SCOPED_GL_DEBUGGROUP("Draw::Screen::DrawScreen");
SCOPED_GL_GPU_ZONE("Draw::Screen::DrawScreen");
luaInputReceiver->Draw();
}
} else {
SCOPED_TIMER("Draw::Screen::Minimap");
SCOPED_GL_DEBUGGROUP("Draw::Screen::Minimap");
SCOPED_GL_GPU_ZONE("Draw::Screen::Minimap");

if (globalRendering->dualScreenMode) {
// minimap is on its own screen, so always draw it
Expand Down
21 changes: 21 additions & 0 deletions rts/Lua/LuaHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "Game/UI/KeySet.h"
#include "Game/UI/MiniMap.h"
#include "Rendering/GlobalRendering.h"
#include "Rendering/GL/myGL.h" // for Tracy GPU zones around Lua draw call-ins
#include "Rml/Backends/RmlUi_Backend.h"
#include "Sim/Misc/GlobalSynced.h"
#include "Sim/Misc/TeamHandler.h"
Expand Down Expand Up @@ -175,6 +176,7 @@ CLuaHandle::CLuaHandle(const string& _name, int _order, bool _userMode, bool _sy
#ifdef TRACY_ENABLE
lua_getglobal(L, "tracy");
LuaTracyExtra::PushEntries(L);
LuaTracyExtra::PushGpuProfile(L); // absent unless the TracyLuaGpuZones config is set
lua_pop(L, 1);
#endif
}
Expand Down Expand Up @@ -2686,6 +2688,19 @@ void CLuaHandle::RunDrawCallIn(const LuaHashString& hs)
if (!hs.GetGlobalFunc(L))
return;

// Coarse per-phase GPU zone: one bar per phase per Lua state (e.g.
// "LuaUI::DrawWorld") summing all widgets/gadgets for that phase. Begin/end
// live entirely in C++ around the dispatch, so the LIFO query stream stays
// balanced. Transient zone because the name is built at runtime.
// NB: also fires if a Lua state draws during loading on the secondary
// context, but TRACY_ON_DEMAND early-returns when no server is attached and
// TracyGpuCollect runs only in the steady-state frame loop, so any stray
// load-time queries are self-limiting.
#if !defined(HEADLESS) && defined(TRACY_ENABLE)
const std::string gpuZoneName = GetName() + "::" + hs.GetString();
TracyGpuZoneTransient(__luaGpuZone, gpuZoneName.c_str(), true);
#endif

LuaOpenGL::SetDrawingEnabled(L, true);

// call the routine
Expand Down Expand Up @@ -2856,6 +2871,12 @@ inline void CLuaHandle::DrawScreenCommon(const LuaHashString& cmdStr)
if (!cmdStr.GetGlobalFunc(L))
return;

// per-phase GPU zone (e.g. "LuaUI::DrawScreen"); see RunDrawCallIn
#if !defined(HEADLESS) && defined(TRACY_ENABLE)
const std::string gpuZoneName = GetName() + "::" + cmdStr.GetString();
TracyGpuZoneTransient(__luaGpuZone, gpuZoneName.c_str(), true);
#endif

lua_pushnumber(L, globalRendering->viewSizeX);
lua_pushnumber(L, globalRendering->viewSizeY);

Expand Down
21 changes: 21 additions & 0 deletions rts/Lua/LuaRBOs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,40 @@

#include "LuaRBOs.h"

#include <algorithm>

#include "LuaInclude.h"

#include "LuaHandle.h"
#include "LuaHashString.h"
#include "LuaUtils.h"
#include "Rendering/GlobalRendering.h"
#include "Rendering/GL/GpuMemTracy.h"
#include "Rendering/Textures/TextureFormat.h"


/******************************************************************************
* RBO
* @see rts/Lua/LuaRBOs.cpp
******************************************************************************/

#if defined(TRACY_ENABLE)
// Estimate of the renderbuffer VRAM footprint for Tracy GPU memory tracking; the
// data type is inferred from the internal format.
static size_t EstimateRBOBytes(const LuaRBOs::RBO& rbo)
{
const size_t texelBytes =
GL::GetNumChannelsFromInternalFormat(rbo.format) *
GL::GetDataTypeSize(GL::GetDataTypeFromInternalFormat(rbo.format));

return size_t(rbo.xsize) * rbo.ysize * std::max(rbo.samples, GLsizei(1)) * texelBytes;
}
#endif

LuaRBOs::~LuaRBOs()
{
for (const RBO* rbo: rbos) {
GPU_MEM_FREE(GL::GpuMemPoolLuaRBOs, rbo->id);
glDeleteRenderbuffersEXT(1, &rbo->id);
}
}
Expand Down Expand Up @@ -80,6 +98,7 @@ void LuaRBOs::RBO::Free(lua_State* L)
if (id == 0)
return;

GPU_MEM_FREE(GL::GpuMemPoolLuaRBOs, id);
glDeleteRenderbuffersEXT(1, &id);
id = 0;

Expand Down Expand Up @@ -220,6 +239,8 @@ int LuaRBOs::CreateRBO(lua_State* L)
lua_setmetatable(L, -2);

if (rboPtr->id != 0) {
GPU_MEM_ALLOC(GL::GpuMemPoolLuaRBOs, rboPtr->id, EstimateRBOBytes(*rboPtr));

LuaRBOs& activeRBOs = CLuaHandle::GetActiveRBOs(L);
auto& rbos = activeRBOs.rbos;

Expand Down
26 changes: 26 additions & 0 deletions rts/Lua/LuaTextures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Rendering/Textures/TextureFormat.h"
#include "Rendering/GlobalRendering.h"
#include "Rendering/GL/FBO.h"
#include "Rendering/GL/GpuMemTracy.h"
#include "Rendering/GL/TexBind.h"
#include "System/SpringMath.h"
#include "System/StringUtil.h"
Expand Down Expand Up @@ -34,6 +35,25 @@ namespace Impl {
}
}

#if defined(TRACY_ENABLE)
// Estimate of the base-level VRAM footprint for Tracy GPU memory tracking. Ignores
// mipmaps and compression; the data type is inferred from the internal format.
static size_t EstimateTextureBytes(const LuaTextures::Texture& tex)
{
const size_t texelBytes =
GL::GetNumChannelsFromInternalFormat(tex.format) *
GL::GetDataTypeSize(GL::GetDataTypeFromInternalFormat(tex.format));

size_t texels = std::max(tex.xsize, GLsizei(1));
if (tex.ysize > 0) texels *= tex.ysize;
if (tex.zsize > 0) texels *= tex.zsize;
if (tex.target == GL_TEXTURE_CUBE_MAP) texels *= 6;
if (tex.target == GL_TEXTURE_2D_MULTISAMPLE && tex.samples > 1) texels *= tex.samples;

return texels * texelBytes;
}
#endif

/******************************************************************************/
/******************************************************************************/

Expand Down Expand Up @@ -143,6 +163,10 @@ std::string LuaTextures::Create(const Texture& tex)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFBO);
}

// storage is fully allocated; attribute its VRAM to the Tracy pool. Reached only
// on success, so the early-return failure paths above need no matching free.
GPU_MEM_ALLOC(GL::GpuMemPoolLuaTextures, texID, EstimateTextureBytes(tex));

std::string str = fmt::format("{}{}", prefix, ++lastCode);

Texture newTex = tex;
Expand Down Expand Up @@ -184,6 +208,7 @@ bool LuaTextures::Free(const std::string& name)

if (it != textureMap.end()) {
const Texture& tex = textureVec[it->second];
GPU_MEM_FREE(GL::GpuMemPoolLuaTextures, tex.id);
glDeleteTextures(1, &tex.id);

if (FBO::IsSupported()) {
Expand Down Expand Up @@ -225,6 +250,7 @@ void LuaTextures::FreeAll()
{
for (const auto& item: textureMap) {
const Texture& tex = textureVec[item.second];
GPU_MEM_FREE(GL::GpuMemPoolLuaTextures, tex.id);
glDeleteTextures(1, &tex.id);

if (FBO::IsSupported()) {
Expand Down
58 changes: 58 additions & 0 deletions rts/Lua/LuaTracyExtra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@
#include "LuaUtils.h"

#include "System/Misc/TracyDefs.h"
#include "System/Config/ConfigHandler.h"
#include "Rendering/GL/myGL.h" // gated Tracy GPU-zone macros (TracyGpuZoneTransient)
#include <common/TracyQueue.hpp>

#include <functional>
#include <set>
#include <string>

CONFIG(bool, TracyLuaGpuZones)
.defaultValue(false)
.description("Register tracy.GpuProfile for per-widget/gadget GPU zones (dev/profiling only)");

/* Tracy seems to want unique, unchanging strings to be passed to
* its API, so we need to immanentize the ephemeral Lua strings
* by storing them.
Expand Down Expand Up @@ -80,3 +86,55 @@ bool LuaTracyExtra::PushEntries(lua_State* L)
LuaPushNamedCFunc(L, "LuaTracyPlotConfig", LuaTracyPlotConfig);
return true;
}

/*** Profile the GPU work submitted by a function as one Tracy GPU zone
*
* @function tracy.GpuProfile
* @param name string zone label (e.g. the widget/gadget name)
* @param fn function the call to profile
* @param ... any arguments forwarded to `fn`
* @return ... whatever `fn` returns
*
* Wraps `fn(...)` in a GPU zone whose begin/end are emitted in C++ around a
* protected call, so the LIFO GPU query stream stays balanced even if `fn`
* errors. Meant to be driven from a handler's central per-addon dispatch, not
* called by individual widgets/gadgets. Measures GPU execution time of what was
* submitted (shaders, overdraw) — not CPU/Lua cost. Only present when the
* `TracyLuaGpuZones` config is set; a transparent passthrough under HEADLESS or
* when no GPU profiling context exists.
*/
static int LuaTracyGpuProfile(lua_State* L)
{
[[maybe_unused]] const char* zoneName = luaL_checkstring(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION);

// stack: [name, fn, arg1 .. argN]; lua_pcall consumes fn + its N args and
// leaves fn's results above `name` (which stays at index 1).
const int numArgs = lua_gettop(L) - 2;

int callStatus;
{
// Begin/end bracket the protected call in C++ (RAII), so the query
// stream is always balanced: a Lua error is caught by lua_pcall and
// never longjmps past this scope. `active` is false when no GPU context
// exists (e.g. no ARB_timer_query), which avoids a null-context deref.
#if !defined(HEADLESS) && defined(TRACY_ENABLE)
TracyGpuZoneTransient(___luaGpuProfileZone, zoneName, tracy::GetGpuCtx().ptr != nullptr);
#endif
callStatus = lua_pcall(L, numArgs, LUA_MULTRET, 0);
}

if (callStatus != 0)
return lua_error(L); // re-raise now that the zone has closed

return lua_gettop(L) - 1; // fn's results (everything above `name`)
}

bool LuaTracyExtra::PushGpuProfile(lua_State* L)
{
if (configHandler == nullptr || !configHandler->GetBool("TracyLuaGpuZones"))
return false;

LuaPushNamedCFunc(L, "GpuProfile", LuaTracyGpuProfile);
return true;
}
5 changes: 5 additions & 0 deletions rts/Lua/LuaTracyExtra.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ struct lua_State;

namespace LuaTracyExtra {
bool PushEntries(lua_State* L);

// Registers tracy.GpuProfile, but only when the TracyLuaGpuZones config is
// enabled — otherwise the function is absent from the Lua environment so it
// cannot be called. Returns whether it was registered.
bool PushGpuProfile(lua_State* L);
};
4 changes: 2 additions & 2 deletions rts/Map/SMF/ROAM/RoamMeshDrawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ void CRoamMeshDrawer::DrawMesh(const DrawPass::e& drawPass)

{
SCOPED_TIMER("Draw::World::Terrain::ROAM::Draw");
SCOPED_GL_DEBUGGROUP("Draw::World::Terrain::ROAM::Draw");
SCOPED_GL_GPU_ZONE("Draw::World::Terrain::ROAM::Draw");
for (Patch& p: patchMeshGrid[drawPass == DrawPass::Shadow]) {
if (!p.IsVisible(CCameraHandler::GetActiveCamera()))
continue;
Expand All @@ -494,7 +494,7 @@ void CRoamMeshDrawer::DrawBorderMesh(const DrawPass::e& drawPass)
{
RECOIL_DETAILED_TRACY_ZONE;
SCOPED_TIMER("Draw::World::Terrain::ROAM::DrawBorderMesh");
SCOPED_GL_DEBUGGROUP("Draw::World::Terrain::ROAM::DrawBorderMesh");
SCOPED_GL_GPU_ZONE("Draw::World::Terrain::ROAM::DrawBorderMesh");
for (const Patch* p: borderPatches[drawPass == DrawPass::Shadow]) {
if (!p->IsVisible(CCameraHandler::GetActiveCamera()))
continue;
Expand Down
1 change: 1 addition & 0 deletions rts/Rendering/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ set(sources_engine_Rendering
"${CMAKE_CURRENT_SOURCE_DIR}/GL/RenderBuffers.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/VBO.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/VAO.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/GpuMemTracyHooks.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/glExtra.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/State.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/myGL.cpp"
Expand Down
4 changes: 2 additions & 2 deletions rts/Rendering/Env/IWater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ void IWater::DrawReflections(const double* clipPlaneEqs, bool drawGround, bool d
drawReflection = true;

SCOPED_TIMER("Draw::Water::DrawReflections");
SCOPED_GL_DEBUGGROUP("Draw::Water::DrawReflections");
SCOPED_GL_GPU_ZONE("Draw::Water::DrawReflections");

// opaque; do not clip skydome (is drawn in camera space)
if (drawSky) {
Expand Down Expand Up @@ -186,7 +186,7 @@ void IWater::DrawRefractions(const double* clipPlaneEqs, bool drawGround, bool d
drawRefraction = true;

SCOPED_TIMER("Draw::Water::DrawRefractions");
SCOPED_GL_DEBUGGROUP("Draw::Water::DrawRefractions");
SCOPED_GL_GPU_ZONE("Draw::Water::DrawRefractions");

glEnable(GL_CLIP_PLANE2);
glClipPlane(GL_CLIP_PLANE2, &clipPlaneEqs[0]);
Expand Down
Loading
Loading