feat(pipeline): MP0 - wire FrameProfiler into GameWindow + DebugPanel toggle
GameWindow gets one field (_frameProfiler), one FrameBoundary() call at
the top of OnRender, three stage scopes (Update in OnUpdate, Upload
around _wbMeshAdapter?.Tick(), ImGui around _imguiBootstrap.Render()),
and one Dispose() call in teardown before _dats?.Dispose() releases the
GpuFrameTimer query ring. No new feature bodies land in GameWindow.cs —
all profiler logic lives in AcDream.App.Diagnostics.
DebugVM.FrameProf mirrors RenderingDiagnostics.FrameProfEnabled so the
DebugPanel checkbox ("Frame profiler ([frame-prof])") toggles the 5s
report live. Note: the checkbox lives in
AcDream.UI.Abstractions/Panels/Debug/DebugPanel.cs (IPanelRenderer,
backend-agnostic) alongside the other Diagnostics-section checkboxes —
not in AcDream.UI.ImGui, which holds no panel-drawing code per Code
Structure Rule 3.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
73bb8777a9
commit
edbb1ffebd
3 changed files with 35 additions and 2 deletions
|
|
@ -122,6 +122,11 @@ public sealed class GameWindow : IDisposable
|
||||||
private readonly long[] _applyLockWaitSamples = new long[256];
|
private readonly long[] _applyLockWaitSamples = new long[256];
|
||||||
private int _applyLockWaitSampleCursor;
|
private int _applyLockWaitSampleCursor;
|
||||||
|
|
||||||
|
// MP0 (2026-07-05): permanent frame profiler — one FrameBoundary call
|
||||||
|
// per OnRender + three stage scopes. All logic lives in
|
||||||
|
// AcDream.App.Diagnostics.FrameProfiler (structure rule 1).
|
||||||
|
private readonly AcDream.App.Diagnostics.FrameProfiler _frameProfiler = new();
|
||||||
|
|
||||||
// Phase A.1: streaming fields replacing the one-shot _entities list.
|
// Phase A.1: streaming fields replacing the one-shot _entities list.
|
||||||
private AcDream.App.Streaming.LandblockStreamer? _streamer;
|
private AcDream.App.Streaming.LandblockStreamer? _streamer;
|
||||||
private AcDream.App.Streaming.GpuWorldState _worldState = new();
|
private AcDream.App.Streaming.GpuWorldState _worldState = new();
|
||||||
|
|
@ -7951,6 +7956,8 @@ public sealed class GameWindow : IDisposable
|
||||||
|
|
||||||
private void OnUpdate(double dt)
|
private void OnUpdate(double dt)
|
||||||
{
|
{
|
||||||
|
using var _updStage = _frameProfiler.BeginStage(AcDream.App.Diagnostics.FrameStage.Update);
|
||||||
|
|
||||||
// [FRAME-DIAG]: applies run later this frame inside _streamingController.Tick;
|
// [FRAME-DIAG]: applies run later this frame inside _streamingController.Tick;
|
||||||
// flush the PREVIOUS OnUpdate's accumulated apply cost here (a clean per-frame
|
// flush the PREVIOUS OnUpdate's accumulated apply cost here (a clean per-frame
|
||||||
// boundary, independent of where in OnUpdate the applies landed) and reset.
|
// boundary, independent of where in OnUpdate the applies landed) and reset.
|
||||||
|
|
@ -8755,6 +8762,8 @@ public sealed class GameWindow : IDisposable
|
||||||
|
|
||||||
private void OnRender(double deltaSeconds)
|
private void OnRender(double deltaSeconds)
|
||||||
{
|
{
|
||||||
|
_frameProfiler.FrameBoundary(_gl!);
|
||||||
|
|
||||||
// Phase G.1: set the clear color from the current sky's fog
|
// Phase G.1: set the clear color from the current sky's fog
|
||||||
// tint so the horizon band continues naturally past the
|
// tint so the horizon band continues naturally past the
|
||||||
// rendered geometry. Fog blends to this color at max distance
|
// rendered geometry. Fog blends to this color at max distance
|
||||||
|
|
@ -8810,7 +8819,10 @@ public sealed class GameWindow : IDisposable
|
||||||
// [FRAME-DIAG]: this OnRender drain is where staged GfxObj/entity meshes hit
|
// [FRAME-DIAG]: this OnRender drain is where staged GfxObj/entity meshes hit
|
||||||
// the GPU (uncapped) — the H2 entity-upload suspect, separate from the apply.
|
// the GPU (uncapped) — the H2 entity-upload suspect, separate from the apply.
|
||||||
long fdE0 = _frameDiag ? System.Diagnostics.Stopwatch.GetTimestamp() : 0L;
|
long fdE0 = _frameDiag ? System.Diagnostics.Stopwatch.GetTimestamp() : 0L;
|
||||||
|
using (var _uplStage = _frameProfiler.BeginStage(AcDream.App.Diagnostics.FrameStage.Upload))
|
||||||
|
{
|
||||||
_wbMeshAdapter?.Tick();
|
_wbMeshAdapter?.Tick();
|
||||||
|
}
|
||||||
if (_frameDiag)
|
if (_frameDiag)
|
||||||
FrameDiagPush(_entityUploadSamples, ref _entityUploadSampleCursor,
|
FrameDiagPush(_entityUploadSamples, ref _entityUploadSampleCursor,
|
||||||
System.Diagnostics.Stopwatch.GetTimestamp() - fdE0);
|
System.Diagnostics.Stopwatch.GetTimestamp() - fdE0);
|
||||||
|
|
@ -9818,8 +9830,11 @@ public sealed class GameWindow : IDisposable
|
||||||
// panels but still over the 3D scene. Cheap when no
|
// panels but still over the 3D scene. Cheap when no
|
||||||
// selection — internal early-return on null guid.
|
// selection — internal early-return on null guid.
|
||||||
_targetIndicator?.Render();
|
_targetIndicator?.Render();
|
||||||
|
using (var _imguiStage = _frameProfiler.BeginStage(AcDream.App.Diagnostics.FrameStage.ImGui))
|
||||||
|
{
|
||||||
_imguiBootstrap.Render();
|
_imguiBootstrap.Render();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update the window title with performance stats every ~0.5s.
|
// Update the window title with performance stats every ~0.5s.
|
||||||
_perfAccum += deltaSeconds;
|
_perfAccum += deltaSeconds;
|
||||||
|
|
@ -14005,6 +14020,7 @@ public sealed class GameWindow : IDisposable
|
||||||
_uiHost?.Dispose();
|
_uiHost?.Dispose();
|
||||||
_textRenderer?.Dispose();
|
_textRenderer?.Dispose();
|
||||||
_debugFont?.Dispose();
|
_debugFont?.Dispose();
|
||||||
|
_frameProfiler.Dispose(); // MP0: releases the GpuFrameTimer query ring
|
||||||
_dats?.Dispose();
|
_dats?.Dispose();
|
||||||
_input?.Dispose();
|
_input?.Dispose();
|
||||||
_gl?.Dispose();
|
_gl?.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,12 @@ public sealed class DebugPanel : IPanel
|
||||||
if (r.Checkbox("Probe auto-walk (ACDREAM_PROBE_AUTOWALK)",
|
if (r.Checkbox("Probe auto-walk (ACDREAM_PROBE_AUTOWALK)",
|
||||||
ref probeAutoWalk)) _vm.ProbeAutoWalk = probeAutoWalk;
|
ref probeAutoWalk)) _vm.ProbeAutoWalk = probeAutoWalk;
|
||||||
|
|
||||||
|
// MP0 (2026-07-05): permanent frame profiler toggle — not a
|
||||||
|
// throwaway investigation probe, so it lives with the other
|
||||||
|
// always-available diagnostics rather than a dated section.
|
||||||
|
bool frameProf = _vm.FrameProf;
|
||||||
|
if (r.Checkbox("Frame profiler ([frame-prof])", ref frameProf)) _vm.FrameProf = frameProf;
|
||||||
|
|
||||||
// ── Indoor rendering diagnostics (2026-05-19) ───────────────
|
// ── Indoor rendering diagnostics (2026-05-19) ───────────────
|
||||||
// Pinpoint where the EnvCell rendering chain breaks for
|
// Pinpoint where the EnvCell rendering chain breaks for
|
||||||
// hypothesis-driven Phase 2 fix. Spec:
|
// hypothesis-driven Phase 2 fix. Spec:
|
||||||
|
|
|
||||||
|
|
@ -291,6 +291,17 @@ public sealed class DebugVM
|
||||||
set => PhysicsDiagnostics.ProbeAutoWalkEnabled = value;
|
set => PhysicsDiagnostics.ProbeAutoWalkEnabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runtime mirror of <c>RenderingDiagnostics.FrameProfEnabled</c>
|
||||||
|
/// (env var <c>ACDREAM_FRAME_PROF</c>). Toggling here starts/stops the
|
||||||
|
/// [frame-prof] 5-second report live — no relaunch required.
|
||||||
|
/// </summary>
|
||||||
|
public bool FrameProf
|
||||||
|
{
|
||||||
|
get => RenderingDiagnostics.FrameProfEnabled;
|
||||||
|
set => RenderingDiagnostics.FrameProfEnabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
// ── Indoor rendering diagnostics (2026-05-19) ───────────────────
|
// ── Indoor rendering diagnostics (2026-05-19) ───────────────────
|
||||||
// Mirror RenderingDiagnostics statics so DebugPanel checkbox toggles
|
// Mirror RenderingDiagnostics statics so DebugPanel checkbox toggles
|
||||||
// take effect on the next render frame without relaunching.
|
// take effect on the next render frame without relaunching.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue