stride3d/stride · error · NotSupportedException

Unsupported type for storage buffer alignment: {type}

Error message

Unsupported type for storage buffer alignment: {type}

What it means

StorageBufferBaseAlignment computes std430-style base alignment for a type in a storage buffer: vectors use their element size, matrices map to a vector of their innermost dimension, arrays recurse on the element, structs take the max member alignment. A type outside these cases (e.g. an unresolved or unexpected symbol, or effectively a bare scalar at top level per this switch) throws NotSupportedException('Unsupported type for storage buffer alignment').

Solutions

  1. Ensure the type symbol fully resolves to Scalar/Vector/Matrix/Array/StructuredType before storage-buffer layout
  2. Implement a case for the unsupported type kind in Builder.CBuffer.cs:162 (e.g. treat bare scalars as (size, size))
  3. Log/inspect the type symbol to find why type resolution produced an unhandled kind

Example fix

// before
_ => throw new NotSupportedException($"Unsupported type for storage buffer alignment: {type}"),
// after
ScalarType sc => (SizeOf(sc), SizeOf(sc)),
_ => throw new NotSupportedException($"Unsupported type for storage buffer alignment: {type}")
Defensive patterns

Strategy: type-guard

Validate before calling

bool HasStorageBufferAlignment(TypeSymbol t) => t is ScalarType or VectorType or MatrixType or ArrayType or StructuredType;
if (!HasStorageBufferAlignment(type)) throw new NotSupportedException($"Type {type} has no std430 alignment");

Type guard

static bool IsStd430Alignable(TypeSymbol t) => t is ScalarType or VectorType or MatrixType or ArrayType or StructuredType;

Try / catch

try { alignment = StorageBufferBaseAlignment(type, modifier); }
catch (NotSupportedException ex) { Log($"Unresolvable type for std430: {ex.Message}"); alignment = 16; /* conservative fallback */ }

Prevention

When it happens

Trigger: Calling StorageBufferBaseAlignment (directly or via vecAlignment/MaxMemberAlignment/alignment) with a symbol not matching Scalar/Vector/Matrix/Array/StructuredType — e.g. an error or placeholder type from failed resolution, or a new type node kind added to the IR.

Common situations: Storage-buffer layout of shaders with unresolved types after parse errors; new IR node types added without updating the alignment switch; deeply nested constructs where recursion reaches an unexpected leaf type.

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/6b28ec3a7ef67449. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.CBuffer.cs:162

    /// Computes the std430 base alignment of a type as required by Vulkan's storage buffer layout
    /// (vec2 → 2×scalar, vec3/vec4 → 4×scalar, struct → max member alignment). Used to round the
    /// ArrayStride of a [RW]StructuredBuffer element type so the SPIR-V validates under relaxed
    /// block layout. Relaxed rules allow scalar-aligned offsets for vector members, but an array
    /// of structs still needs its stride aligned to the struct's base alignment.
    /// </summary>
    public static int StorageBufferBaseAlignment(SymbolType type, TypeModifier typeModifier = TypeModifier.None) => type switch
    {
        ScalarType { Type: Scalar.Int or Scalar.UInt or Scalar.Float or Scalar.Boolean or Scalar.Half } => 4,
        ScalarType { Type: Scalar.Int64 or Scalar.UInt64 or Scalar.Double } => 8,
        VectorType { Size: 2, BaseType: var bt } => 2 * StorageBufferBaseAlignment(bt),
        VectorType { Size: 3 or 4, BaseType: var bt } => 4 * StorageBufferBaseAlignment(bt),
        MatrixType m when typeModifier == TypeModifier.RowMajor
            => StorageBufferBaseAlignment(new VectorType(m.BaseType, m.Columns)),
        MatrixType m
            => StorageBufferBaseAlignment(new VectorType(m.BaseType, m.Rows)),
        ArrayType a => StorageBufferBaseAlignment(a.BaseType, typeModifier),
        StructuredType s => MaxMemberAlignment(s),
        _ => throw new NotSupportedException($"Unsupported type for storage buffer alignment: {type}"),
    };

    static int MaxMemberAlignment(StructuredType s)
    {
        var max = 4;
        foreach (var member in s.Members)
            max = Math.Max(max, StorageBufferBaseAlignment(member.Type, member.TypeModifier));
        return max;
    }

    /// <summary>
    /// Returns the ArrayStride required for <paramref name="elementType"/> when used as the element
    /// of a [RW]StructuredBuffer's runtime array. The value is the packed size (via
    /// <see cref="TypeSizeInBuffer"/>) rounded up to the type's std430 base alignment, so that the
    /// emitted SPIR-V validates under relaxed block layout.
    /// </summary>
    public static int StorageBufferArrayStride(SymbolType elementType, TypeModifier typeModifier = TypeModifier.None)
    {

View on GitHub (pinned to 96fad776d2)