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

@ -534,6 +534,13 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
// These are public so the pure-CPU unit tests in AcDream.Core.Tests can
// exercise BuildIndirectArrays without needing a GL context.
/// <summary>
/// Stride in bytes of <c>DrawElementsIndirectCommand</c> in the indirect buffer.
/// 5 × <c>uint</c> = 20 bytes. Tests and callers reference this symbolically
/// rather than hard-coding <c>20</c> so a layout change produces a compile error.
/// </summary>
public const int DrawCommandStride = 20; // sizeof(DrawElementsIndirectCommand): 5 × uint
/// <summary>
/// Public view of the per-group inputs to <see cref="BuildIndirectArrays"/> — used in tests.
/// </summary>
@ -622,8 +629,7 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
}
}
const int SizeofDEIC = 20; // sizeof(DrawElementsIndirectCommand) — 5 × uint
return new IndirectLayoutResult(opaqueCount, transparentCount, opaqueCount * SizeofDEIC);
return new IndirectLayoutResult(opaqueCount, transparentCount, opaqueCount * DrawCommandStride);
}
private static bool IsOpaque(TranslucencyKind t)