feat(app): performance overlay in window title

Updates the window title every ~0.5s with:
  FPS | frame time (ms) | visible/total landblocks | entity count | animated count

Example: "acdream | 60 fps | 16.7 ms | lb 12/25 visible | ent 847 | anim 19"

Zero rendering cost — uses Silk.NET's window title setter, no font
renderer or GPU overlay needed. The visible/total landblock ratio
makes Phase A.2 frustum culling's impact visible at a glance: turning
the camera should show the visible count drop as landblocks behind
the camera get culled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-12 09:02:00 +02:00
parent 3c9fc63af7
commit a33f3c4c7f

View file

@ -1331,6 +1331,11 @@ public sealed class GameWindow : IDisposable
_capturedMouse = isFlyMode ? mouse : null;
}
// Performance overlay state — updated every ~0.5s and written to the
// window title so there's zero rendering cost (no font/overlay needed).
private double _perfAccum;
private int _perfFrameCount;
private void OnRender(double deltaSeconds)
{
_gl!.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
@ -1340,12 +1345,40 @@ public sealed class GameWindow : IDisposable
if (_animatedEntities.Count > 0)
TickAnimations((float)deltaSeconds);
int visibleLandblocks = 0;
int totalLandblocks = 0;
if (_cameraController is not null)
{
var camera = _cameraController.Active;
var frustum = AcDream.App.Rendering.FrustumPlanes.FromViewProjection(camera.View * camera.Projection);
_terrain?.Draw(camera, frustum);
_staticMesh?.Draw(camera, _worldState.LandblockEntries, frustum);
// Count visible vs total for the perf overlay.
foreach (var entry in _worldState.LandblockEntries)
{
totalLandblocks++;
if (AcDream.App.Rendering.FrustumCuller.IsAabbVisible(frustum, entry.AabbMin, entry.AabbMax))
visibleLandblocks++;
}
}
// Update the window title with performance stats every ~0.5s.
_perfAccum += deltaSeconds;
_perfFrameCount++;
if (_perfAccum >= 0.5)
{
double avgFrameTime = _perfAccum / _perfFrameCount * 1000.0;
double fps = _perfFrameCount / _perfAccum;
int entityCount = _worldState.Entities.Count;
int animatedCount = _animatedEntities.Count;
_window!.Title = $"acdream | {fps:F0} fps | {avgFrameTime:F1} ms | " +
$"lb {visibleLandblocks}/{totalLandblocks} visible | " +
$"ent {entityCount} | anim {animatedCount}";
_perfAccum = 0;
_perfFrameCount = 0;
}
}