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
|
|
@ -26,6 +26,10 @@ internal sealed class ContiguousRangeAllocator
|
|||
public int HighWaterMark { get; private set; }
|
||||
public int Free => Capacity - Used;
|
||||
public int LargestFreeRange => _free.Count == 0 ? 0 : _free.Max(range => range.Length);
|
||||
public int TrailingFreeLength =>
|
||||
_free.Count != 0 && _free[^1].End == Capacity
|
||||
? _free[^1].Length
|
||||
: 0;
|
||||
|
||||
public bool TryAllocate(int length, out MeshBufferRange allocation)
|
||||
{
|
||||
|
|
@ -73,6 +77,30 @@ internal sealed class ContiguousRangeAllocator
|
|||
InsertAndCoalesce(new MeshBufferRange(oldCapacity, newCapacity - oldCapacity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an unused tail after the matching physical GPU buffer has been
|
||||
/// replaced. Live offsets are unchanged, so no render-data rewrite is
|
||||
/// required.
|
||||
/// </summary>
|
||||
public void Shrink(int newCapacity)
|
||||
{
|
||||
if (newCapacity <= 0 || newCapacity >= Capacity)
|
||||
throw new ArgumentOutOfRangeException(nameof(newCapacity));
|
||||
if (newCapacity < HighWaterMark)
|
||||
throw new InvalidOperationException("Cannot trim a GPU arena through a live allocation.");
|
||||
|
||||
MeshBufferRange tail = _free.Count == 0 ? default : _free[^1];
|
||||
if (tail.End != Capacity || tail.Offset > newCapacity)
|
||||
throw new InvalidOperationException("The requested GPU arena tail is not wholly free.");
|
||||
|
||||
if (tail.Offset == newCapacity)
|
||||
_free.RemoveAt(_free.Count - 1);
|
||||
else
|
||||
_free[^1] = new MeshBufferRange(tail.Offset, newCapacity - tail.Offset);
|
||||
Capacity = newCapacity;
|
||||
RecalculateHighWaterMark();
|
||||
}
|
||||
|
||||
public void Release(MeshBufferRange allocation)
|
||||
{
|
||||
if (allocation.Length <= 0
|
||||
|
|
@ -84,6 +112,7 @@ internal sealed class ContiguousRangeAllocator
|
|||
|
||||
InsertAndCoalesce(allocation);
|
||||
Used = checked(Used - allocation.Length);
|
||||
RecalculateHighWaterMark();
|
||||
}
|
||||
|
||||
private void InsertAndCoalesce(MeshBufferRange released)
|
||||
|
|
@ -114,4 +143,11 @@ internal sealed class ContiguousRangeAllocator
|
|||
|
||||
_free.Insert(index, new MeshBufferRange(start, end - start));
|
||||
}
|
||||
|
||||
private void RecalculateHighWaterMark()
|
||||
{
|
||||
HighWaterMark = _free.Count != 0 && _free[^1].End == Capacity
|
||||
? _free[^1].Offset
|
||||
: Capacity;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue