refactor(render): move outdoor dynamics onto landscape turns

This commit is contained in:
Erik 2026-08-31 03:57:45 +02:00
parent 474b05e7dc
commit 2127c955f6
8 changed files with 151 additions and 12 deletions

View file

@ -273,10 +273,14 @@ public sealed class RenderScenePViewFrameProductTests
0x0100_0000_0000_0023,
RenderProjectionClass.LiveDynamicRoot,
parentCell: Cell);
RenderProjectionRecord outdoorDynamic = Record(
0x0100_0000_0000_0024,
RenderProjectionClass.LiveDynamicRoot);
scene.Apply(
[
RenderProjectionDelta.Register(Generation, 1, lookInDynamic),
RenderProjectionDelta.Register(Generation, 2, rootDynamic),
RenderProjectionDelta.Register(Generation, 3, outdoorDynamic),
]);
PortalVisibilityFrame portal = Portal(Cell);
@ -309,6 +313,9 @@ public sealed class RenderScenePViewFrameProductTests
Assert.DoesNotContain(
frame.RouteCandidates.ToArray(),
candidate => candidate.Id == rootDynamic.Id);
Assert.DoesNotContain(
frame.RouteCandidates.ToArray(),
candidate => candidate.Id == outdoorDynamic.Id);
Assert.NotNull(frame.WalkLookInViews);
Assert.False(frame.WalkLookInViews!.SphereVisibleInLookInTurn(
routeIndex: 0,

View file

@ -92,6 +92,7 @@ public sealed class WalkFrameDriverTests
public readonly Dictionary<uint, WalkFrameStaticRecords> CellStaticsByCell = new();
public readonly Dictionary<uint, WalkFrameStaticRecords> CellDynamicsByCell = new();
public readonly Dictionary<uint, WalkFrameStaticRecords> OutdoorStaticsByCell = new();
public readonly Dictionary<uint, WalkFrameStaticRecords> OutdoorDynamicsByCell = new();
public readonly Dictionary<WalkBuilding, WalkFrameStaticRecords> ShellByBuilding = new();
public readonly Dictionary<WalkBuilding, Matrix4x4> WorldTransformByBuilding = new();
@ -104,6 +105,9 @@ public sealed class WalkFrameDriverTests
public WalkFrameStaticRecords GetOutdoorStatics(uint cellId) =>
OutdoorStaticsByCell.GetValueOrDefault(cellId, WalkFrameStaticRecords.Empty);
public WalkFrameStaticRecords GetOutdoorDynamics(uint cellId) =>
OutdoorDynamicsByCell.GetValueOrDefault(cellId, WalkFrameStaticRecords.Empty);
public WalkFrameStaticRecords GetBuildingShellStatics(WalkBuilding building) =>
ShellByBuilding.GetValueOrDefault(building, WalkFrameStaticRecords.Empty);
@ -601,12 +605,22 @@ public sealed class WalkFrameDriverTests
var worldData = new FakeWorldData();
worldData.OutdoorStaticsByCell[0x8C040005u] = new WalkFrameStaticRecords(
new[] { MakeRecord(301, 0, Vector3.Zero, [new MeshRef((uint)gfxObj, Matrix4x4.Identity)]) }, 0x8C04u);
worldData.OutdoorDynamicsByCell[0x8C040005u] = new WalkFrameStaticRecords(
new[] { MakeRecord(302, 0x50000001, 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, Matrix4x4.Identity, Vector3.Zero);
var activeViews = new WalkPortalView();
WalkCopyView.AppendFullViewportQuad(
activeViews,
ctx.Rays,
ctx.WorldViewpoint,
ctx.ViewportWidth,
ctx.ViewportHeight);
((IWalkEventSink)driver).OnLandscapeViews(activeViews);
((IWalkEventSink)driver).OnLandscapeCellTurn(0x8C040005u);
Assert.Empty(log); // no GPU work at Collect time; nothing recorded to the log yet
driver.EndFrame();
@ -615,9 +629,13 @@ public sealed class WalkFrameDriverTests
// FW4 #132 positional invariant: the cell's emitters submit at its
// own landscape turn, after its meshes flush.
Assert.Equal(new[] { "FLUSH:1:OutdoorStatic", "PARTICLES:12d" }, log);
GpuRecordedMultiDrawIndirect mdi = Assert.Single(fx.Device.Calls.OfType<GpuRecordedMultiDrawIndirect>());
Assert.Equal(1u, mdi.DrawCount);
Assert.Equal(
new[] { "FLUSH:2:OutdoorStatic,Dynamic", "PARTICLES:12d,12e" },
log);
GpuRecordedMultiDrawIndirect[] mdi =
fx.Device.Calls.OfType<GpuRecordedMultiDrawIndirect>().ToArray();
Assert.Equal(2, mdi.Length);
Assert.Equal(2u, mdi.Aggregate(0u, static (sum, call) => sum + call.DrawCount));
}
// ── Fixture (mirrors WalkStaticStreamPopulatorTests' DispatcherFixture —