chore(diag): dense-town FPS profiling apparatus (ACDREAM_FPS_PROF) [throwaway]
FrameProfiler (frame/update/render/present/gpu split + per-renderer glFinish
attribution) + OnRender/OnUpdate hooks + terrain & EnvCell glFinish timers +
the degrade-coverage probe test. Used to root-cause the dense-town FPS; STRIP
when the fix lands (mirrors 92e95be).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fd9354f69e
commit
e27923b4b5
4 changed files with 482 additions and 0 deletions
|
|
@ -62,6 +62,14 @@ public sealed class GameWindow : IDisposable
|
|||
private double _lastFps = 60.0;
|
||||
private double _lastFrameMs = 16.7;
|
||||
|
||||
// THROWAWAY FPS-investigation apparatus (2026-06-23, ACDREAM_FPS_PROF=1):
|
||||
// frame-level CPU/GPU/wall profiler to find the dense-town bottleneck. See
|
||||
// FrameProfiler. Lazy-constructed on first OnRender once _gl is live.
|
||||
private readonly bool _fpsProf =
|
||||
string.Equals(Environment.GetEnvironmentVariable("ACDREAM_FPS_PROF"), "1", StringComparison.Ordinal);
|
||||
private FrameProfiler? _frameProfiler;
|
||||
private int _msaaSamples;
|
||||
|
||||
// Phase I.2: per-frame counters surfaced through the ImGui DebugPanel
|
||||
// VM closures. Computed once per render pass alongside the frustum
|
||||
// walk + nearest-object scan; the VM closures just read the cached
|
||||
|
|
@ -976,6 +984,7 @@ public sealed class GameWindow : IDisposable
|
|||
var startupDisplay = startupStore.LoadDisplay();
|
||||
var startupBase = AcDream.UI.Abstractions.Settings.QualitySettings.From(startupDisplay.Quality);
|
||||
var startupQuality = AcDream.UI.Abstractions.Settings.QualitySettings.WithEnvOverrides(startupBase);
|
||||
_msaaSamples = startupQuality.MsaaSamples; // ACDREAM_FPS_PROF apparatus
|
||||
|
||||
var options = WindowOptions.Default with
|
||||
{
|
||||
|
|
@ -7613,6 +7622,11 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
private void OnUpdate(double dt)
|
||||
{
|
||||
// THROWAWAY FPS apparatus (ACDREAM_FPS_PROF=1): stamp the start of the
|
||||
// update phase so the profiler can split frame time into update vs render
|
||||
// vs present. Robust to early-returns below (no matching EndUpdate needed).
|
||||
if (_fpsProf) _frameProfiler?.MarkUpdateStart();
|
||||
|
||||
// [FRAME-DIAG]: applies run later this frame inside _streamingController.Tick;
|
||||
// flush the PREVIOUS OnUpdate's accumulated apply cost here (a clean per-frame
|
||||
// boundary, independent of where in OnUpdate the applies landed) and reset.
|
||||
|
|
@ -8347,6 +8361,14 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
private void OnRender(double deltaSeconds)
|
||||
{
|
||||
// THROWAWAY FPS apparatus (ACDREAM_FPS_PROF=1): bracket the whole frame's
|
||||
// CPU (this method) + GPU (TimeElapsed query) work. Begin before any GL.
|
||||
if (_fpsProf && _gl is not null)
|
||||
{
|
||||
_frameProfiler ??= new FrameProfiler(_gl);
|
||||
_frameProfiler.BeginFrame();
|
||||
}
|
||||
|
||||
// Phase G.1: set the clear color from the current sky's fog
|
||||
// tint so the horizon band continues naturally past the
|
||||
// rendered geometry. Fog blends to this color at max distance
|
||||
|
|
@ -9399,6 +9421,11 @@ public sealed class GameWindow : IDisposable
|
|||
_imguiBootstrap.Render();
|
||||
}
|
||||
|
||||
// THROWAWAY FPS apparatus (ACDREAM_FPS_PROF=1): close the frame's CPU+GPU
|
||||
// brackets after ALL GL work (incl. ImGui). wall = the real frame period.
|
||||
if (_fpsProf && _frameProfiler is not null)
|
||||
_frameProfiler.EndFrame(deltaSeconds * 1000.0, _window!.VSync, _msaaSamples, deltaSeconds);
|
||||
|
||||
// Update the window title with performance stats every ~0.5s.
|
||||
_perfAccum += deltaSeconds;
|
||||
_perfFrameCount++;
|
||||
|
|
@ -10765,9 +10792,15 @@ public sealed class GameWindow : IDisposable
|
|||
AcDream.Core.Vfx.ParticleRenderPass.SkyPreScene);
|
||||
|
||||
EnableClipDistances();
|
||||
// THROWAWAY FPS apparatus: glFinish-bracket the PER-SLICE terrain draw so
|
||||
// [PASS-GPU] reports terrain ms/frame + calls/frame (= slice count). This
|
||||
// is the suspected multiplier: terrain is redrawn fully once per slice.
|
||||
System.Diagnostics.Stopwatch? _terrGpuSw = null;
|
||||
if (FrameProfiler.PassGpuEnabled) { _gl!.Finish(); _terrGpuSw = System.Diagnostics.Stopwatch.StartNew(); }
|
||||
_terrainCpuStopwatch.Restart();
|
||||
_terrain?.Draw(camera, frustum, neverCullLandblockId: playerLb);
|
||||
_terrainCpuStopwatch.Stop();
|
||||
if (_terrGpuSw is not null) { _gl!.Finish(); FrameProfiler.AddRendererGpu("terrain", _terrGpuSw.Elapsed.TotalMilliseconds); }
|
||||
_terrainCpuSamples[_terrainCpuSampleCursor] =
|
||||
(long)(_terrainCpuStopwatch.Elapsed.TotalMicroseconds * 100.0);
|
||||
_terrainCpuSampleCursor = (_terrainCpuSampleCursor + 1) % _terrainCpuSamples.Length;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue