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
55
src/AcDream.App/Rendering/Wb/TextureAtlasSlotAllocator.cs
Normal file
55
src/AcDream.App/Rendering/Wb/TextureAtlasSlotAllocator.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
namespace AcDream.App.Rendering.Wb;
|
||||
|
||||
/// <summary>
|
||||
/// Owns the physical layer slots in one texture array. A released texture
|
||||
/// remains rented until the GPU-retirement callback returns its layer, so
|
||||
/// <see cref="AvailableCount"/> never advertises a CPU-unreferenced layer
|
||||
/// that an in-flight draw may still sample.
|
||||
/// </summary>
|
||||
internal sealed class TextureAtlasSlotAllocator
|
||||
{
|
||||
private readonly bool[] _rented;
|
||||
private readonly Stack<int> _returned = new();
|
||||
private int _next;
|
||||
|
||||
public TextureAtlasSlotAllocator(int capacity)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(capacity, 1);
|
||||
_rented = new bool[capacity];
|
||||
}
|
||||
|
||||
public int AvailableCount => _returned.Count + (_rented.Length - _next);
|
||||
|
||||
public int Rent()
|
||||
{
|
||||
int slot;
|
||||
if (_returned.Count != 0)
|
||||
{
|
||||
slot = _returned.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_next == _rented.Length)
|
||||
throw new InvalidOperationException(
|
||||
$"Texture atlas has no GPU-safe layer available ({_rented.Length} layers)."
|
||||
);
|
||||
slot = _next++;
|
||||
}
|
||||
|
||||
if (_rented[slot])
|
||||
throw new InvalidOperationException($"Texture atlas layer {slot} was rented twice.");
|
||||
_rented[slot] = true;
|
||||
return slot;
|
||||
}
|
||||
|
||||
public void Return(int slot)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(slot);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(slot, _next);
|
||||
if (!_rented[slot])
|
||||
throw new InvalidOperationException($"Texture atlas layer {slot} was returned twice.");
|
||||
|
||||
_rented[slot] = false;
|
||||
_returned.Push(slot);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue