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>
125 lines
4.1 KiB
C#
125 lines
4.1 KiB
C#
using DatReaderWriter.DBObjs;
|
|
using DatReaderWriter.Lib.IO;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace AcDream.Content.Tests;
|
|
|
|
public sealed class BoundedDatObjectCacheTests
|
|
{
|
|
[Fact]
|
|
public void GetOrAdd_EvictsLeastRecentlyUsedEntryAtEntryLimit()
|
|
{
|
|
var cache = CreateCache(entryLimit: 2, byteLimit: 100);
|
|
var first = Surface(1);
|
|
var second = Surface(2);
|
|
var third = Surface(3);
|
|
|
|
cache.GetOrAdd(1, first);
|
|
cache.GetOrAdd(2, second);
|
|
Assert.True(cache.TryGet<Surface>(1, out _)); // first is now hottest
|
|
cache.GetOrAdd(3, third);
|
|
|
|
Assert.True(cache.TryGet<Surface>(1, out var retainedFirst));
|
|
Assert.Same(first, retainedFirst);
|
|
Assert.False(cache.TryGet<Surface>(2, out _));
|
|
Assert.True(cache.TryGet<Surface>(3, out var retainedThird));
|
|
Assert.Same(third, retainedThird);
|
|
Assert.Equal(2, cache.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_EnforcesEstimatedByteBudgetAndDoesNotRetainOversizeEntry()
|
|
{
|
|
var cache = new BoundedDatObjectCache(
|
|
entryLimit: 10,
|
|
estimatedByteLimit: 10,
|
|
estimateRetainedBytes: value => value.Id);
|
|
|
|
cache.GetOrAdd(6, Surface(6));
|
|
cache.GetOrAdd(5, Surface(5));
|
|
|
|
Assert.False(cache.TryGet<Surface>(6, out _));
|
|
Assert.True(cache.TryGet<Surface>(5, out _));
|
|
Assert.Equal(5, cache.EstimatedBytes);
|
|
|
|
var oversize = Surface(11);
|
|
Assert.Same(oversize, cache.GetOrAdd(11, oversize));
|
|
Assert.False(cache.TryGet<Surface>(11, out _));
|
|
Assert.Equal(1, cache.Count);
|
|
Assert.Equal(5, cache.EstimatedBytes);
|
|
}
|
|
|
|
[Fact]
|
|
public void ProductionEstimator_ChargesKnownRenderSurfacePayload()
|
|
{
|
|
const int byteLimit = 512 * 1024;
|
|
var cache = new BoundedDatObjectCache(
|
|
entryLimit: 10,
|
|
estimatedByteLimit: byteLimit);
|
|
var oversizeTexture = new RenderSurface
|
|
{
|
|
Id = 12,
|
|
SourceData = new byte[byteLimit + 1],
|
|
};
|
|
|
|
Assert.Same(oversizeTexture, cache.GetOrAdd(12, oversizeTexture));
|
|
Assert.False(cache.TryGet<RenderSurface>(12, out _));
|
|
Assert.Equal(0, cache.Count);
|
|
Assert.Equal(0, cache.EstimatedBytes);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_DuplicateKeyKeepsOneCanonicalObject()
|
|
{
|
|
var cache = CreateCache(entryLimit: 4, byteLimit: 100);
|
|
var canonical = Surface(7);
|
|
var duplicate = Surface(7);
|
|
|
|
Assert.Same(canonical, cache.GetOrAdd(7, canonical));
|
|
Assert.Same(canonical, cache.GetOrAdd(7, duplicate));
|
|
Assert.Equal(1, cache.Count);
|
|
Assert.Equal(1, cache.EstimatedBytes);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetOrAdd_ConcurrentDuplicateKeyPublishesOneCanonicalObject()
|
|
{
|
|
var cache = CreateCache(entryLimit: 4, byteLimit: 100);
|
|
var returned = new ConcurrentBag<Surface>();
|
|
|
|
Parallel.For(0, 1_000, i =>
|
|
{
|
|
returned.Add(cache.GetOrAdd(42, Surface((uint)(1_000 + i))));
|
|
});
|
|
|
|
Surface[] results = returned.ToArray();
|
|
Assert.NotEmpty(results);
|
|
Surface canonical = results[0];
|
|
Assert.All(results, value => Assert.Same(canonical, value));
|
|
Assert.True(cache.TryGet<Surface>(42, out var retained));
|
|
Assert.Same(canonical, retained);
|
|
Assert.Equal(1, cache.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void SameFileIdWithDifferentRequestedTypes_DoesNotAlias()
|
|
{
|
|
var cache = CreateCache(entryLimit: 4, byteLimit: 100);
|
|
var surface = Surface(99);
|
|
var palette = new Palette { Id = 99 };
|
|
|
|
cache.GetOrAdd<Surface>(99, surface);
|
|
cache.GetOrAdd<Palette>(99, palette);
|
|
|
|
Assert.True(cache.TryGet<Surface>(99, out var retainedSurface));
|
|
Assert.True(cache.TryGet<Palette>(99, out var retainedPalette));
|
|
Assert.Same(surface, retainedSurface);
|
|
Assert.Same(palette, retainedPalette);
|
|
Assert.Equal(2, cache.Count);
|
|
}
|
|
|
|
private static BoundedDatObjectCache CreateCache(int entryLimit, long byteLimit) =>
|
|
new(entryLimit, byteLimit, _ => 1);
|
|
|
|
private static Surface Surface(uint id) => new() { Id = id };
|
|
}
|