test(render): pin cell-shell batch-to-index-segment pairing under reorder
Uploads a cell-shell mesh whose storage order is the reverse of its surface
order and asserts each uploaded batch's FirstIndex reads back its own
indices from the arena. Guards the G1 regression fixed at 8c6563ca.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
e7ad25a705
commit
015b660d0f
1 changed files with 58 additions and 0 deletions
|
|
@ -232,6 +232,64 @@ public sealed class MeshPipelineDeviceSeamTests
|
|||
System.Runtime.InteropServices.MemoryMarshal.Cast<byte, ushort>(indexBytes).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Campaign OVERHAUL S1 (G1 FAIL 2026-09-02). Cell-shell batches upload in
|
||||
/// ascending source surface index (retail's built-EnvCell subset order,
|
||||
/// ConstructMesh @0x0059DFA0 / DrawMesh @0x0059D4A0), which differs from
|
||||
/// the (Width,Height,Format) storage order the index segments used to be
|
||||
/// filled in. The first fix ordered only the batch list, so batch i took
|
||||
/// segment i's index range from a different batch: magenta walls,
|
||||
/// stretched textures, missing faces in every dungeon. This pins that each
|
||||
/// uploaded batch's FirstIndex points at ITS OWN indices in the arena, with
|
||||
/// a fixture whose storage order is the reverse of its surface order.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CellShellBatchesKeepTheirOwnIndexRangesWhenReorderedBySurfaceIndex()
|
||||
{
|
||||
using var device = new RecordingGpuDevice();
|
||||
using ObjectMeshManager manager = Build(device, modernPath: true);
|
||||
GlobalMeshBuffer arena = manager.GlobalBuffer!;
|
||||
|
||||
static AcDream.Content.TextureBatchData CellBatch(int slot, uint surfaceId, int size, ushort[] indices) => new()
|
||||
{
|
||||
Key = new AcDream.Content.TextureKey { SurfaceId = surfaceId },
|
||||
TextureData = new byte[size * size * 4],
|
||||
Indices = [.. indices],
|
||||
IsCellShell = true,
|
||||
SourceSurfaceIndex = slot,
|
||||
CullMode = DatReaderWriter.Enums.CullMode.Clockwise,
|
||||
};
|
||||
|
||||
// Two storage groups (two texture sizes) so dictionary insertion order
|
||||
// puts slot 5 first; retail order is slot 2 first.
|
||||
var mesh = new AcDream.Content.ObjectMeshData
|
||||
{
|
||||
ObjectId = 0x1_0000_0000UL | 0xF4180104UL,
|
||||
Vertices = new VertexPositionNormalTexture[6],
|
||||
TextureBatches =
|
||||
{
|
||||
[(8, 8, Chorizite.Core.Render.Enums.TextureFormat.RGBA8)] = [CellBatch(5, 0x08000005u, 8, [0, 1, 2])],
|
||||
[(16, 16, Chorizite.Core.Render.Enums.TextureFormat.RGBA8)] = [CellBatch(2, 0x08000002u, 16, [3, 4, 5])],
|
||||
},
|
||||
};
|
||||
|
||||
ObjectRenderData data = Assert.IsType<ObjectRenderData>(manager.UploadMeshData(mesh));
|
||||
|
||||
Assert.Equal(2, data.Batches.Count);
|
||||
Assert.Equal(0x08000002u, data.Batches[0].Key.SurfaceId); // ascending surface index wins
|
||||
Assert.Equal(0x08000005u, data.Batches[1].Key.SurfaceId);
|
||||
|
||||
foreach (ObjectRenderBatch batch in data.Batches)
|
||||
{
|
||||
ushort[] expected = batch.Key.SurfaceId == 0x08000002u ? [3, 4, 5] : [0, 1, 2];
|
||||
var bytes = new byte[batch.IndexCount * sizeof(ushort)];
|
||||
arena.IndexStore!.Read((long)batch.FirstIndex * sizeof(ushort), bytes);
|
||||
Assert.Equal(
|
||||
expected,
|
||||
System.Runtime.InteropServices.MemoryMarshal.Cast<byte, ushort>(bytes).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #429 allocation gate (I1 style). Completing a prepared mesh on the
|
||||
/// render thread must allocate near its retained pick-copy size
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue