Skip to content

Commit 677d45e

Browse files
committed
SDSL: fix matrix size miscalculation in StructuredBuffer layout
MatrixType in TypeSizeInBuffer had a stray * 4 in the StructuredBuffer branch, so float4x4 reported 256 bytes instead of 64. Any RWStructuredBuffer<struct-with-matrix> would have emitted a broken ArrayStride — luckily the only real user is InstanceTransform, a float4x4 inside its own struct, and that path wasn't validated by a unit test. Replace the formula with std430 strict matrix layout: each column (ColumnMajor) or row (RowMajor) is padded to its std430 base alignment. Covers non-square matrices correctly under Vulkan relaxed block layout. Adds CSMatrix.sdsl regression test covering RWStructuredBuffer<Transform> where Transform = { float4x4 Matrix; float3 Scale }.
1 parent 7462e7d commit 677d45e

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.CBuffer.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,41 @@ public static (int Size, int Alignment) TypeSizeInBuffer(SymbolType symbol, Type
4141
VectorType v => MultiplySize(TypeSizeInBuffer(v.BaseType, typeModifier, alignmentRules), v.Size),
4242
// Note: this is HLSL-style so Rows/Columns meaning is swapped
4343
// Note: HLSL default is ColumnMajor
44+
// StructuredBuffer uses std430 strict matrix layout: each column (ColumnMajor) or row
45+
// (RowMajor) is padded to its std430 base alignment, matching how the Vulkan validator
46+
// expects matrix layout under relaxed block layout.
47+
MatrixType m when alignmentRules == AlignmentRules.StructuredBuffer
48+
=> StructuredBufferMatrixSize(m, typeModifier),
4449
MatrixType m when typeModifier == TypeModifier.ColumnMajor || typeModifier == TypeModifier.None
45-
=> MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), alignmentRules == AlignmentRules.CBuffer ? (4 * (m.Rows - 1)) + m.Columns : m.Rows * m.Columns * 4),
50+
=> MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), (4 * (m.Rows - 1)) + m.Columns),
4651
MatrixType m when typeModifier == TypeModifier.RowMajor
47-
=> MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), alignmentRules == AlignmentRules.CBuffer ? (4 * (m.Columns - 1)) + m.Rows : m.Rows * m.Columns * 4),
52+
=> MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), (4 * (m.Columns - 1)) + m.Rows),
4853
// Round up to 16 bytes (size of float4)
4954
ArrayType a => Array(TypeSizeInBuffer(a.BaseType, typeModifier, alignmentRules), a.Size, alignmentRules),
5055
// TODO: StructureType
5156
_ => throw new NotSupportedException($"Unsupported type for buffer layout: {symbol}"),
5257
};
5358
}
5459

60+
/// <summary>
61+
/// Computes std430 size and alignment for a matrix in a StorageBuffer.
62+
/// ColumnMajor: matrix is an array of <c>Columns</c> column-vectors of dimension <c>Rows</c>.
63+
/// RowMajor: matrix is an array of <c>Rows</c> row-vectors of dimension <c>Columns</c>.
64+
/// Each element vector is laid out at its std430 base-alignment stride, so non-square matrices
65+
/// get trailing padding on the short axis.
66+
/// </summary>
67+
private static (int Size, int Alignment) StructuredBufferMatrixSize(MatrixType m, TypeModifier typeModifier)
68+
{
69+
var (vecDim, vecCount) = typeModifier == TypeModifier.RowMajor
70+
? (m.Columns, m.Rows)
71+
: (m.Rows, m.Columns);
72+
var scalarSize = TypeSizeInBuffer(m.BaseType, typeModifier, AlignmentRules.StructuredBuffer).Size;
73+
var vecSize = scalarSize * vecDim;
74+
var vecAlignment = StorageBufferBaseAlignment(new VectorType(m.BaseType, vecDim));
75+
var vecStride = (vecSize + vecAlignment - 1) / vecAlignment * vecAlignment;
76+
return (vecStride * vecCount, vecAlignment);
77+
}
78+
5579
private static (int, int) StructSizeInBuffer(StructuredType s, AlignmentRules alignmentRules)
5680
{
5781
var offset = 0;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// PSMain(ExpectedResult=#00000000)
2+
3+
namespace Stride.Shaders.Tests;
4+
5+
shader CSMatrix
6+
{
7+
stage stream uint3 DispatchThreadId : SV_DispatchThreadID;
8+
9+
struct Transform
10+
{
11+
float4x4 Matrix;
12+
float3 Scale;
13+
};
14+
15+
RWTexture2D<float4> Output;
16+
RWStructuredBuffer<Transform> Output2;
17+
18+
[numthreads(1, 1, 1)]
19+
void CSMain()
20+
{
21+
Output[int2(0, 0)] = float4(0, 0, 0, 0);
22+
Output2[0].Scale = float3(0, 0, 0);
23+
}
24+
}

0 commit comments

Comments
 (0)