phase(N.5) Task 9 fixup: layout assertion + DrawCommandStride const

Code quality review caught:
- sizeofDEIC was a local; promoted to public const DrawCommandStride
  so tests can reference it symbolically.
- BatchDataPublic layout invariant (size + field offsets) wasn't
  asserted in tests. Added BatchDataPublic_LayoutMatchesPrivateBatchData
  + DrawCommandStride_MatchesStructSize tests to gate Task 10's
  MemoryMarshal.Cast<BatchData, BatchDataPublic> safety.
- Plan doc updated: BatchDataPublic spec was Pack=4 (wrong — must
  match private BatchData's Pack=8 for the cast to work). Implementation
  was already correct; plan now matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-08 20:42:49 +02:00
parent 9a7a250b62
commit b163c53622
3 changed files with 30 additions and 5 deletions

View file

@ -1364,7 +1364,8 @@ public readonly record struct IndirectGroupInput(
TranslucencyKind Translucency);
/// <summary>Public mirror of the per-group BatchData laid into the SSBO. Tests verify alignment.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 4)]
// Pack=8 (not 4) — must stay layout-identical to private BatchData for Task 10's MemoryMarshal.Cast.
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct BatchDataPublic
{
public ulong TextureHandle;
@ -1431,8 +1432,7 @@ public static IndirectLayoutResult BuildIndirectArrays(
}
}
int sizeofDEIC = 20; // matches struct layout
return new IndirectLayoutResult(opaqueCount, transparentCount, opaqueCount * sizeofDEIC);
return new IndirectLayoutResult(opaqueCount, transparentCount, opaqueCount * DrawCommandStride);
}
private static bool IsOpaque(TranslucencyKind t)