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

  1. Flatten or inline struct members before CBuffer layout, or lay out each member individually instead of passing the StructuredType
  2. Implement the StructureType case (compute per-member offsets via StructSizeInBuffer) in Builder.CBuffer.cs:56
  3. 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

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


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)