fix #225: stabilize render pacing and frame CPU

Replace scheduler-quantized software sleeps with a reusable Windows high-resolution deadline timer, expose pacing in the frame profiler, and make shutdown wake every persistent mesh worker without losing the shared signal.

Preserve retail alpha order while using a stable radix, skip duplicate deferred-alpha SSBO packing, pack light sets, cache static selection descriptors, and retire historical material groups at the whole-frame boundary. The fixed dense-Caul sample improved from roughly 9-12 ms CPU to 5.3-6.2 ms without reducing visual quality.

Release build succeeds with zero warnings and all 6,300 tests pass with five intentional skips. Three independent retail, architecture, and adversarial reviews are clean; the post-review connected route remains pending because local ACE is offline.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-19 06:29:30 +02:00
parent 47d7086a74
commit 3718e341be
17 changed files with 1103 additions and 225 deletions

View file

@ -10871,7 +10871,9 @@ public sealed class GameWindow : IDisposable
$"acdream | {fps:F0} fps | {avgFrameTime:F1} ms | "
+ $"lb {visibleLandblocks}/{totalLandblocks} | ent {entityCount}/anim {animatedCount} | "
+ $"PY{titleCal.Year} {titleCal.Month} {titleCal.Day} {titleCal.Hour} (df={df:F4})";
if (_options.UiProbeEnabled)
// Script automation must remain performance-neutral. Only the
// explicit dump switch requests this allocation-heavy snapshot.
if (_options.UiProbeDump)
{
(int particleSets, long particleBytes) =
_particleRenderer?.DynamicBufferDiagnostics ?? default;
@ -12893,7 +12895,11 @@ public sealed class GameWindow : IDisposable
}
private void OnFrameRendered(double _)
=> _framePacing.CompleteFrame();
{
using var pacingStage = _frameProfiler.BeginStage(
AcDream.App.Diagnostics.FrameStage.Pacing);
_framePacing.CompleteFrame();
}
private void OnWindowMoved(Silk.NET.Maths.Vector2D<int> _)
=> RefreshActiveMonitorFramePacing();
@ -15022,6 +15028,9 @@ public sealed class GameWindow : IDisposable
}
private void OnClosing()
=> CompleteShutdown();
private void CompleteShutdown()
{
_shutdown ??= CreateShutdownTransaction();
try
@ -15036,7 +15045,6 @@ public sealed class GameWindow : IDisposable
// context/process teardown is the final safety net.
Console.Error.WriteLine($"[shutdown] {error}");
}
}
private ResourceShutdownTransaction CreateShutdownTransaction() => new(
@ -15160,6 +15168,7 @@ public sealed class GameWindow : IDisposable
new("text renderer", () => _textRenderer?.Dispose()),
new("debug font", () => _debugFont?.Dispose()),
new("frame profiler", _frameProfiler.Dispose),
new("frame pacing", _framePacing.Dispose),
]),
new ResourceShutdownStage("frame flight owner",
[
@ -15202,7 +15211,17 @@ public sealed class GameWindow : IDisposable
EndMouseLookAndRestoreCursor();
}
public void Dispose() => _window?.Dispose();
public void Dispose()
{
// Closing is the normal path and runs while the render context is
// current. This direct call also covers a constructed-but-never-run
// window and exceptions during Window.Create/Run, so owned kernel
// handles (including the frame timer) never depend on a native window
// event for disposal.
CompleteShutdown();
_window?.Dispose();
_window = null;
}
// ── Phase I.6 — TurbineChat outbound helpers ──────────────────