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:
Erik 2026-07-18 21:35:16 +02:00
parent 3971997689
commit 749e8ceeb1
225 changed files with 29107 additions and 3914 deletions

View file

@ -11,10 +11,15 @@ public class StreamingControllerTests
private sealed class FakeStreamer
{
public List<uint> Loads { get; } = new();
public List<(uint Id, LandblockStreamJobKind Kind)> LoadJobs { get; } = new();
public List<uint> Unloads { get; } = new();
public Queue<LandblockStreamResult> Pending { get; } = new();
public void EnqueueLoad(uint id, LandblockStreamJobKind _) => Loads.Add(id);
public void EnqueueLoad(uint id, LandblockStreamJobKind kind)
{
Loads.Add(id);
LoadJobs.Add((id, kind));
}
public void EnqueueUnload(uint id) => Unloads.Add(id);
public IReadOnlyList<LandblockStreamResult> DrainCompletions(int max)
{
@ -65,6 +70,285 @@ public class StreamingControllerTests
Assert.Empty(fake.Unloads);
}
[Fact]
public void ReconfigureRadii_SmallerWindowUnloadsOnlyOutsideResidents()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
int pendingClears = 0;
var controller = new StreamingController(
fake.EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 2,
farRadius: 2,
clearPendingLoads: () => pendingClears++);
controller.Tick(50, 50);
for (int dx = -2; dx <= 2; dx++)
for (int dy = -2; dy <= 2; dy++)
AddPublished(state, 50 + dx, 50 + dy, LandblockStreamTier.Near);
fake.Loads.Clear();
fake.LoadJobs.Clear();
controller.ReconfigureRadii(0, 0);
Assert.Equal(1, pendingClears);
Assert.Empty(fake.Loads);
Assert.Equal(24, fake.Unloads.Count);
Assert.DoesNotContain(0x3232FFFFu, fake.Unloads);
}
[Fact]
public void ReconfigureRadii_LargerWindowLoadsOnlyMissingResidents()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
var controller = new StreamingController(
fake.EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 0,
farRadius: 0);
controller.Tick(50, 50);
AddPublished(state, 50, 50, LandblockStreamTier.Near);
fake.Loads.Clear();
fake.LoadJobs.Clear();
controller.ReconfigureRadii(1, 1);
Assert.Equal(8, fake.LoadJobs.Count);
Assert.All(
fake.LoadJobs,
static job => Assert.Equal(LandblockStreamJobKind.LoadNear, job.Kind));
Assert.DoesNotContain(fake.LoadJobs, static job => job.Id == 0x3232FFFFu);
Assert.Empty(fake.Unloads);
}
[Fact]
public void ReconfigureRadii_UnchangedWindowDoesNotClearOrRebootstrap()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
int pendingClears = 0;
var controller = new StreamingController(
fake.EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 1,
farRadius: 2,
clearPendingLoads: () => pendingClears++);
controller.Tick(50, 50);
fake.Loads.Clear();
fake.LoadJobs.Clear();
controller.ReconfigureRadii(1, 2);
Assert.Equal(0, pendingClears);
Assert.Empty(fake.Loads);
Assert.Empty(fake.Unloads);
}
[Fact]
public void ReconfigureRadii_ClearFailureRetainsOldWindowAndResumesWithoutDuplicateLoads()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
int clearAttempts = 0;
var controller = new StreamingController(
fake.EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 0,
farRadius: 0,
clearPendingLoads: () =>
{
clearAttempts++;
if (clearAttempts == 1)
throw new InvalidOperationException("clear not admitted");
});
controller.Tick(50, 50);
AddPublished(state, 50, 50, LandblockStreamTier.Near);
fake.LoadJobs.Clear();
Assert.Throws<AggregateException>(() => controller.ReconfigureRadii(1, 1));
Assert.Equal(0, controller.NearRadius);
Assert.Equal(0, controller.FarRadius);
Assert.Empty(fake.LoadJobs);
controller.ReconfigureRadii(1, 1);
Assert.Equal(2, clearAttempts);
Assert.Equal(8, fake.LoadJobs.Count);
Assert.Equal(8, fake.LoadJobs.Select(static job => job.Id).Distinct().Count());
Assert.Equal(1, controller.NearRadius);
Assert.Equal(1, controller.FarRadius);
}
[Fact]
public void ReconfigureRadii_QueueFailureRetriesOnlyUncommittedAdmission()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
int loadAttempts = 0;
bool failNext = false;
void EnqueueLoad(uint id, LandblockStreamJobKind kind)
{
loadAttempts++;
if (failNext)
{
failNext = false;
throw new InvalidOperationException("load not admitted");
}
fake.EnqueueLoad(id, kind);
}
var controller = new StreamingController(
EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 0,
farRadius: 0);
controller.Tick(50, 50);
AddPublished(state, 50, 50, LandblockStreamTier.Near);
fake.LoadJobs.Clear();
loadAttempts = 0;
failNext = true;
Assert.Throws<AggregateException>(() => controller.ReconfigureRadii(1, 1));
Assert.Equal(8, loadAttempts);
Assert.Equal(7, fake.LoadJobs.Count);
Assert.Equal(0, controller.NearRadius);
controller.ReconfigureRadii(1, 1);
Assert.Equal(9, loadAttempts);
Assert.Equal(8, fake.LoadJobs.Count);
Assert.Equal(8, fake.LoadJobs.Select(static job => job.Id).Distinct().Count());
Assert.Equal(1, controller.NearRadius);
}
[Fact]
public void ReconfigureRadii_CommittedQueueFailureIsReportedButNeverReplayed()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
bool throwCommitted = false;
int loadAttempts = 0;
void EnqueueLoad(uint id, LandblockStreamJobKind kind)
{
loadAttempts++;
fake.EnqueueLoad(id, kind);
if (throwCommitted)
{
throwCommitted = false;
throw new StreamingMutationException(
"post-admission diagnostic failed",
mutationCommitted: true);
}
}
var controller = new StreamingController(
EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 0,
farRadius: 0);
controller.Tick(50, 50);
AddPublished(state, 50, 50, LandblockStreamTier.Near);
fake.LoadJobs.Clear();
loadAttempts = 0;
throwCommitted = true;
Assert.Throws<AggregateException>(() => controller.ReconfigureRadii(1, 1));
Assert.Equal(8, loadAttempts);
Assert.Equal(8, fake.LoadJobs.Count);
Assert.Equal(1, controller.NearRadius);
controller.ReconfigureRadii(1, 1);
Assert.Equal(8, loadAttempts);
}
[Fact]
public void ReconfigureRadii_ClearCallbackReentryDefersWithoutRecursiveClear()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
StreamingController? controller = null;
int clearCalls = 0;
controller = new StreamingController(
fake.EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 0,
farRadius: 0,
clearPendingLoads: () =>
{
clearCalls++;
controller!.ReconfigureRadii(1, 1);
});
controller.Tick(50, 50);
AddPublished(state, 50, 50, LandblockStreamTier.Near);
fake.LoadJobs.Clear();
controller.ReconfigureRadii(1, 1);
Assert.Equal(1, clearCalls);
Assert.Equal(8, fake.LoadJobs.Count);
Assert.Equal(1, controller.NearRadius);
}
[Fact]
public void ReconfigureRadii_QueueCallbackReentryDefersWithoutDuplicateAdmission()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
StreamingController? controller = null;
bool reenter = false;
int loadCalls = 0;
void EnqueueLoad(uint id, LandblockStreamJobKind kind)
{
loadCalls++;
fake.EnqueueLoad(id, kind);
if (reenter)
{
reenter = false;
controller!.ReconfigureRadii(1, 1);
}
}
controller = new StreamingController(
EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 0,
farRadius: 0);
controller.Tick(50, 50);
AddPublished(state, 50, 50, LandblockStreamTier.Near);
fake.LoadJobs.Clear();
loadCalls = 0;
reenter = true;
controller.ReconfigureRadii(1, 1);
Assert.Equal(8, loadCalls);
Assert.Equal(8, fake.LoadJobs.Count);
Assert.Equal(8, fake.LoadJobs.Select(static job => job.Id).Distinct().Count());
Assert.Equal(1, controller.NearRadius);
}
[Fact]
public void DrainingLoadedResult_AddsToState()
{
@ -115,4 +399,59 @@ public class StreamingControllerTests
Assert.False(state.IsLoaded(landblockId));
}
[Fact]
public void DrainingUnloadedResult_CommitsStateBeforePresentationTeardown()
{
var state = new GpuWorldState();
var fake = new FakeStreamer();
const uint landblockId = 0x2020FFFFu;
var lb = new LoadedLandblock(
landblockId,
new LandBlock(),
new[]
{
new WorldEntity
{
Id = 1,
SourceGfxObjOrSetupId = 0x01000000u,
Position = System.Numerics.Vector3.Zero,
Rotation = System.Numerics.Quaternion.Identity,
MeshRefs = Array.Empty<MeshRef>(),
},
});
state.AddLandblock(lb);
bool callbackSawDetachedState = false;
var controller = new StreamingController(
fake.EnqueueLoad,
fake.EnqueueUnload,
fake.DrainCompletions,
(_, _) => { },
state,
nearRadius: 2,
farRadius: 2,
removeTerrain: id =>
{
callbackSawDetachedState = id == landblockId
&& !state.TryGetLandblock(id, out _);
});
fake.Pending.Enqueue(new LandblockStreamResult.Unloaded(landblockId));
controller.Tick(50, 50);
Assert.True(callbackSawDetachedState);
Assert.False(state.IsLoaded(landblockId));
}
private static void AddPublished(
GpuWorldState state,
int x,
int y,
LandblockStreamTier tier)
{
uint id = ((uint)x << 24) | ((uint)y << 16) | 0xFFFFu;
state.AddLandblock(
new LoadedLandblock(id, new LandBlock(), Array.Empty<WorldEntity>()),
tier: tier);
}
}