feat: Add comprehensive profiling system with F3 overlay
Add real-time performance profiling infrastructure to monitor frame times, render performance, and identify bottlenecks. Features: - Profiler.h: ScopedTimer RAII helper for automatic timing measurements - ProfilerOverlay: F3-togglable overlay displaying real-time metrics - Detailed timing breakdowns: grid rendering, entity rendering, FOV, Python callbacks, and animation updates - Per-frame counters: cells rendered, entities rendered, draw calls - Performance color coding: green (<16ms), yellow (<33ms), red (>33ms) - Benchmark suite: static grid and moving entities performance tests Integration: - GameEngine: Integrated profiler overlay with F3 toggle - UIGrid: Added timing instrumentation for grid and entity rendering - Metrics tracked in ProfilingMetrics struct with 60-frame averaging Usage: - Press F3 in-game to toggle profiler overlay - Run benchmarks with tests/benchmark_*.py scripts - ScopedTimer automatically measures code block execution time This addresses issue #104 (Basic profiling/metrics). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8153fd2503
commit
e9e9cd2f81
8 changed files with 715 additions and 29 deletions
|
|
@ -9,11 +9,16 @@
|
|||
#include "McRogueFaceConfig.h"
|
||||
#include "HeadlessRenderer.h"
|
||||
#include "SceneTransition.h"
|
||||
#include "Profiler.h"
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
class GameEngine
|
||||
{
|
||||
public:
|
||||
// Forward declare nested class so private section can use it
|
||||
class ProfilerOverlay;
|
||||
|
||||
// Viewport modes (moved here so private section can use it)
|
||||
enum class ViewportMode {
|
||||
Center, // 1:1 pixels, viewport centered in window
|
||||
|
|
@ -51,7 +56,12 @@ private:
|
|||
sf::Vector2u gameResolution{1024, 768}; // Fixed game resolution
|
||||
sf::View gameView; // View for the game content
|
||||
ViewportMode viewportMode = ViewportMode::Fit;
|
||||
|
||||
|
||||
// Profiling overlay
|
||||
bool showProfilerOverlay = false; // F3 key toggles this
|
||||
int overlayUpdateCounter = 0; // Only update overlay every N frames
|
||||
ProfilerOverlay* profilerOverlay = nullptr; // The actual overlay renderer
|
||||
|
||||
void updateViewport();
|
||||
|
||||
void testTimers();
|
||||
|
|
@ -69,17 +79,29 @@ public:
|
|||
int drawCalls = 0; // Draw calls per frame
|
||||
int uiElements = 0; // Number of UI elements rendered
|
||||
int visibleElements = 0; // Number of visible elements
|
||||
|
||||
|
||||
// Detailed timing breakdowns (added for profiling system)
|
||||
float gridRenderTime = 0.0f; // Time spent rendering grids (ms)
|
||||
float entityRenderTime = 0.0f; // Time spent rendering entities (ms)
|
||||
float fovOverlayTime = 0.0f; // Time spent rendering FOV overlays (ms)
|
||||
float pythonScriptTime = 0.0f; // Time spent in Python callbacks (ms)
|
||||
float animationTime = 0.0f; // Time spent updating animations (ms)
|
||||
|
||||
// Grid-specific metrics
|
||||
int gridCellsRendered = 0; // Number of grid cells drawn this frame
|
||||
int entitiesRendered = 0; // Number of entities drawn this frame
|
||||
int totalEntities = 0; // Total entities in scene
|
||||
|
||||
// Frame time history for averaging
|
||||
static constexpr int HISTORY_SIZE = 60;
|
||||
float frameTimeHistory[HISTORY_SIZE] = {0};
|
||||
int historyIndex = 0;
|
||||
|
||||
|
||||
void updateFrameTime(float deltaMs) {
|
||||
frameTime = deltaMs;
|
||||
frameTimeHistory[historyIndex] = deltaMs;
|
||||
historyIndex = (historyIndex + 1) % HISTORY_SIZE;
|
||||
|
||||
|
||||
// Calculate average
|
||||
float sum = 0.0f;
|
||||
for (int i = 0; i < HISTORY_SIZE; ++i) {
|
||||
|
|
@ -88,13 +110,26 @@ public:
|
|||
avgFrameTime = sum / HISTORY_SIZE;
|
||||
fps = avgFrameTime > 0 ? static_cast<int>(1000.0f / avgFrameTime) : 0;
|
||||
}
|
||||
|
||||
|
||||
void resetPerFrame() {
|
||||
drawCalls = 0;
|
||||
uiElements = 0;
|
||||
visibleElements = 0;
|
||||
|
||||
// Reset per-frame timing metrics
|
||||
gridRenderTime = 0.0f;
|
||||
entityRenderTime = 0.0f;
|
||||
fovOverlayTime = 0.0f;
|
||||
pythonScriptTime = 0.0f;
|
||||
animationTime = 0.0f;
|
||||
|
||||
// Reset per-frame counters
|
||||
gridCellsRendered = 0;
|
||||
entitiesRendered = 0;
|
||||
totalEntities = 0;
|
||||
}
|
||||
} metrics;
|
||||
|
||||
GameEngine();
|
||||
GameEngine(const McRogueFaceConfig& cfg);
|
||||
~GameEngine();
|
||||
|
|
@ -144,5 +179,30 @@ public:
|
|||
sf::Music music;
|
||||
sf::Sound sfx;
|
||||
std::shared_ptr<std::vector<std::shared_ptr<UIDrawable>>> scene_ui(std::string scene);
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Visual overlay that displays real-time profiling metrics
|
||||
*/
|
||||
class GameEngine::ProfilerOverlay {
|
||||
private:
|
||||
sf::Font& font;
|
||||
sf::Text text;
|
||||
sf::RectangleShape background;
|
||||
bool visible;
|
||||
int updateInterval;
|
||||
int frameCounter;
|
||||
|
||||
sf::Color getPerformanceColor(float frameTimeMs);
|
||||
std::string formatFloat(float value, int precision = 1);
|
||||
std::string formatPercentage(float part, float total);
|
||||
|
||||
public:
|
||||
ProfilerOverlay(sf::Font& fontRef);
|
||||
void toggle();
|
||||
void setVisible(bool vis);
|
||||
bool isVisible() const;
|
||||
void update(const ProfilingMetrics& metrics);
|
||||
void render(sf::RenderTarget& target);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue