stride3d/stride · error · NotSupportedException
Unsupported type for buffer layout
Error message
Unsupported type for buffer layout: {symbol} What it means
TypeSizeInBuffer has a switch over buffer-layout symbol kinds (scalars, vectors, matrices in Column/Row major, arrays). Types not covered — notably StructureType, marked TODO in the source — reach the default arm and throw NotSupportedException('Unsupported type for buffer layout'). The CBuffer layout code simply does not yet support struct-typed members.
Solutions
- Flatten or inline struct members before CBuffer layout, or lay out each member individually instead of passing the StructuredType
- Implement the StructureType case (compute per-member offsets via StructSizeInBuffer) in Builder.CBuffer.cs:56
- Ensure upstream type resolution converts user structs into flattened members before layout
Example fix
// before StructuredType s => throw new NotSupportedException(...), // after StructuredType s => StructSizeInBuffer(s, alignmentRules).Size, // implement struct layout
Defensive patterns
Strategy: type-guard
Validate before calling
bool IsLayoutSupported(TypeSymbol t) => t is ScalarType or VectorType or MatrixType or ArrayType; // StructuredType unsupported for CBuffer layout
if (!IsLayoutSupported(symbol)) throw new NotSupportedException($"Type {symbol} cannot be laid out in a CBuffer yet"); Type guard
static bool IsBufferLayoutable(TypeSymbol t) => t is not StructuredType and (ScalarType or VectorType or MatrixType or ArrayType);
Try / catch
try { size = TypeSizeInBuffer(symbol, modifier, rules); }
catch (NotSupportedException ex) { Log(ex.Message); size = symbol switch { StructuredType s => FlattenAndMeasure(s, rules), _ => 0 }; } Prevention
- Avoid struct-typed members inside cbuffers until StructureType layout is implemented
- Flatten nested structs into scalar/vector/matrix members upstream of layout
- Track the TODO at Builder.CBuffer.cs for StructureType support before enabling struct members
- Validate SPIR-V types resolve to primitives before running cbuffer layout
When it happens
Trigger: Computing buffer size/offset for a type symbol that is a StructureType (or any other unhandled symbol) — e.g. a cbuffer member declared as a nested struct, or a type that failed to resolve down to scalar/vector/matrix/array.
Common situations: HLSL cbuffers containing struct members being translated to SPIR-V; unresolved or error-recovery type symbols flowing into layout computation; forward-declared/abstract struct nodes.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Unsupported AlignmentRules value
- Unsupported type for storage buffer alignment
- Can't OpLoad with cbuffer
- Cannot simplify constant of type
- Unsupported constant type
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/a5b1d1295e8b8def.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.CBuffer.cs:56
VectorType v when alignmentRules == AlignmentRules.StructuredBuffer
=> (TypeSizeInBuffer(v.BaseType, typeModifier, alignmentRules).Size * v.Size,
TypeSizeInBuffer(v.BaseType, typeModifier, alignmentRules).Alignment * (v.Size == 2 ? 2 : 4)),
VectorType v => MultiplySize(TypeSizeInBuffer(v.BaseType, typeModifier, alignmentRules), v.Size),
// Note: this is HLSL-style so Rows/Columns meaning is swapped
// Note: HLSL default is ColumnMajor
// StructuredBuffer uses std430 strict matrix layout: each column (ColumnMajor) or row
// (RowMajor) is padded to its std430 base alignment, matching how the Vulkan validator
// expects matrix layout under relaxed block layout.
MatrixType m when alignmentRules == AlignmentRules.StructuredBuffer
=> StructuredBufferMatrixSize(m, typeModifier),
MatrixType m when typeModifier == TypeModifier.ColumnMajor || typeModifier == TypeModifier.None
=> MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), (4 * (m.Rows - 1)) + m.Columns),
MatrixType m when typeModifier == TypeModifier.RowMajor
=> MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), (4 * (m.Columns - 1)) + m.Rows),
// Round up to 16 bytes (size of float4)
ArrayType a => Array(TypeSizeInBuffer(a.BaseType, typeModifier, alignmentRules), a.Size, alignmentRules),
// TODO: StructureType
_ => throw new NotSupportedException($"Unsupported type for buffer layout: {symbol}"),
};
}
/// <summary>
/// Computes std430 size and alignment for a matrix in a StorageBuffer.
/// ColumnMajor: matrix is an array of <c>Columns</c> column-vectors of dimension <c>Rows</c>.
/// RowMajor: matrix is an array of <c>Rows</c> row-vectors of dimension <c>Columns</c>.
/// Each element vector is laid out at its std430 base-alignment stride, so non-square matrices
/// get trailing padding on the short axis.
/// </summary>
private static (int Size, int Alignment) StructuredBufferMatrixSize(MatrixType m, TypeModifier typeModifier)
{
var (vecDim, vecCount) = typeModifier == TypeModifier.RowMajor
? (m.Columns, m.Rows)
: (m.Rows, m.Columns);
var scalarSize = TypeSizeInBuffer(m.BaseType, typeModifier, AlignmentRules.StructuredBuffer).Size;
var vecSize = scalarSize * vecDim;
var vecAlignment = StorageBufferBaseAlignment(new VectorType(m.BaseType, vecDim));View on GitHub (pinned to 96fad776d2)