using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using AcDream.App.Rendering.Wb; using Xunit; namespace AcDream.App.Tests.Rendering.Wb; /// /// Campaign V slice V2 (2026-07-27): CPU-side proof that /// — EnvCellRenderer's per-batch GPU struct, /// sharing mesh_modern.vert's BatchData shader-side layout with /// WbDrawDispatcher — packs at the exact std430 offsets the shader expects /// after TextureHandle (a raw 64-bit ARB_bindless_texture handle) became /// TextureTableIndex (a slot into the binding=9 handle table). Mirrors /// ClipFrameLayoutTests' role for ClipFrame and /// WbDrawDispatcherIndirectBuilderTests.BatchDataPublic_LayoutMatchesPrivateBatchData /// for WbDrawDispatcher's own BatchData — a silent layout drift here would /// desync EnvCellRenderer's uploaded bytes from what mesh_modern.vert reads, /// with no build error. /// /// Layout under test (std430, 16 bytes total): /// offset 0 : uint TextureTableIndex /// offset 4 : uint Reserved (pad) /// offset 8 : uint TextureIndex (layer within the texture array) /// offset 12 : uint Flags /// public class ModernBatchDataLayoutTests { [Fact] public void Size_Is16Bytes_MatchingGpuBatchDataStride() { Assert.Equal(16, Unsafe.SizeOf()); } [Fact] public void FieldOffsets_MatchStd430Layout() { Assert.Equal(0, (int)Marshal.OffsetOf(nameof(ModernBatchData.TextureTableIndex))); Assert.Equal(4, (int)Marshal.OffsetOf(nameof(ModernBatchData.Reserved))); Assert.Equal(8, (int)Marshal.OffsetOf(nameof(ModernBatchData.TextureIndex))); Assert.Equal(12, (int)Marshal.OffsetOf(nameof(ModernBatchData.Flags))); } [Fact] public void FieldValues_RoundTripThroughTheStruct() { var data = new ModernBatchData { TextureTableIndex = 7u, TextureIndex = 3u, }; Assert.Equal(7u, data.TextureTableIndex); Assert.Equal(0u, data.Reserved); Assert.Equal(3u, data.TextureIndex); Assert.Equal(0u, data.Flags); } }