fix(portal): synchronize destination presentation state
This commit is contained in:
parent
4b1bceefbb
commit
e95f55f25b
42 changed files with 2815 additions and 288 deletions
|
|
@ -0,0 +1,104 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.Core.World;
|
||||
using DatReaderWriter.DBObjs;
|
||||
|
||||
namespace AcDream.App.Tests.Rendering.Wb;
|
||||
|
||||
public sealed class LandblockSpawnAdapterReadinessTests
|
||||
{
|
||||
[Fact]
|
||||
public void RenderReady_WaitsForStaticAndEnvCellMeshes()
|
||||
{
|
||||
var meshes = new ReadinessMeshAdapter();
|
||||
var adapter = new LandblockSpawnAdapter(meshes);
|
||||
var entity = new WorldEntity
|
||||
{
|
||||
Id = 1,
|
||||
ServerGuid = 0,
|
||||
SourceGfxObjOrSetupId = 0x01000010u,
|
||||
Position = Vector3.Zero,
|
||||
Rotation = Quaternion.Identity,
|
||||
MeshRefs = [new MeshRef(0x01000010u, Matrix4x4.Identity)],
|
||||
};
|
||||
var landblock = new LoadedLandblock(
|
||||
0x1234FFFFu,
|
||||
new LandBlock(),
|
||||
new[] { entity });
|
||||
const ulong envCellGeometryId = 0x2_0000_1234ul;
|
||||
|
||||
adapter.OnLandblockLoaded(landblock, new[] { envCellGeometryId });
|
||||
|
||||
Assert.False(adapter.IsLandblockRenderReady(landblock.LandblockId));
|
||||
meshes.ReadyIds.Add(0x01000010ul);
|
||||
Assert.False(adapter.IsLandblockRenderReady(landblock.LandblockId));
|
||||
meshes.ReadyIds.Add(envCellGeometryId);
|
||||
Assert.True(adapter.IsLandblockRenderReady(landblock.LandblockId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenderReady_EmptyPublishedLandblockIsReadyUntilUnload()
|
||||
{
|
||||
var meshes = new ReadinessMeshAdapter();
|
||||
var adapter = new LandblockSpawnAdapter(meshes);
|
||||
var landblock = new LoadedLandblock(
|
||||
0x1234FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>());
|
||||
|
||||
adapter.OnLandblockLoaded(landblock);
|
||||
|
||||
Assert.True(adapter.IsLandblockRenderReady(landblock.LandblockId));
|
||||
adapter.OnLandblockUnloaded(landblock.LandblockId);
|
||||
Assert.False(adapter.IsLandblockRenderReady(landblock.LandblockId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SharedEnvCellGeometry_IsPinnedPerLandblockAndReleasedSymmetrically()
|
||||
{
|
||||
const ulong sharedGeometryId = 0x2_0000_1234ul;
|
||||
var meshes = new ReadinessMeshAdapter();
|
||||
var adapter = new LandblockSpawnAdapter(meshes);
|
||||
var first = new LoadedLandblock(
|
||||
0x1234FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>());
|
||||
var second = new LoadedLandblock(
|
||||
0x1235FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>());
|
||||
|
||||
adapter.OnLandblockLoaded(first, new[] { sharedGeometryId, sharedGeometryId });
|
||||
adapter.OnLandblockLoaded(second, new[] { sharedGeometryId });
|
||||
|
||||
Assert.Equal(2, meshes.ReferenceCounts[sharedGeometryId]);
|
||||
Assert.Equal(2, meshes.PreparedPinCalls.Count);
|
||||
|
||||
adapter.OnLandblockUnloaded(first.LandblockId);
|
||||
Assert.Equal(1, meshes.ReferenceCounts[sharedGeometryId]);
|
||||
|
||||
adapter.OnLandblockUnloaded(second.LandblockId);
|
||||
Assert.DoesNotContain(sharedGeometryId, meshes.ReferenceCounts);
|
||||
}
|
||||
|
||||
private sealed class ReadinessMeshAdapter : IWbMeshAdapter
|
||||
{
|
||||
public HashSet<ulong> ReadyIds { get; } = new();
|
||||
public Dictionary<ulong, int> ReferenceCounts { get; } = new();
|
||||
public List<ulong> PreparedPinCalls { get; } = new();
|
||||
public void IncrementRefCount(ulong id) =>
|
||||
ReferenceCounts[id] = ReferenceCounts.GetValueOrDefault(id) + 1;
|
||||
public void PinPreparedRenderData(ulong id)
|
||||
{
|
||||
PreparedPinCalls.Add(id);
|
||||
IncrementRefCount(id);
|
||||
}
|
||||
public void DecrementRefCount(ulong id)
|
||||
{
|
||||
int count = ReferenceCounts[id] - 1;
|
||||
if (count == 0) ReferenceCounts.Remove(id);
|
||||
else ReferenceCounts[id] = count;
|
||||
}
|
||||
public bool IsRenderDataReady(ulong id) => ReadyIds.Contains(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.Content;
|
||||
using Chorizite.Core.Render.Enums;
|
||||
|
||||
namespace AcDream.App.Tests.Rendering.Wb;
|
||||
|
||||
public sealed class MeshUploadCachesTests
|
||||
{
|
||||
[Fact]
|
||||
public void CpuCacheHit_AfterCompletedUpload_ReStagesExactlyOnceWithTexturePayload()
|
||||
{
|
||||
var staging = new MeshUploadStagingQueue();
|
||||
var cache = new CpuMeshUploadCache(capacity: 2);
|
||||
byte[] textureBytes = [1, 2, 3, 4];
|
||||
var data = new ObjectMeshData { ObjectId = 0x01000010ul, UploadAttempts = 2 };
|
||||
data.TextureBatches[(1, 1, TextureFormat.RGBA8)] =
|
||||
[
|
||||
new TextureBatchData { TextureData = textureBytes },
|
||||
];
|
||||
cache.Store(data);
|
||||
|
||||
Assert.True(staging.Stage(data));
|
||||
Assert.True(staging.TryDequeue(out var initial));
|
||||
Assert.Same(data, initial);
|
||||
staging.Complete(data.ObjectId); // GPU upload completed, then was later evicted.
|
||||
|
||||
data.UploadAttempts = 3;
|
||||
Assert.True(cache.TryGetAndStage(data.ObjectId, staging, out var cached));
|
||||
Assert.Same(data, cached);
|
||||
Assert.Equal(0, data.UploadAttempts);
|
||||
Assert.Equal(textureBytes, cached!.TextureBatches.Values.Single().Single().TextureData);
|
||||
Assert.True(cache.TryGetAndStage(data.ObjectId, staging, out _));
|
||||
Assert.True(staging.TryDequeue(out var restaged));
|
||||
Assert.Same(data, restaged);
|
||||
Assert.False(staging.TryDequeue(out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Retry_RetainsQueueOwnershipUntilCompletion()
|
||||
{
|
||||
var staging = new MeshUploadStagingQueue();
|
||||
var data = new ObjectMeshData { ObjectId = 0x01000010ul };
|
||||
|
||||
Assert.True(staging.Stage(data));
|
||||
Assert.True(staging.TryDequeue(out var attempt));
|
||||
staging.Requeue(attempt!);
|
||||
Assert.False(staging.Stage(data));
|
||||
Assert.True(staging.TryDequeue(out var retry));
|
||||
Assert.Same(data, retry);
|
||||
|
||||
staging.Complete(data.ObjectId);
|
||||
Assert.True(staging.Stage(data));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UploadCompletion_NeverManufacturesLogicalOwnership()
|
||||
{
|
||||
const ulong id = 0x01000010ul;
|
||||
var ownership = new MeshOwnershipCounter();
|
||||
|
||||
Assert.Equal(1, ownership.Acquire(id));
|
||||
Assert.True(ownership.MarkUploadComplete(id));
|
||||
Assert.Equal(1, ownership.Count(id));
|
||||
|
||||
Assert.Equal(0, ownership.Release(id));
|
||||
Assert.False(ownership.MarkUploadComplete(id)); // late upload after unload
|
||||
Assert.Equal(0, ownership.Count(id));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue