fix(rendering): bound portal resource lifetime
Separate logical ownership, render publication, and GPU retirement across live entities, landblocks, particles, textures, mesh arenas, portal/UI teardown, and per-frame scratch storage. Add bounded DAT/texture caches, upload budgets, three-frame fence retirement, exact-incarnation appearance reconciliation, frame pacing, and extensive lifetime conformance coverage.\n\nThe seven-destination connected route now cuts peak working/private memory roughly in half, returns Caul to 125-153 FPS locally, and produces no WER or AMD reset.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
3971997689
commit
749e8ceeb1
225 changed files with 29107 additions and 3914 deletions
|
|
@ -206,4 +206,97 @@ public class ClipFrameAssemblerTests
|
|||
Assert.False(asm2.OutdoorVisible);
|
||||
Assert.Equal(TerrainClipMode.Skip, asm2.TerrainMode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Assemble_ReusedAssembly_ClearsStateAndReusesExactLengthArrays()
|
||||
{
|
||||
const uint firstCell = 0xA9B40100;
|
||||
const uint secondCell = 0xA9B40200;
|
||||
var frame = ClipFrame.NoClip();
|
||||
var reuse = new ClipFrameAssembly();
|
||||
|
||||
var first = new PortalVisibilityFrame();
|
||||
first.CellViews[firstCell] = ViewOf(
|
||||
Square(-0.4f, 0f, 0.15f),
|
||||
Square(0.4f, 0f, 0.15f));
|
||||
first.OrderedVisibleCells.Add(firstCell);
|
||||
first.OutsideView.Add(Square(0f, 0.5f, 0.2f));
|
||||
ClipFrameAssembly firstResult = ClipFrameAssembler.Assemble(frame, first, reuse);
|
||||
Assert.Same(reuse, firstResult);
|
||||
int sliceAllocations = reuse.SliceArrayAllocationCount;
|
||||
int slotAllocations = reuse.SlotArrayAllocationCount;
|
||||
|
||||
var second = new PortalVisibilityFrame();
|
||||
second.CellViews[secondCell] = ViewOf(
|
||||
Square(-0.4f, 0f, 0.15f),
|
||||
Square(0.4f, 0f, 0.15f));
|
||||
second.OrderedVisibleCells.Add(secondCell);
|
||||
second.OutsideView.Add(Square(0f, 0.5f, 0.2f));
|
||||
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
ClipFrameAssembly actual = ClipFrameAssembler.Assemble(frame, second, reuse);
|
||||
Assert.Same(reuse, actual);
|
||||
Assert.DoesNotContain(firstCell, actual.CellIdToViewSlices.Keys);
|
||||
Assert.Contains(secondCell, actual.CellIdToViewSlices.Keys);
|
||||
Assert.Equal(2, actual.CellIdToViewSlices[secondCell].Length);
|
||||
Assert.Equal(2, actual.CellIdToViewSlots[secondCell].Length);
|
||||
Assert.Single(actual.OutsideViewSlices);
|
||||
Assert.Equal(sliceAllocations, reuse.SliceArrayAllocationCount);
|
||||
Assert.Equal(slotAllocations, reuse.SlotArrayAllocationCount);
|
||||
}
|
||||
|
||||
var empty = new PortalVisibilityFrame();
|
||||
ClipFrameAssembly cleared = ClipFrameAssembler.Assemble(frame, empty, reuse);
|
||||
Assert.Empty(cleared.CellIdToSlot);
|
||||
Assert.Empty(cleared.CellIdToViewSlots);
|
||||
Assert.Empty(cleared.CellIdToViewSlices);
|
||||
Assert.Empty(cleared.PerCellPlaneCounts);
|
||||
Assert.Empty(cleared.OutsideViewSlices);
|
||||
Assert.Equal(TerrainClipMode.Skip, cleared.TerrainMode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Assemble_ReusedAssembly_ChangingCardinalityStaysBoundedThenReachesSteadyState()
|
||||
{
|
||||
const uint cellId = 0xA9B40100;
|
||||
var frame = ClipFrame.NoClip();
|
||||
var reuse = new ClipFrameAssembly();
|
||||
|
||||
static PortalVisibilityFrame FrameWithSlices(uint id, int count)
|
||||
{
|
||||
var portalFrame = new PortalVisibilityFrame();
|
||||
var view = new CellView();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// The assembler consumes the retail view_poly list directly. Distinct placement is
|
||||
// irrelevant to this cache-cardinality stress; avoid CellView dedup collapsing it.
|
||||
view.Polygons.Add(Square(i * 0.001f, 0f, 0.0004f));
|
||||
}
|
||||
portalFrame.CellViews[id] = view;
|
||||
portalFrame.OrderedVisibleCells.Add(id);
|
||||
return portalFrame;
|
||||
}
|
||||
|
||||
for (int count = 1; count <= 180; count++)
|
||||
ClipFrameAssembler.Assemble(frame, FrameWithSlices(cellId, count), reuse);
|
||||
|
||||
// Flush the final live arrays into the cache too.
|
||||
ClipFrameAssembler.Assemble(frame, new PortalVisibilityFrame(), reuse);
|
||||
Assert.InRange(reuse.RetainedSliceItems, 0, ClipFrameAssembly.MaxRetainedSliceItems);
|
||||
Assert.InRange(reuse.RetainedSlotItems, 0, ClipFrameAssembly.MaxRetainedSlotItems);
|
||||
Assert.InRange(reuse.RetainedSliceArrays, 0, ClipFrameAssembly.MaxRetainedArraysPerPool);
|
||||
Assert.InRange(reuse.RetainedSlotArrays, 0, ClipFrameAssembly.MaxRetainedArraysPerPool);
|
||||
|
||||
PortalVisibilityFrame steady = FrameWithSlices(cellId, 73);
|
||||
ClipFrameAssembler.Assemble(frame, steady, reuse);
|
||||
int sliceAllocations = reuse.SliceArrayAllocationCount;
|
||||
int slotAllocations = reuse.SlotArrayAllocationCount;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
ClipFrameAssembler.Assemble(frame, steady, reuse);
|
||||
Assert.Equal(sliceAllocations, reuse.SliceArrayAllocationCount);
|
||||
Assert.Equal(slotAllocations, reuse.SlotArrayAllocationCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue