{"record":{"id":"6b28ec3a7ef67449","repo":"stride3d/stride","slug":"unsupported-type-for-storage-buffer-alignment-type","errorCode":null,"errorMessage":"Unsupported type for storage buffer alignment: {type}","messagePattern":"Unsupported type for storage buffer alignment: (.+?)","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.CBuffer.cs","lineNumber":162,"sourceCode":"    /// Computes the std430 base alignment of a type as required by Vulkan's storage buffer layout\n    /// (vec2 → 2×scalar, vec3/vec4 → 4×scalar, struct → max member alignment). Used to round the\n    /// ArrayStride of a [RW]StructuredBuffer element type so the SPIR-V validates under relaxed\n    /// block layout. Relaxed rules allow scalar-aligned offsets for vector members, but an array\n    /// of structs still needs its stride aligned to the struct's base alignment.\n    /// </summary>\n    public static int StorageBufferBaseAlignment(SymbolType type, TypeModifier typeModifier = TypeModifier.None) => type switch\n    {\n        ScalarType { Type: Scalar.Int or Scalar.UInt or Scalar.Float or Scalar.Boolean or Scalar.Half } => 4,\n        ScalarType { Type: Scalar.Int64 or Scalar.UInt64 or Scalar.Double } => 8,\n        VectorType { Size: 2, BaseType: var bt } => 2 * StorageBufferBaseAlignment(bt),\n        VectorType { Size: 3 or 4, BaseType: var bt } => 4 * StorageBufferBaseAlignment(bt),\n        MatrixType m when typeModifier == TypeModifier.RowMajor\n            => StorageBufferBaseAlignment(new VectorType(m.BaseType, m.Columns)),\n        MatrixType m\n            => StorageBufferBaseAlignment(new VectorType(m.BaseType, m.Rows)),\n        ArrayType a => StorageBufferBaseAlignment(a.BaseType, typeModifier),\n        StructuredType s => MaxMemberAlignment(s),\n        _ => throw new NotSupportedException($\"Unsupported type for storage buffer alignment: {type}\"),\n    };\n\n    static int MaxMemberAlignment(StructuredType s)\n    {\n        var max = 4;\n        foreach (var member in s.Members)\n            max = Math.Max(max, StorageBufferBaseAlignment(member.Type, member.TypeModifier));\n        return max;\n    }\n\n    /// <summary>\n    /// Returns the ArrayStride required for <paramref name=\"elementType\"/> when used as the element\n    /// of a [RW]StructuredBuffer's runtime array. The value is the packed size (via\n    /// <see cref=\"TypeSizeInBuffer\"/>) rounded up to the type's std430 base alignment, so that the\n    /// emitted SPIR-V validates under relaxed block layout.\n    /// </summary>\n    public static int StorageBufferArrayStride(SymbolType elementType, TypeModifier typeModifier = TypeModifier.None)\n    {","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.CBuffer.cs#L144-L180","documentation":"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').","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the type symbol fully resolves to Scalar/Vector/Matrix/Array/StructuredType before storage-buffer layout","Implement a case for the unsupported type kind in Builder.CBuffer.cs:162 (e.g. treat bare scalars as (size, size))","Log/inspect the type symbol to find why type resolution produced an unhandled kind"],"exampleFix":"// before\n_ => throw new NotSupportedException($\"Unsupported type for storage buffer alignment: {type}\"),\n// after\nScalarType sc => (SizeOf(sc), SizeOf(sc)),\n_ => throw new NotSupportedException($\"Unsupported type for storage buffer alignment: {type}\")","handlingStrategy":"type-guard","validationCode":"bool HasStorageBufferAlignment(TypeSymbol t) => t is ScalarType or VectorType or MatrixType or ArrayType or StructuredType;\nif (!HasStorageBufferAlignment(type)) throw new NotSupportedException($\"Type {type} has no std430 alignment\");","typeGuard":"static bool IsStd430Alignable(TypeSymbol t) => t is ScalarType or VectorType or MatrixType or ArrayType or StructuredType;","tryCatchPattern":"try { alignment = StorageBufferBaseAlignment(type, modifier); }\ncatch (NotSupportedException ex) { Log($\"Unresolvable type for std430: {ex.Message}\"); alignment = 16; /* conservative fallback */ }","preventionTips":["Resolve all type symbols fully before storage-buffer layout (no error/placeholder types)","Extend the switch whenever new IR type kinds are added","Run storage-buffer layout only on modules that passed type validation","Test std430 alignment on shaders with nested arrays/structs/matrices"],"tags":["spirv","layout","std430","unsupported-type"],"backgroundTag":"unsupported-operation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}