Add excluding GPU swapchain present time from CPU draw time in profiling tool

This commit is contained in:
Wojtek Figat
2023-10-16 10:58:07 +02:00
parent db6b98ecd1
commit d25954725f
4 changed files with 38 additions and 23 deletions

View File

@@ -503,6 +503,9 @@ void GPUDevice::DrawEnd()
// Call present on all used tasks // Call present on all used tasks
int32 presentCount = 0; int32 presentCount = 0;
bool anyVSync = false; bool anyVSync = false;
#if COMPILE_WITH_PROFILER
const double presentStart = Platform::GetTimeSeconds();
#endif
for (int32 i = 0; i < RenderTask::Tasks.Count(); i++) for (int32 i = 0; i < RenderTask::Tasks.Count(); i++)
{ {
const auto task = RenderTask::Tasks[i]; const auto task = RenderTask::Tasks[i];
@@ -537,6 +540,10 @@ void GPUDevice::DrawEnd()
#endif #endif
GetMainContext()->Flush(); GetMainContext()->Flush();
} }
#if COMPILE_WITH_PROFILER
const double presentEnd = Platform::GetTimeSeconds();
ProfilerGPU::OnPresentTime((float)((presentEnd - presentStart) * 1000.0));
#endif
_wasVSyncUsed = anyVSync; _wasVSyncUsed = anyVSync;
_isRendering = false; _isRendering = false;

View File

@@ -74,6 +74,7 @@ void ProfilerGPU::EventBuffer::Clear()
_data.Clear(); _data.Clear();
_isResolved = false; _isResolved = false;
FrameIndex = 0; FrameIndex = 0;
PresentTime = 0.0f;
} }
GPUTimerQuery* ProfilerGPU::GetTimerQuery() GPUTimerQuery* ProfilerGPU::GetTimerQuery()
@@ -133,7 +134,9 @@ void ProfilerGPU::BeginFrame()
// Clear stats // Clear stats
RenderStatsData::Counter = RenderStatsData(); RenderStatsData::Counter = RenderStatsData();
_depth = 0; _depth = 0;
Buffers[CurrentBuffer].FrameIndex = Engine::FrameCount; auto& buffer = Buffers[CurrentBuffer];
buffer.FrameIndex = Engine::FrameCount;
buffer.PresentTime = 0.0f;
// Try to resolve previous frames // Try to resolve previous frames
for (int32 i = 0; i < PROFILER_GPU_EVENTS_FRAMES; i++) for (int32 i = 0; i < PROFILER_GPU_EVENTS_FRAMES; i++)
@@ -149,6 +152,12 @@ void ProfilerGPU::OnPresent()
buffer.EndAll(); buffer.EndAll();
} }
void ProfilerGPU::OnPresentTime(float time)
{
auto& buffer = Buffers[CurrentBuffer];
buffer.PresentTime += time;
}
void ProfilerGPU::EndFrame() void ProfilerGPU::EndFrame()
{ {
if (_depth) if (_depth)
@@ -164,7 +173,7 @@ void ProfilerGPU::EndFrame()
buffer.Clear(); buffer.Clear();
} }
bool ProfilerGPU::GetLastFrameData(float& drawTimeMs, RenderStatsData& statsData) bool ProfilerGPU::GetLastFrameData(float& drawTimeMs, float& presentTimeMs, RenderStatsData& statsData)
{ {
uint64 maxFrame = 0; uint64 maxFrame = 0;
int32 maxFrameIndex = -1; int32 maxFrameIndex = -1;
@@ -177,17 +186,19 @@ bool ProfilerGPU::GetLastFrameData(float& drawTimeMs, RenderStatsData& statsData
maxFrameIndex = i; maxFrameIndex = i;
} }
} }
if (maxFrameIndex != -1) if (maxFrameIndex != -1)
{ {
auto& frame = frames[maxFrameIndex]; auto& frame = frames[maxFrameIndex];
const auto root = frame.Get(0); const auto root = frame.Get(0);
drawTimeMs = root->Time; drawTimeMs = root->Time;
presentTimeMs = frame.PresentTime;
statsData = root->Stats; statsData = root->Stats;
return true; return true;
} }
// No data
drawTimeMs = 0.0f; drawTimeMs = 0.0f;
presentTimeMs = 0.0f;
Platform::MemoryClear(&statsData, sizeof(statsData)); Platform::MemoryClear(&statsData, sizeof(statsData));
return false; return false;
} }

View File

@@ -20,6 +20,8 @@ class GPUTimerQuery;
API_CLASS(Static) class FLAXENGINE_API ProfilerGPU API_CLASS(Static) class FLAXENGINE_API ProfilerGPU
{ {
DECLARE_SCRIPTING_TYPE_NO_SPAWN(ProfilerGPU); DECLARE_SCRIPTING_TYPE_NO_SPAWN(ProfilerGPU);
friend class Engine;
friend class GPUDevice;
public: public:
/// <summary> /// <summary>
/// Represents single CPU profiling event data. /// Represents single CPU profiling event data.
@@ -69,6 +71,11 @@ public:
/// </summary> /// </summary>
uint64 FrameIndex; uint64 FrameIndex;
/// <summary>
/// Sum of all present events duration on CPU during this frame (in milliseconds).
/// </summary>
float PresentTime;
/// <summary> /// <summary>
/// Determines whether this buffer has ready data (resolved and not empty). /// Determines whether this buffer has ready data (resolved and not empty).
/// </summary> /// </summary>
@@ -151,32 +158,20 @@ public:
/// <param name="index">The event token index returned by the BeginEvent method.</param> /// <param name="index">The event token index returned by the BeginEvent method.</param>
static void EndEvent(int32 index); static void EndEvent(int32 index);
/// <summary>
/// Begins the new frame rendering. Called by the engine to sync profiling data.
/// </summary>
static void BeginFrame();
/// <summary>
/// Called when just before flushing current frame GPU commands (via Present or Flush). Call active timer queries should be ended now.
/// </summary>
static void OnPresent();
/// <summary>
/// Ends the frame rendering. Called by the engine to sync profiling data.
/// </summary>
static void EndFrame();
/// <summary> /// <summary>
/// Tries to get the rendering stats from the last frame drawing (that has been resolved and has valid data). /// Tries to get the rendering stats from the last frame drawing (that has been resolved and has valid data).
/// </summary> /// </summary>
/// <param name="drawTimeMs">The draw execution time on a GPU (in milliseconds).</param> /// <param name="drawTimeMs">The draw execution time on a GPU (in milliseconds).</param>
/// <param name="presentTimeMs">The final frame present time on a CPU (in milliseconds). Time game waited for vsync or GPU to finish previous frame rendering.</param>
/// <param name="statsData">The rendering stats data.</param> /// <param name="statsData">The rendering stats data.</param>
/// <returns>True if got the data, otherwise false.</returns> /// <returns>True if got the data, otherwise false.</returns>
static bool GetLastFrameData(float& drawTimeMs, RenderStatsData& statsData); API_FUNCTION() static bool GetLastFrameData(float& drawTimeMs, float& presentTimeMs, RenderStatsData& statsData);
/// <summary> private:
/// Releases resources. Calls to the profiling API after Dispose are not valid static void BeginFrame();
/// </summary> static void OnPresent();
static void OnPresentTime(float time);
static void EndFrame();
static void Dispose(); static void Dispose();
}; };

View File

@@ -48,7 +48,9 @@ void ProfilingToolsService::Update()
stats.PhysicsTimeMs = static_cast<float>(Time::Physics.LastLength * 1000.0); stats.PhysicsTimeMs = static_cast<float>(Time::Physics.LastLength * 1000.0);
stats.DrawCPUTimeMs = static_cast<float>(Time::Draw.LastLength * 1000.0); stats.DrawCPUTimeMs = static_cast<float>(Time::Draw.LastLength * 1000.0);
ProfilerGPU::GetLastFrameData(stats.DrawGPUTimeMs, stats.DrawStats); float presentTime;
ProfilerGPU::GetLastFrameData(stats.DrawGPUTimeMs, presentTime, stats.DrawStats);
stats.DrawCPUTimeMs = Math::Max(stats.DrawCPUTimeMs - presentTime, 0.0f); // Remove swapchain present wait time to exclude from drawing on CPU
} }
// Extract CPU profiler events // Extract CPU profiler events