{"record":{"id":"a5b1d1295e8b8def","repo":"stride3d/stride","slug":"unsupported-type-for-buffer-layout-symbol","errorCode":null,"errorMessage":"Unsupported type for buffer layout: {symbol}","messagePattern":"Unsupported type for buffer layout: (.+?)","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.CBuffer.cs","lineNumber":56,"sourceCode":"            VectorType v when alignmentRules == AlignmentRules.StructuredBuffer\n                => (TypeSizeInBuffer(v.BaseType, typeModifier, alignmentRules).Size * v.Size,\n                    TypeSizeInBuffer(v.BaseType, typeModifier, alignmentRules).Alignment * (v.Size == 2 ? 2 : 4)),\n            VectorType v => MultiplySize(TypeSizeInBuffer(v.BaseType, typeModifier, alignmentRules), v.Size),\n            // Note: this is HLSL-style so Rows/Columns meaning is swapped\n            // Note: HLSL default is ColumnMajor\n            // StructuredBuffer uses std430 strict matrix layout: each column (ColumnMajor) or row\n            // (RowMajor) is padded to its std430 base alignment, matching how the Vulkan validator\n            // expects matrix layout under relaxed block layout.\n            MatrixType m when alignmentRules == AlignmentRules.StructuredBuffer\n                => StructuredBufferMatrixSize(m, typeModifier),\n            MatrixType m when typeModifier == TypeModifier.ColumnMajor || typeModifier == TypeModifier.None\n                => MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), (4 * (m.Rows - 1)) + m.Columns),\n            MatrixType m when typeModifier == TypeModifier.RowMajor\n                => MultiplySize(TypeSizeInBuffer(m.BaseType, typeModifier, alignmentRules), (4 * (m.Columns - 1)) + m.Rows),\n            // Round up to 16 bytes (size of float4)\n            ArrayType a => Array(TypeSizeInBuffer(a.BaseType, typeModifier, alignmentRules), a.Size, alignmentRules),\n            // TODO: StructureType\n            _ => throw new NotSupportedException($\"Unsupported type for buffer layout: {symbol}\"),\n        };\n    }\n\n    /// <summary>\n    /// Computes std430 size and alignment for a matrix in a StorageBuffer.\n    /// ColumnMajor: matrix is an array of <c>Columns</c> column-vectors of dimension <c>Rows</c>.\n    /// RowMajor: matrix is an array of <c>Rows</c> row-vectors of dimension <c>Columns</c>.\n    /// Each element vector is laid out at its std430 base-alignment stride, so non-square matrices\n    /// get trailing padding on the short axis.\n    /// </summary>\n    private static (int Size, int Alignment) StructuredBufferMatrixSize(MatrixType m, TypeModifier typeModifier)\n    {\n        var (vecDim, vecCount) = typeModifier == TypeModifier.RowMajor\n            ? (m.Columns, m.Rows)\n            : (m.Rows, m.Columns);\n        var scalarSize = TypeSizeInBuffer(m.BaseType, typeModifier, AlignmentRules.StructuredBuffer).Size;\n        var vecSize = scalarSize * vecDim;\n        var vecAlignment = StorageBufferBaseAlignment(new VectorType(m.BaseType, vecDim));","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.CBuffer.cs#L38-L74","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nStructuredType s => throw new NotSupportedException(...),\n// after\nStructuredType s => StructSizeInBuffer(s, alignmentRules).Size, // implement struct layout","handlingStrategy":"type-guard","validationCode":"bool IsLayoutSupported(TypeSymbol t) => t is ScalarType or VectorType or MatrixType or ArrayType; // StructuredType unsupported for CBuffer layout\nif (!IsLayoutSupported(symbol)) throw new NotSupportedException($\"Type {symbol} cannot be laid out in a CBuffer yet\");","typeGuard":"static bool IsBufferLayoutable(TypeSymbol t) => t is not StructuredType and (ScalarType or VectorType or MatrixType or ArrayType);","tryCatchPattern":"try { size = TypeSizeInBuffer(symbol, modifier, rules); }\ncatch (NotSupportedException ex) { Log(ex.Message); size = symbol switch { StructuredType s => FlattenAndMeasure(s, rules), _ => 0 }; }","preventionTips":["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"],"tags":["spirv","layout","unsupported-type","cbuffer"],"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"}