perf(render) Campaign FW3.4a: one walk pass; prepare-once/draw-ranges; arena records

The FW3.4 dense-Arwic pair triggered the +/-20% stop rule (+33.5% CPU
p50, 14x frame allocation). This slice removes the three measured
costs without changing GPU command order (the referee suites assert
identical recorded call sequences):

- WalkFrameDriver: Collect (ONE walk per frame - no GPU work; leaf
  calls and flush points become a recorded event list; the driver
  absorbed the renderer collection pass and exposes the visited sets)
  + Replay (prepare the whole stream once, then replay events,
  interleaving DrawOrderedRange with leaf calls in the exact recorded
  order). RunFrame = Collect+Replay for existing callers.
- WbDrawDispatcher: SubmitOrderedStream split into PrepareOrderedStream
  (all sections + commands + merge runs uploaded once per frame) and
  DrawOrderedRange (bind-once latch; per-run pipeline + DrawIdOffset +
  DrawIndirectRangeRhi). Load-bearing correctness catch from the
  implementation round: merge runs take FORCED BREAKS at the recorded
  event marks - whole-stream merging must not fuse two segments that
  retail separates with a leaf GPU call (shell, punch); the straddle
  assert stays as a dead-code safety net.
- WalkProductionWorldData: WalkFrameStaticRecords carries an
  ArraySegment into a per-frame grow-only arena; the per-cell
  fresh-array copies (the 1.9 MB/frame alloc p50) are gone - zero
  steady-state allocation after warmup.

Suites (lead-verified): full Release build 0 warnings; hermetic
6,758/0; Walk lane 209/1; InstalledDat Walk conformance 40/1
untouched. Next: the dense-Arwic re-measure against the same-session
baseline.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-30 17:01:26 +02:00
parent 6301e4dbea
commit 212f5a12e5
7 changed files with 1051 additions and 359 deletions

View file

@ -216,9 +216,9 @@ public sealed class WalkFrameDriverTests
var worldData = new FakeWorldData();
worldData.CellStaticsByCell[0x100] = new WalkFrameStaticRecords(
[MakeRecord(101, 0, Vector3.Zero, [new MeshRef((uint)gfxObjA, Matrix4x4.Identity)])], 0x8C04u);
new[] { MakeRecord(101, 0, Vector3.Zero, [new MeshRef((uint)gfxObjA, Matrix4x4.Identity)]) }, 0x8C04u);
worldData.CellStaticsByCell[0x101] = new WalkFrameStaticRecords(
[MakeRecord(102, 0, Vector3.Zero, [new MeshRef((uint)gfxObjB, Matrix4x4.Identity)])], 0x8C04u);
new[] { MakeRecord(102, 0, Vector3.Zero, [new MeshRef((uint)gfxObjB, Matrix4x4.Identity)]) }, 0x8C04u);
var leaf = new RecordingLeafRenderer(log);
var trace = new RecordingTrace(log);
@ -294,9 +294,9 @@ public sealed class WalkFrameDriverTests
var worldData = new FakeWorldData();
worldData.CellStaticsByCell[0x100] = new WalkFrameStaticRecords(
[MakeRecord(101, 0, Vector3.Zero, [new MeshRef((uint)gfxObjA, Matrix4x4.Identity)])], 0x8C04u);
new[] { MakeRecord(101, 0, Vector3.Zero, [new MeshRef((uint)gfxObjA, Matrix4x4.Identity)]) }, 0x8C04u);
worldData.CellStaticsByCell[0x101] = new WalkFrameStaticRecords(
[MakeRecord(102, 0, Vector3.Zero, [new MeshRef((uint)gfxObjB, Matrix4x4.Identity)])], 0x8C04u);
new[] { MakeRecord(102, 0, Vector3.Zero, [new MeshRef((uint)gfxObjB, Matrix4x4.Identity)]) }, 0x8C04u);
var leaf = new RecordingLeafRenderer(log);
var trace = new RecordingTrace(log);
@ -383,9 +383,9 @@ public sealed class WalkFrameDriverTests
var worldData = new FakeWorldData();
worldData.ShellByBuilding[building] = new WalkFrameStaticRecords(
[MakeRecord(201, 0, Vector3.Zero, [new MeshRef((uint)shellGfxObj, Matrix4x4.Identity)])], 0x8C04u);
new[] { MakeRecord(201, 0, Vector3.Zero, [new MeshRef((uint)shellGfxObj, Matrix4x4.Identity)]) }, 0x8C04u);
worldData.CellStaticsByCell[0x104] = new WalkFrameStaticRecords(
[MakeRecord(202, 0, Vector3.Zero, [new MeshRef((uint)interiorGfxObj, Matrix4x4.Identity)])], 0x8C04u);
new[] { MakeRecord(202, 0, Vector3.Zero, [new MeshRef((uint)interiorGfxObj, Matrix4x4.Identity)]) }, 0x8C04u);
Matrix4x4 buildingWorld = Matrix4x4.CreateTranslation(10f, 0f, 0f);
worldData.WorldTransformByBuilding[building] = buildingWorld;
@ -401,9 +401,10 @@ public sealed class WalkFrameDriverTests
Assert.Equal(1, activeView.ViewCount);
using DrawScope draw = fx.BeginDraw();
driver.BeginFrame(ctx, draw.Frame, draw.Pass, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
driver.BeginFrame(ctx, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
walk.DrawBuilding(building, activeView, ctx, driver);
driver.EndFrame();
driver.Replay(draw.Frame, draw.Pass);
Assert.Equal(
new[] { "ALPHA:12.50", "PUNCH:4@v0", "SHELL:00000104", "FLUSH:1:LookInStatic", "FLUSH:1:BuildingShell" },
@ -433,7 +434,7 @@ public sealed class WalkFrameDriverTests
var driver = new WalkFrameDriver(fx.Dispatcher, new RecordingLeafRenderer(log), new FakeWorldData());
using DrawScope draw = fx.BeginDraw();
driver.BeginFrame(ctx, draw.Frame, draw.Pass, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
driver.BeginFrame(ctx, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
Assert.Throws<InvalidOperationException>(
() => ((IWalkEventSink)driver).Emit(WalkEvent.DrawCells(0, [0x100u])));
@ -450,18 +451,82 @@ public sealed class WalkFrameDriverTests
var driver = new WalkFrameDriver(fx.Dispatcher, new RecordingLeafRenderer(log), new FakeWorldData());
using DrawScope draw = fx.BeginDraw();
driver.BeginFrame(ctx, draw.Frame, draw.Pass, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
driver.BeginFrame(ctx, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
Assert.Throws<InvalidOperationException>(
() => driver.BeginFrame(
ctx, draw.Frame, draw.Pass, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0));
ctx, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0));
driver.EndFrame();
// EndFrame cleared the open-frame guard: BeginFrame is usable again.
driver.BeginFrame(ctx, draw.Frame, draw.Pass, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
driver.BeginFrame(ctx, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
driver.EndFrame();
}
// ── Campaign FW3.4a fail-loud: Replay without a completed Collect (no
// BeginFrame/EndFrame at all, or BeginFrame with no matching EndFrame)
// has nothing recorded to draw — throw rather than silently drawing
// nothing, which would look like an empty frame instead of a misuse. ──
[Fact]
public void Replay_WithNoPrecedingCollect_Throws()
{
using var fx = new DispatcherFixture();
var log = new List<string>();
var driver = new WalkFrameDriver(fx.Dispatcher, new RecordingLeafRenderer(log), new FakeWorldData());
using DrawScope draw = fx.BeginDraw();
Assert.Throws<InvalidOperationException>(() => driver.Replay(draw.Frame, draw.Pass));
}
[Fact]
public void Replay_WhileCollectIsStillOpen_Throws()
{
using var fx = new DispatcherFixture();
var log = new List<string>();
var ctx = new TestContext();
var driver = new WalkFrameDriver(fx.Dispatcher, new RecordingLeafRenderer(log), new FakeWorldData());
using DrawScope draw = fx.BeginDraw();
driver.BeginFrame(ctx, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
Assert.Throws<InvalidOperationException>(() => driver.Replay(draw.Frame, draw.Pass));
}
// ── Deliverable: Collect + Replay called as the SPLIT PAIR (never
// RunFrame) — the shape RetailPViewRenderer uses, since it must run other
// frame work (PrepareCellBatches/BuildAndBorrow) between the two. Proves
// the pair alone — with no GPU work happening until Replay — reproduces
// the same turn order RunFrame's combined call would. ──────────────────
[Fact]
public void CollectThenReplay_AsSeparateCalls_PerformsNoGpuWorkUntilReplay()
{
using var fx = new DispatcherFixture();
var log = new List<string>();
var ctx = new TestContext();
var driver = new WalkFrameDriver(
fx.Dispatcher, new RecordingLeafRenderer(log), new FakeWorldData(), new RecordingTrace(log));
var walk = new RetailFrameWalk();
// Outdoor root (camera cell low word < 0x100): a minimal, no-op
// landscape — LScape::draw still runs its sky/terrain turn against
// it even though nothing is published to walk cells/buildings for.
var landscape = new WalkLandscape { MidWidth = 1, Blocks = new WalkLandBlock?[1] };
using DrawScope draw = fx.BeginDraw();
driver.Collect(
walk, cameraCellId: 0u, cameraCell: null, landscape, ctx,
Matrix4x4.Identity, cameraWorldPosition: Vector3.Zero, activeTerrainSliceCount: 1);
// No GPU calls at all yet — Collect is CPU-only.
Assert.Empty(log);
Assert.Empty(fx.Device.Calls);
driver.Replay(draw.Frame, draw.Pass);
Assert.Equal(new[] { "SKY", "TERRAIN:0" }, log);
}
// ── Deliverable: an outdoor landscape-cell turn with no building appends
// straight to the stream (no shell call — outdoor cells have no EnvCell
// shell), and the accumulated content flushes at frame end. ───────────
@ -478,16 +543,18 @@ public sealed class WalkFrameDriverTests
var ctx = new TestContext();
var worldData = new FakeWorldData();
worldData.OutdoorStaticsByCell[0x8C040005u] = new WalkFrameStaticRecords(
[MakeRecord(301, 0, Vector3.Zero, [new MeshRef((uint)gfxObj, Matrix4x4.Identity)])], 0x8C04u);
new[] { MakeRecord(301, 0, Vector3.Zero, [new MeshRef((uint)gfxObj, Matrix4x4.Identity)]) }, 0x8C04u);
var driver = new WalkFrameDriver(
fx.Dispatcher, new RecordingLeafRenderer(log), worldData, new RecordingTrace(log));
using DrawScope draw = fx.BeginDraw();
driver.BeginFrame(ctx, draw.Frame, draw.Pass, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
driver.BeginFrame(ctx, Matrix4x4.Identity, Vector3.Zero, activeTerrainSliceCount: 0);
((IWalkEventSink)driver).OnLandscapeCellTurn(0x8C040005u);
Assert.Empty(log); // accumulates in the stream; nothing flushed yet
Assert.Empty(log); // no GPU work at Collect time; nothing recorded to the log yet
driver.EndFrame();
Assert.Empty(log); // still nothing — EndFrame closes Collect, it does not Replay
driver.Replay(draw.Frame, draw.Pass);
Assert.Equal(new[] { "FLUSH:1:OutdoorStatic" }, log);
GpuRecordedMultiDrawIndirect mdi = Assert.Single(fx.Device.Calls.OfType<GpuRecordedMultiDrawIndirect>());