mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Removes GL code from the common GPU profiler.
This commit is contained in:
parent
6ef6a87287
commit
0b33921c06
16 changed files with 150 additions and 185 deletions
|
|
@ -558,7 +558,7 @@ netwarnings = "true" ; Show warnings if the network connection is b
|
|||
|
||||
[profiler2]
|
||||
autoenable = false ; Enable HTTP server output at startup (default off for security/performance)
|
||||
gpu.arb.enable = true ; Allow GL_ARB_timer_query timing mode when available.
|
||||
gpu.enable = true ; Allow GPU timing mode when available.
|
||||
|
||||
[rlinterface]
|
||||
address = "127.0.0.1:6000"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -433,7 +433,7 @@ std::optional<bool> CGUIManager::TickObjects()
|
|||
|
||||
void CGUIManager::Draw(CCanvas2D& canvas) const
|
||||
{
|
||||
PROFILE3_GPU("gui");
|
||||
PROFILE3("gui");
|
||||
|
||||
for (const SGUIPage& p : m_PageStack)
|
||||
p.gui->Draw(canvas);
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ void CConsole::Render(CCanvas2D& canvas)
|
|||
if (!(m_Visible || m_Toggle))
|
||||
return;
|
||||
|
||||
PROFILE3_GPU("console");
|
||||
PROFILE3("console");
|
||||
|
||||
DrawWindow(canvas);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -169,7 +169,7 @@ void CLogger::WriteWarning(const char* message)
|
|||
|
||||
void CLogger::Render(CCanvas2D& canvas)
|
||||
{
|
||||
PROFILE3_GPU("logger");
|
||||
PROFILE3("logger");
|
||||
|
||||
CleanupRenderQueue();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -165,6 +165,6 @@ public:
|
|||
#define PROFILE3(name) PROFILE(name); PROFILE2(name)
|
||||
|
||||
// Also do GPU
|
||||
#define PROFILE3_GPU(name) PROFILE(name); PROFILE2(name); PROFILE2_GPU(name)
|
||||
#define PROFILE3_GPU(deviceCommandContext, name) PROFILE(name); PROFILE2(name); PROFILE2_GPU(deviceCommandContext, name)
|
||||
|
||||
#endif // INCLUDED_PROFILE
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void CProfileViewer::RenderProfile(CCanvas2D& canvas)
|
|||
return;
|
||||
}
|
||||
|
||||
PROFILE3_GPU("profile viewer");
|
||||
PROFILE3("profile viewer");
|
||||
|
||||
AbstractProfileTable* table = m->path[m->path.size() - 1];
|
||||
const std::vector<ProfileColumn>& columns = table->GetColumns();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -256,28 +256,28 @@ void CProfiler2::Shutdown()
|
|||
m_Initialised = false;
|
||||
}
|
||||
|
||||
void CProfiler2::RecordGPUFrameStart()
|
||||
void CProfiler2::RecordGPUFrameStart(Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
if (m_GPU)
|
||||
m_GPU->FrameStart();
|
||||
m_GPU->FrameStart(deviceCommandContext);
|
||||
}
|
||||
|
||||
void CProfiler2::RecordGPUFrameEnd()
|
||||
void CProfiler2::RecordGPUFrameEnd(Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
if (m_GPU)
|
||||
m_GPU->FrameEnd();
|
||||
m_GPU->FrameEnd(deviceCommandContext);
|
||||
}
|
||||
|
||||
void CProfiler2::RecordGPURegionEnter(const char* id)
|
||||
void CProfiler2::RecordGPURegionEnter(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id)
|
||||
{
|
||||
if (m_GPU)
|
||||
m_GPU->RegionEnter(id);
|
||||
m_GPU->RegionEnter(deviceCommandContext, id);
|
||||
}
|
||||
|
||||
void CProfiler2::RecordGPURegionLeave(const char* id)
|
||||
void CProfiler2::RecordGPURegionLeave(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id)
|
||||
{
|
||||
if (m_GPU)
|
||||
m_GPU->RegionLeave(id);
|
||||
m_GPU->RegionLeave(deviceCommandContext, id);
|
||||
}
|
||||
|
||||
void CProfiler2::RegisterCurrentThread(const std::string& name)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -86,6 +86,14 @@
|
|||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
namespace Backend
|
||||
{
|
||||
class IDeviceCommandContext;
|
||||
}
|
||||
}
|
||||
|
||||
struct mg_context;
|
||||
|
||||
// Note: Lots of functions are defined inline, to hypothetically
|
||||
|
|
@ -95,7 +103,7 @@ class CProfiler2GPU;
|
|||
|
||||
class CProfiler2
|
||||
{
|
||||
friend class CProfiler2GPUARB;
|
||||
friend class CProfiler2GPUImpl;
|
||||
public:
|
||||
// Items stored in the buffers:
|
||||
|
||||
|
|
@ -327,10 +335,10 @@ public:
|
|||
va_end(argp);
|
||||
}
|
||||
|
||||
void RecordGPUFrameStart();
|
||||
void RecordGPUFrameEnd();
|
||||
void RecordGPURegionEnter(const char* id);
|
||||
void RecordGPURegionLeave(const char* id);
|
||||
void RecordGPUFrameStart(Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
|
||||
void RecordGPUFrameEnd(Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
|
||||
void RecordGPURegionEnter(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id);
|
||||
void RecordGPURegionLeave(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id);
|
||||
|
||||
/**
|
||||
* Call in any thread to produce a JSON representation of the general
|
||||
|
|
@ -418,15 +426,17 @@ protected:
|
|||
class CProfile2GPURegion
|
||||
{
|
||||
public:
|
||||
CProfile2GPURegion(const char* name) : m_Name(name)
|
||||
CProfile2GPURegion(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* name)
|
||||
: m_DeviceCommandContext(deviceCommandContext), m_Name(name)
|
||||
{
|
||||
g_Profiler2.RecordGPURegionEnter(m_Name);
|
||||
g_Profiler2.RecordGPURegionEnter(m_DeviceCommandContext, m_Name);
|
||||
}
|
||||
~CProfile2GPURegion()
|
||||
{
|
||||
g_Profiler2.RecordGPURegionLeave(m_Name);
|
||||
g_Profiler2.RecordGPURegionLeave(m_DeviceCommandContext, m_Name);
|
||||
}
|
||||
private:
|
||||
Renderer::Backend::IDeviceCommandContext* m_DeviceCommandContext;
|
||||
const char* m_Name;
|
||||
};
|
||||
|
||||
|
|
@ -439,7 +449,7 @@ private:
|
|||
*/
|
||||
#define PROFILE2(region) CProfile2Region profile2__(region)
|
||||
|
||||
#define PROFILE2_GPU(region) CProfile2GPURegion profile2gpu__(region)
|
||||
#define PROFILE2_GPU(deviceCommandContext, region) CProfile2GPURegion profile2gpu__(deviceCommandContext, region)
|
||||
|
||||
/**
|
||||
* Record the named event at the current time.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -24,35 +24,29 @@
|
|||
|
||||
#include "Profiler2GPU.h"
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/Profiler2.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "renderer/backend/IDevice.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
#include <deque>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
|
||||
/*
|
||||
* GL_ARB_timer_query supports sync and async queries for absolute GPU
|
||||
* timestamps, which lets us time regions of code relative to the CPU.
|
||||
* At the start of a frame, we record the CPU time and sync GPU timestamp,
|
||||
* giving the time-vs-timestamp offset.
|
||||
/**
|
||||
* At each enter/leave-region event, we do an async GPU timestamp query.
|
||||
* When all the queries for a frame have their results available,
|
||||
* we convert their GPU timestamps into CPU times and record the data.
|
||||
* we convert their GPU timestamps into durations and record the data.
|
||||
*/
|
||||
class CProfiler2GPUARB
|
||||
class CProfiler2GPUImpl
|
||||
{
|
||||
NONCOPYABLE(CProfiler2GPUARB);
|
||||
NONCOPYABLE(CProfiler2GPUImpl);
|
||||
|
||||
struct SEvent
|
||||
{
|
||||
const char* id;
|
||||
GLuint query;
|
||||
uint32_t queryHandle;
|
||||
bool isEnter; // true if entering region; false if leaving
|
||||
};
|
||||
|
||||
|
|
@ -60,8 +54,7 @@ class CProfiler2GPUARB
|
|||
{
|
||||
u32 num;
|
||||
|
||||
double syncTimeStart; // CPU time at start of maybe this frame or a recent one
|
||||
GLint64 syncTimestampStart; // GL timestamp corresponding to timeStart
|
||||
double syncTimeStart; // CPU time at start of this frame.
|
||||
|
||||
std::vector<SEvent> events;
|
||||
};
|
||||
|
|
@ -69,45 +62,35 @@ class CProfiler2GPUARB
|
|||
std::deque<SFrame> m_Frames;
|
||||
|
||||
public:
|
||||
static bool IsSupported()
|
||||
CProfiler2GPUImpl(CProfiler2& profiler)
|
||||
: m_Profiler(profiler), m_Storage(*new CProfiler2::ThreadStorage(profiler, "gpu"))
|
||||
{
|
||||
if (g_VideoMode.GetBackendDevice()->GetBackend() != Renderer::Backend::Backend::GL)
|
||||
return false;
|
||||
return ogl_HaveExtension("GL_ARB_timer_query");
|
||||
}
|
||||
|
||||
CProfiler2GPUARB(CProfiler2& profiler)
|
||||
: m_Profiler(profiler), m_Storage(*new CProfiler2::ThreadStorage(profiler, "gpu_arb"))
|
||||
{
|
||||
// TODO: maybe we should check QUERY_COUNTER_BITS to ensure it's
|
||||
// high enough (but apparently it might trigger GL errors on ATI)
|
||||
|
||||
m_Storage.RecordSyncMarker(m_Profiler.GetTime());
|
||||
m_Storage.Record(CProfiler2::ITEM_EVENT, m_Profiler.GetTime(), "thread start");
|
||||
|
||||
m_Profiler.AddThreadStorage(&m_Storage);
|
||||
}
|
||||
|
||||
~CProfiler2GPUARB()
|
||||
~CProfiler2GPUImpl()
|
||||
{
|
||||
// Pop frames to return queries to the free list
|
||||
while (!m_Frames.empty())
|
||||
PopFrontFrame();
|
||||
|
||||
if (!m_FreeQueries.empty())
|
||||
glDeleteQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]);
|
||||
ogl_WarnIfError();
|
||||
for (const uint32_t queryHandle : m_FreeQueries)
|
||||
g_VideoMode.GetBackendDevice()->FreeQuery(queryHandle);
|
||||
m_FreeQueries.clear();
|
||||
|
||||
m_Profiler.RemoveThreadStorage(&m_Storage);
|
||||
}
|
||||
|
||||
void FrameStart()
|
||||
void FrameStart(Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
ProcessFrames();
|
||||
|
||||
SFrame frame;
|
||||
frame.num = m_Profiler.GetFrameNumber();
|
||||
|
||||
// GL backend:
|
||||
// On (at least) some NVIDIA Windows drivers, when GPU-bound, or when
|
||||
// vsync enabled and not CPU-bound, the first glGet* call at the start
|
||||
// of a frame appears to trigger a wait (to stop the GPU getting too
|
||||
|
|
@ -116,90 +99,81 @@ public:
|
|||
// reported results. So we'll only do it fairly rarely, and for most
|
||||
// frames we'll just assume the clocks don't drift much
|
||||
|
||||
const double RESYNC_PERIOD = 1.0; // seconds
|
||||
|
||||
double now = m_Profiler.GetTime();
|
||||
|
||||
if (m_Frames.empty() || now > m_Frames.back().syncTimeStart + RESYNC_PERIOD)
|
||||
{
|
||||
PROFILE2("profile timestamp resync");
|
||||
|
||||
glGetInteger64v(GL_TIMESTAMP, &frame.syncTimestampStart);
|
||||
ogl_WarnIfError();
|
||||
|
||||
frame.syncTimeStart = m_Profiler.GetTime();
|
||||
// (Have to do GetTime again after GL_TIMESTAMP, because GL_TIMESTAMP
|
||||
// might wait a while before returning its now-current timestamp)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reuse the previous frame's sync data
|
||||
frame.syncTimeStart = m_Frames[m_Frames.size()-1].syncTimeStart;
|
||||
frame.syncTimestampStart = m_Frames[m_Frames.size()-1].syncTimestampStart;
|
||||
}
|
||||
// Timestamps might shift and overflow for all backends. So for
|
||||
// simplicity we don't synchronize the frame start on CPU and GPU. As
|
||||
// we only need durations. We just roughly assume that the first
|
||||
// timestamp on GPU matches the CPU frame start. For real timestamps
|
||||
// it's better to use GPU Trace instruments.
|
||||
|
||||
frame.syncTimeStart = m_Profiler.GetTime();
|
||||
m_Frames.push_back(frame);
|
||||
|
||||
RegionEnter("frame");
|
||||
RegionEnter(deviceCommandContext, "frame");
|
||||
}
|
||||
|
||||
void FrameEnd()
|
||||
void FrameEnd(Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
RegionLeave("frame");
|
||||
RegionLeave(deviceCommandContext, "frame");
|
||||
}
|
||||
|
||||
void RecordRegion(const char* id, bool isEnter)
|
||||
void RecordRegion(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id, bool isEnter)
|
||||
{
|
||||
ENSURE(!m_Frames.empty());
|
||||
SFrame& frame = m_Frames.back();
|
||||
|
||||
SEvent event;
|
||||
event.id = id;
|
||||
event.query = NewQuery();
|
||||
event.queryHandle = NewQuery();
|
||||
event.isEnter = isEnter;
|
||||
|
||||
glQueryCounter(event.query, GL_TIMESTAMP);
|
||||
ogl_WarnIfError();
|
||||
deviceCommandContext->InsertTimestampQuery(event.queryHandle, isEnter);
|
||||
|
||||
frame.events.push_back(event);
|
||||
}
|
||||
|
||||
void RegionEnter(const char* id)
|
||||
void RegionEnter(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id)
|
||||
{
|
||||
RecordRegion(id, true);
|
||||
RecordRegion(deviceCommandContext, id, true);
|
||||
}
|
||||
|
||||
void RegionLeave(const char* id)
|
||||
void RegionLeave(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id)
|
||||
{
|
||||
RecordRegion(id, false);
|
||||
RecordRegion(deviceCommandContext, id, false);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void ProcessFrames()
|
||||
{
|
||||
Renderer::Backend::IDevice* device{g_VideoMode.GetBackendDevice()};
|
||||
while (!m_Frames.empty())
|
||||
{
|
||||
SFrame& frame = m_Frames.front();
|
||||
|
||||
// Queries become available in order so we only need to check the last one
|
||||
GLint available = 0;
|
||||
glGetQueryObjectivARB(frame.events.back().query, GL_QUERY_RESULT_AVAILABLE, &available);
|
||||
ogl_WarnIfError();
|
||||
if (!available)
|
||||
// We assume queries become available in order so we only need to
|
||||
// check the last one.
|
||||
if (!device->IsQueryResultAvailable(frame.events.back().queryHandle))
|
||||
break;
|
||||
|
||||
// The frame's queries are now available, so retrieve and record all their results:
|
||||
// We use the first event GPU timestamp as a frame start.
|
||||
const uint64_t firstFrameTimestamp{!frame.events.empty()
|
||||
? device->GetQueryResult(frame.events[0].queryHandle) : 0u};
|
||||
|
||||
const double timestampMultiplier{
|
||||
device->GetCapabilities().timestampMultiplier};
|
||||
|
||||
std::vector<std::pair<int, uint64_t>> stack;
|
||||
|
||||
// The frame's queries are now available, so retrieve and record all their results:
|
||||
for (size_t i = 0; i < frame.events.size(); ++i)
|
||||
{
|
||||
GLuint64 queryTimestamp = 0;
|
||||
glGetQueryObjectui64v(frame.events[i].query, GL_QUERY_RESULT, &queryTimestamp);
|
||||
// (use the non-suffixed function here, as defined by GL_ARB_timer_query)
|
||||
ogl_WarnIfError();
|
||||
const uint64_t queryTimestamp{
|
||||
i == 0 ? firstFrameTimestamp : device->GetQueryResult(frame.events[i].queryHandle)};
|
||||
ENSURE(queryTimestamp >= firstFrameTimestamp);
|
||||
|
||||
// Convert to absolute CPU-clock time
|
||||
double t = frame.syncTimeStart + (double)(queryTimestamp - frame.syncTimestampStart) / 1e9;
|
||||
const double t{
|
||||
frame.syncTimeStart + static_cast<double>(queryTimestamp - firstFrameTimestamp) * timestampMultiplier};
|
||||
|
||||
// Record a frame-start for syncing
|
||||
if (i == 0)
|
||||
|
|
@ -224,83 +198,60 @@ private:
|
|||
ENSURE(!m_Frames.empty());
|
||||
SFrame& frame = m_Frames.front();
|
||||
for (size_t i = 0; i < frame.events.size(); ++i)
|
||||
m_FreeQueries.push_back(frame.events[i].query);
|
||||
m_FreeQueries.push_back(frame.events[i].queryHandle);
|
||||
m_Frames.pop_front();
|
||||
}
|
||||
|
||||
// Returns a new GL query object (or a recycled old one)
|
||||
GLuint NewQuery()
|
||||
// Returns a new backend query handle (or a recycled old one).
|
||||
uint32_t NewQuery()
|
||||
{
|
||||
if (m_FreeQueries.empty())
|
||||
{
|
||||
// Generate a batch of new queries
|
||||
m_FreeQueries.resize(8);
|
||||
glGenQueriesARB(m_FreeQueries.size(), &m_FreeQueries[0]);
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
return g_VideoMode.GetBackendDevice()->AllocateQuery();
|
||||
|
||||
GLuint query = m_FreeQueries.back();
|
||||
const uint32_t queryHandle{m_FreeQueries.back()};
|
||||
m_FreeQueries.pop_back();
|
||||
return query;
|
||||
return queryHandle;
|
||||
}
|
||||
|
||||
CProfiler2& m_Profiler;
|
||||
CProfiler2::ThreadStorage& m_Storage;
|
||||
|
||||
std::vector<GLuint> m_FreeQueries; // query objects that are allocated but not currently in used
|
||||
std::vector<uint32_t> m_FreeQueries; // query objects that are allocated but not currently in used
|
||||
};
|
||||
|
||||
CProfiler2GPU::CProfiler2GPU(CProfiler2& profiler) :
|
||||
m_Profiler(profiler)
|
||||
{
|
||||
if (g_ConfigDB.Get("profiler2.gpu.arb.enable", false) && CProfiler2GPUARB::IsSupported())
|
||||
if (g_ConfigDB.Get("profiler2.gpu.enable", false) && g_VideoMode.GetBackendDevice()->GetCapabilities().timestamps)
|
||||
{
|
||||
m_ProfilerARB = std::make_unique<CProfiler2GPUARB>(m_Profiler);
|
||||
m_Impl = std::make_unique<CProfiler2GPUImpl>(m_Profiler);
|
||||
}
|
||||
}
|
||||
|
||||
CProfiler2GPU::~CProfiler2GPU() = default;
|
||||
|
||||
void CProfiler2GPU::FrameStart()
|
||||
void CProfiler2GPU::FrameStart(Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
if (m_ProfilerARB)
|
||||
m_ProfilerARB->FrameStart();
|
||||
if (m_Impl)
|
||||
m_Impl->FrameStart(deviceCommandContext);
|
||||
}
|
||||
|
||||
void CProfiler2GPU::FrameEnd()
|
||||
void CProfiler2GPU::FrameEnd(Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
if (m_ProfilerARB)
|
||||
m_ProfilerARB->FrameEnd();
|
||||
if (m_Impl)
|
||||
m_Impl->FrameEnd(deviceCommandContext);
|
||||
}
|
||||
|
||||
void CProfiler2GPU::RegionEnter(const char* id)
|
||||
void CProfiler2GPU::RegionEnter(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id)
|
||||
{
|
||||
if (m_ProfilerARB)
|
||||
m_ProfilerARB->RegionEnter(id);
|
||||
if (m_Impl)
|
||||
m_Impl->RegionEnter(deviceCommandContext, id);
|
||||
}
|
||||
|
||||
void CProfiler2GPU::RegionLeave(const char* id)
|
||||
void CProfiler2GPU::RegionLeave(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id)
|
||||
{
|
||||
if (m_ProfilerARB)
|
||||
m_ProfilerARB->RegionLeave(id);
|
||||
if (m_Impl)
|
||||
m_Impl->RegionLeave(deviceCommandContext, id);
|
||||
}
|
||||
|
||||
#else // CONFIG2_GLES
|
||||
|
||||
class CProfiler2GPUARB
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
CProfiler2GPU::CProfiler2GPU(CProfiler2& UNUSED(profiler))
|
||||
{
|
||||
}
|
||||
|
||||
CProfiler2GPU::~CProfiler2GPU() = default;
|
||||
|
||||
void CProfiler2GPU::FrameStart() { }
|
||||
void CProfiler2GPU::FrameEnd() { }
|
||||
void CProfiler2GPU::RegionEnter(const char* UNUSED(id)) { }
|
||||
void CProfiler2GPU::RegionLeave(const char* UNUSED(id)) { }
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
@ -20,12 +20,18 @@
|
|||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lib/config2.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class CProfiler2;
|
||||
class CProfiler2GPUARB;
|
||||
class CProfiler2GPUImpl;
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
namespace Backend
|
||||
{
|
||||
class IDeviceCommandContext;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by CProfiler2 for GPU profiling support.
|
||||
|
|
@ -38,15 +44,12 @@ public:
|
|||
CProfiler2GPU(CProfiler2& profiler);
|
||||
~CProfiler2GPU();
|
||||
|
||||
void FrameStart();
|
||||
void FrameEnd();
|
||||
void RegionEnter(const char* id);
|
||||
void RegionLeave(const char* id);
|
||||
void FrameStart(Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
|
||||
void FrameEnd(Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
|
||||
void RegionEnter(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id);
|
||||
void RegionLeave(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const char* id);
|
||||
|
||||
private:
|
||||
#if !CONFIG2_GLES
|
||||
CProfiler2& m_Profiler;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<CProfiler2GPUARB> m_ProfilerARB;
|
||||
std::unique_ptr<CProfiler2GPUImpl> m_Impl;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -481,7 +481,7 @@ void OverlayRenderer::Upload(
|
|||
void OverlayRenderer::RenderOverlaysBeforeWater(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
PROFILE3_GPU("overlays (before)");
|
||||
PROFILE3("overlays (before)");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render overlays before water");
|
||||
|
||||
for (SOverlayLine* line : m->lines)
|
||||
|
|
@ -496,7 +496,7 @@ void OverlayRenderer::RenderOverlaysBeforeWater(
|
|||
void OverlayRenderer::RenderOverlaysAfterWater(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
PROFILE3_GPU("overlays (after)");
|
||||
PROFILE3("overlays (after)");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render overlays after water");
|
||||
|
||||
RenderTexturedOverlayLines(deviceCommandContext);
|
||||
|
|
@ -656,7 +656,7 @@ void OverlayRenderer::RenderForegroundOverlays(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CCamera& viewCamera)
|
||||
{
|
||||
PROFILE3_GPU("overlays (fg)");
|
||||
PROFILE3("overlays (fg)");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render foreground overlays");
|
||||
|
||||
const CVector3D right = -viewCamera.GetOrientation().GetLeft();
|
||||
|
|
@ -791,7 +791,7 @@ void OverlayRendererInternals::GenerateSphere()
|
|||
void OverlayRenderer::RenderSphereOverlays(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
PROFILE3_GPU("overlays (spheres)");
|
||||
PROFILE3("overlays (spheres)");
|
||||
|
||||
if (m->spheres.empty() || m->shaderOverlaySolid.technique)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -693,6 +693,7 @@ void CPostprocManager::ApplyPostproc(
|
|||
if (!hasEffects && !hasAA && !hasSharp)
|
||||
return;
|
||||
|
||||
PROFILE3_GPU(deviceCommandContext, "Render postproc");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render postproc");
|
||||
|
||||
if (hasEffects)
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger)
|
|||
{
|
||||
PROFILE3("render");
|
||||
|
||||
g_Profiler2.RecordGPUFrameStart();
|
||||
g_Profiler2.RecordGPUFrameStart(m->deviceCommandContext.get());
|
||||
|
||||
g_TexMan.UploadResourcesIfNeeded(m->deviceCommandContext.get());
|
||||
|
||||
|
|
@ -605,7 +605,7 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger)
|
|||
PROFILE2_ATTR("blend splats: %zu", stats.m_BlendSplats);
|
||||
PROFILE2_ATTR("particles: %zu", stats.m_Particles);
|
||||
|
||||
g_Profiler2.RecordGPUFrameEnd();
|
||||
g_Profiler2.RecordGPUFrameEnd(m->deviceCommandContext.get());
|
||||
}
|
||||
|
||||
void CRenderer::RenderFrame2D(const bool renderGUI, const bool renderLogger)
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ void CSceneRenderer::RenderShadowMap(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context)
|
||||
{
|
||||
PROFILE3_GPU("shadow map");
|
||||
PROFILE3_GPU(deviceCommandContext, "shadow map");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render shadow map");
|
||||
|
||||
CShaderDefines shadowsContext = context;
|
||||
|
|
@ -337,7 +337,7 @@ void CSceneRenderer::RenderPatches(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup)
|
||||
{
|
||||
PROFILE3_GPU("patches");
|
||||
PROFILE3("patches");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render patches");
|
||||
|
||||
// Switch on wireframe if we need it.
|
||||
|
|
@ -367,7 +367,7 @@ void CSceneRenderer::RenderModels(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup)
|
||||
{
|
||||
PROFILE3_GPU("models");
|
||||
PROFILE3("models");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render models");
|
||||
|
||||
int flags = 0;
|
||||
|
|
@ -390,7 +390,7 @@ void CSceneRenderer::RenderTransparentModels(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode)
|
||||
{
|
||||
PROFILE3_GPU("transparent models");
|
||||
PROFILE3("transparent models");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render transparent models");
|
||||
|
||||
int flags = 0;
|
||||
|
|
@ -545,7 +545,7 @@ void CSceneRenderer::RenderReflections(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, const CBoundingBoxAligned& scissor)
|
||||
{
|
||||
PROFILE3_GPU("water reflections");
|
||||
PROFILE3_GPU(deviceCommandContext, "water reflections");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render water reflections");
|
||||
|
||||
WaterManager& wm = m->waterManager;
|
||||
|
|
@ -622,7 +622,7 @@ void CSceneRenderer::RenderRefractions(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, const CBoundingBoxAligned &scissor)
|
||||
{
|
||||
PROFILE3_GPU("water refractions");
|
||||
PROFILE3_GPU(deviceCommandContext, "water refractions");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render water refractions");
|
||||
|
||||
WaterManager& wm = m->waterManager;
|
||||
|
|
@ -699,7 +699,7 @@ void CSceneRenderer::RenderSilhouettes(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context)
|
||||
{
|
||||
PROFILE3_GPU("silhouettes");
|
||||
PROFILE3("silhouettes");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render silhouettes");
|
||||
|
||||
CShaderDefines contextOccluder = context;
|
||||
|
|
@ -752,7 +752,7 @@ void CSceneRenderer::RenderParticles(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
int cullGroup)
|
||||
{
|
||||
PROFILE3_GPU("particles");
|
||||
PROFILE3("particles");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render particles");
|
||||
|
||||
m->particleRenderer.RenderParticles(
|
||||
|
|
@ -770,7 +770,7 @@ void CSceneRenderer::PrepareSubmissions(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CBoundingBoxAligned& waterScissor)
|
||||
{
|
||||
PROFILE3("prepare submissions");
|
||||
PROFILE3_GPU(deviceCommandContext, "prepare submissions");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Prepare submissions");
|
||||
|
||||
m->skyManager.LoadAndUploadSkyTexturesIfNeeded(deviceCommandContext);
|
||||
|
|
@ -824,7 +824,7 @@ void CSceneRenderer::PrepareSubmissions(
|
|||
{
|
||||
m->waterManager.UpdateQuality();
|
||||
|
||||
PROFILE3_GPU("water scissor");
|
||||
PROFILE3_GPU(deviceCommandContext, "water scissor");
|
||||
if (g_RenderingOptions.GetWaterReflection())
|
||||
RenderReflections(deviceCommandContext, context, waterScissor);
|
||||
|
||||
|
|
@ -936,7 +936,7 @@ void CSceneRenderer::DisplayFrustum()
|
|||
// Text overlay rendering
|
||||
void CSceneRenderer::RenderTextOverlays(CCanvas2D& canvas)
|
||||
{
|
||||
PROFILE3_GPU("text overlays");
|
||||
PROFILE3("text overlays");
|
||||
|
||||
if (m_DisplayTerrainPriorities)
|
||||
m->terrainRenderer.RenderPriorities(canvas, CULL_DEFAULT);
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ void ITerrainOverlay::RenderOverlaysBeforeWater(
|
|||
if (g_TerrainOverlayList.empty())
|
||||
return;
|
||||
|
||||
PROFILE3_GPU("terrain overlays (before)");
|
||||
PROFILE3("terrain overlays (before)");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain overlays before water");
|
||||
|
||||
for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i)
|
||||
|
|
@ -130,7 +130,7 @@ void ITerrainOverlay::RenderOverlaysAfterWater(
|
|||
if (g_TerrainOverlayList.empty())
|
||||
return;
|
||||
|
||||
PROFILE3_GPU("terrain overlays (after)");
|
||||
PROFILE3("terrain overlays (after)");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain overlays after water");
|
||||
|
||||
for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -443,7 +443,7 @@ bool TerrainRenderer::RenderFancyWater(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup, ShadowMap* shadow)
|
||||
{
|
||||
PROFILE3_GPU("fancy water");
|
||||
PROFILE3("fancy water");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render fancy water");
|
||||
|
||||
CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
|
||||
|
|
@ -660,7 +660,7 @@ void TerrainRenderer::RenderSimpleWater(
|
|||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
int cullGroup)
|
||||
{
|
||||
PROFILE3_GPU("simple water");
|
||||
PROFILE3("simple water");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render Simple Water");
|
||||
|
||||
const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager();
|
||||
|
|
|
|||
Loading…
Reference in a new issue