Tesseract-Engine/src/Windows/PerformanceWindow.cpp

304 lines
9.9 KiB
C++
Raw Normal View History

#include "PerformanceWindow.h"
#include "imgui.h"
#include <algorithm> // for std::max
#include <float.h> // for FLT_MAX
2024-12-26 04:00:13 +00:00
#include "Engine/ThemeManager.h"
2025-01-01 07:36:53 +00:00
#include "Engine/ScopedTimer.h"
extern int LoadedAssets;
extern int g_GPU_Triangles_drawn_to_screen;
2025-01-03 23:14:25 +00:00
extern int g_GPU_Draw_Calls;
2025-01-01 07:36:53 +00:00
const char *polygonModeOptions[] = {"Fill", "Wireframe", "Points"};
static int polygonMode = 0;
2024-12-27 06:09:43 +00:00
// Initialize static members
int PerformanceWindow::m_OpenGLCallCount = 0;
2024-12-26 04:00:13 +00:00
int PerformanceWindow::m_TriangleCount = 0;
// We'll store up to 60 data points for each stat.
static float s_FpsHistory[60] = {0.0f};
static float s_MsHistory[60] = {0.0f};
static float s_CallsHistory[60] = {0.0f};
static float s_TriangleHistory[60] = {0.0f};
// Current dynamic max scale for FPS and ms
static float s_FpsScale = 120.0f; // default starting scale for FPS
static float s_MsScale = 25.0f; // default starting scale for ms
// Push new value into history, shifting old values left
static void PushValueToHistory(float* historyArray, int historySize, float newValue)
{
for (int i = 0; i < historySize - 1; i++)
{
historyArray[i] = historyArray[i + 1];
}
historyArray[historySize - 1] = newValue;
}
// We'll track when we last pushed data to our history.
static double s_LastPushTime = 0.0;
// We'll also track when we last updated the scale
static double s_LastScaleUpdate = 0.0;
void PerformanceWindow::UpdatePerformanceStats(int newCallCount, int newTriangleCount)
{
m_OpenGLCallCount = newCallCount;
m_TriangleCount = newTriangleCount;
// Reset GPU counters each frame, or each time you show
g_GPU_Triangles_drawn_to_screen = 0;
2025-01-03 23:14:25 +00:00
g_GPU_Draw_Calls = 0;
}
void PerformanceWindow::Show(float fps, float ms)
{
2025-01-01 07:36:53 +00:00
SCOPE_TIMER("PerformanceWindow::Show");
// 1) Get current time from ImGui's internal clock
2024-12-26 04:00:13 +00:00
double currentTime = ImGui::GetTime();
// 2) If at least 0.05s has passed, push new data (~20 times a second)
if ((currentTime - s_LastPushTime) >= 0.05)
{
s_LastPushTime = currentTime;
// Push new values into our history arrays
2024-12-26 04:00:13 +00:00
PushValueToHistory(s_FpsHistory, 60, fps);
PushValueToHistory(s_MsHistory, 60, ms);
PushValueToHistory(s_CallsHistory, 60, (float)m_OpenGLCallCount);
PushValueToHistory(s_TriangleHistory, 60, (float)m_TriangleCount);
}
// We'll calculate a fallback max for calls
static float callsMax = 300.0f;
// 3) Every 1 second, recalculate the max scale for FPS, ms, and calls
if ((currentTime - s_LastScaleUpdate) >= 1.0)
{
s_LastScaleUpdate = currentTime;
// Recompute s_FpsScale
float maxFps = 0.0f;
for (int i = 0; i < 60; i++)
maxFps = std::max(maxFps, s_FpsHistory[i]);
maxFps = std::max(1.0f, maxFps * 1.15f); // add ~15% headroom
s_FpsScale = maxFps;
// Recompute s_MsScale
float maxMs = 0.0f;
for (int i = 0; i < 60; i++)
maxMs = std::max(maxMs, s_MsHistory[i]);
maxMs = std::max(1.0f, maxMs * 1.15f);
s_MsScale = maxMs;
// Recompute callsMax
float localMax = 0.0f;
for (int i = 0; i < 60; i++)
localMax = std::max(localMax, s_CallsHistory[i]);
if (localMax > 0.0f)
callsMax = localMax * 1.2f; // 20% headroom
else
callsMax = 300.0f; // default
}
// Optional style adjustments
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
// Optionally make the window auto-resize or set constraints:
// ImGui::SetNextWindowSizeConstraints(ImVec2(350, 300), ImVec2(FLT_MAX, FLT_MAX));
// ImGui::Begin("Performance##performance", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::Begin("Performance##performance");
// A color-coded main header
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Performance Stats");
ImGui::Separator();
ImGui::Spacing();
// Show current FPS / ms in color
{
// Line 1: FPS (green) + MS (teal)
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "FPS: %.1f", fps);
ImGui::SameLine();
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.8f, 1.0f), "| ms: %.3f", ms);
}
// Collapsible header for the performance graphs
if (ImGui::CollapsingHeader("Performance Graphs", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Spacing();
// --------- FPS & MS side by side ----------
ImGui::BeginGroup(); // left group
{
ImGui::Text("FPS");
ImGui::PushStyleColor(ImGuiCol_PlotLines, IM_COL32(0, 255, 0, 255)); // green
ImGui::PushStyleColor(ImGuiCol_PlotLinesHovered, IM_COL32(255, 0, 0, 255)); // red on hover
ImGui::PlotLines("##FPS", // hidden label
s_FpsHistory, IM_ARRAYSIZE(s_FpsHistory),
0, // offset
nullptr, // overlay
0.0f,
s_FpsScale,
ImVec2(150, 60));
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Frames per second over time");
ImGui::EndTooltip();
}
ImGui::PopStyleColor(2);
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup(); // right group
{
ImGui::Text("ms/frame");
ImGui::PlotHistogram("##ms/frame",
s_MsHistory,
IM_ARRAYSIZE(s_MsHistory),
0,
nullptr,
0.0f,
s_MsScale,
ImVec2(150, 60));
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Frame time in milliseconds");
ImGui::EndTooltip();
}
}
ImGui::EndGroup();
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// --------- OpenGL Calls & Indices -----------
// 1) GL Calls
ImGui::Text("OpenGL Calls: %d", m_OpenGLCallCount);
ImGui::PlotLines("##GL Calls",
s_CallsHistory,
IM_ARRAYSIZE(s_CallsHistory),
0, // offset
nullptr, // overlay text
2024-12-26 04:00:13 +00:00
0.0f,
callsMax,
ImVec2(-1, 50)); // auto-fill width, fixed height=50
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Number of GL draw calls per frame");
ImGui::EndTooltip();
}
ImGui::Spacing();
// 2) Indices
ImGui::Text("Indices: %d", m_TriangleCount);
// For Indices, we use a histogram. We could also do dynamic range like callsMax.
float indexHistMax = std::max(1.0f, (float)m_TriangleCount * 2.5f);
ImGui::PlotHistogram("##Indices",
s_TriangleHistory,
IM_ARRAYSIZE(s_TriangleHistory),
0,
nullptr,
0.0f,
indexHistMax,
ImVec2(-1, 50)); // auto-size width, height=50
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Number of indices being rendered per frame");
ImGui::EndTooltip();
}
}
ImGui::Spacing();
2024-12-26 04:00:13 +00:00
ImGui::Separator();
ImGui::Spacing();
// -------------- Asset Count --------------
{
ImGui::Text("Loaded Assets: ");
ImGui::SameLine();
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%d", LoadedAssets);
}
2024-12-26 04:00:13 +00:00
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
2024-12-26 04:00:13 +00:00
// -------------- Theme Combo Box --------------
2024-12-26 04:00:13 +00:00
{
const char* options[] = {"Bootstrap", "Duck Red", "Windark", "Deep Dark", "Tesseract Black"};
static int current_option = -1;
const char* preview_value = (current_option >= 0 && current_option < IM_ARRAYSIZE(options))
? options[current_option]
: "Select an option";
ImGui::Text("Theme: ");
ImGui::SameLine();
if (ImGui::BeginCombo("##ThemeCombo", preview_value))
2024-12-26 04:00:13 +00:00
{
for (int n = 0; n < IM_ARRAYSIZE(options); n++)
2024-12-26 04:00:13 +00:00
{
bool is_selected = (current_option == n);
if (ImGui::Selectable(options[n], is_selected))
{
current_option = n;
// Switch theme
ThemeManager_ChangeTheme(n);
}
if (is_selected)
ImGui::SetItemDefaultFocus();
2024-12-26 04:00:13 +00:00
}
ImGui::EndCombo();
2024-12-26 04:00:13 +00:00
}
}
ImGui::Spacing();
// -------------- Polygon Mode Combo Box --------------
2024-12-27 06:09:43 +00:00
{
ImGui::Text("Polygon Mode: ");
ImGui::SameLine();
if (ImGui::Combo("##PolygonMode", &polygonMode, polygonModeOptions, IM_ARRAYSIZE(polygonModeOptions)))
2024-12-27 06:09:43 +00:00
{
switch (polygonMode)
{
case 0: // Fill
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
case 1: // Wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
case 2: // Points
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
break;
default:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
}
2024-12-27 06:09:43 +00:00
}
}
2024-12-26 04:00:13 +00:00
ImGui::End(); // End of "Performance##performance"
2024-12-26 04:00:13 +00:00
// Pop the style var
ImGui::PopStyleVar();
}