stride3d/stride · error · NotSupportedException
Unsupported mul operand types
Error message
Unsupported mul operand types: {context.ReverseTypes[a.TypeId]} and {context.ReverseTypes[b.TypeId]} What it means
CompileMul lowers the SDSL mul() intrinsic (HLSL-style matrix multiply) to SPIR-V OpMatrixTimesMatrix/OpVectorTimesMatrix etc. It pattern-matches on the operand type pair; if the combination (e.g. matrix-matrix with mismatched inner dimensions, or types that are neither vectors nor matrices) has no matching case, it throws NotSupportedException listing both resolved operand types.
Solutions
- Verify the operand shapes: for mul(M1, M2) the inner dimensions must match (columns of M1 vs rows of M2 in HLSL terms).
- Use explicit casts so both operands are the same base type (e.g. float matrices).
- Multiply by a scalar with the * operator, not mul().
- If a valid SPIR-V mapping exists that is missing, add a case to the switch in CompileMul (e.g. OpVectorTimesScalar).
Example fix
// before (SDSL) float2x4 a; float4x3 b; float3 v; float3 r = mul(mul(a, b), v); // ok only if dims align float1x1 s = mul(a, 2); // throws: unsupported operand types // after float2x3 r = mul(a, b); float2x4 s2 = a * 2;
Defensive patterns
Strategy: validation
Validate before calling
bool IsValidMul(TypeBase a, TypeBase b) =>
(a, b) switch {
(MatrixType m1, MatrixType m2) => m1.Rows == m2.Columns,
(VectorType, MatrixType) => true,
(MatrixType, VectorType) => true,
_ => false }; Type guard
bool IsMatrixOrVector(TypeBase t) => t is MatrixType or VectorType;
Try / catch
try { result = intrinsics.CompileMul(table, ctx, builder, fnType, a, b); }
catch (NotSupportedException ex) { /* report operand types to shader diagnostics */ } Prevention
- Match HLSL mul() dimension rules (inner dims must agree)
- Use * for scalar multiplication instead of mul
- Keep matrix base types identical (all float or all int)
When it happens
Trigger: Calling mul(a, b) where a and b are not a valid (matrix,matrix), (vector,matrix), (matrix,vector) pair, or where the inner dimensions do not match (type1.Rows != type2.Columns for matrix-matrix).
Common situations: Transposed dimension assumptions from HLSL row/column conventions; multiplying a matrix by a scalar with mul instead of *; dimension typo in a floatNxM declaration; mixing float and int matrices.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Unsupported element type for clamp
- Unsupported element type for saturate
- Unsupported element type for sign
- Unexpected type for f16tof32
- Unexpected type for f32tof16
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/f10df13caf16e18d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/IntrinsicImplementations.cs:203
// Version on https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-mul
// Note: SPIR-V and HLSL have opposite meaning for Rows/Columns and multiplication order need to be swapped
var result = (context.ReverseTypes[a.TypeId], context.ReverseTypes[b.TypeId]) switch
{
(ScalarType type1, ScalarType type2) => builder.InsertData(new OpFMul(a.TypeId, context.Bound++, a.Id, b.Id)),
(ScalarType type1, VectorType type2) => builder.InsertData(new OpVectorTimesScalar(b.TypeId, context.Bound++, b.Id, a.Id)),
(ScalarType type1, MatrixType type2) => builder.InsertData(new OpMatrixTimesScalar(b.TypeId, context.Bound++, b.Id, a.Id)),
(VectorType type1, ScalarType type2) => builder.InsertData(new OpVectorTimesScalar(a.TypeId, context.Bound++, a.Id, b.Id)),
(VectorType type1, VectorType type2) when type1.Size == type2.Size => builder.InsertData(new OpDot(a.TypeId, context.Bound++, a.Id, b.Id)),
(VectorType type1, MatrixType type2) when type1.Size == type2.Columns => builder.InsertData(new OpMatrixTimesVector(context.GetOrRegister(new VectorType(type1.BaseType, type2.Rows)), context.Bound++, b.Id, a.Id)),
(MatrixType type1, ScalarType type2) => builder.InsertData(new OpMatrixTimesScalar(a.TypeId, context.Bound++, a.Id, b.Id)),
(MatrixType type1, VectorType type2) when type1.Rows == type2.Size => builder.InsertData(new OpVectorTimesMatrix(context.GetOrRegister(new VectorType(type1.BaseType, type1.Columns)), context.Bound++, b.Id, a.Id)),
// This is HLSL-style so Rows/Columns meaning is swapped
//float2x4 = OpTypeMatrix vec4 x2 = MatrixType(Rows: 4, Columns: 2)
//float4x3 = OpTypeMatrix vec3 x4 = MatrixType(Rows: 3, Columns: 4)
//float2x3 = OpTypeMatrix vec3 x2 = MatrixType(Rows: 3, Columns: 2)
// mul(float2x4,float4x3) => float2x3
(MatrixType type1, MatrixType type2) when type1.Rows == type2.Columns => builder.InsertData(new OpMatrixTimesMatrix(context.GetOrRegister(new MatrixType(type1.BaseType, type2.Rows, type1.Columns)), context.Bound++, b.Id, a.Id)),
_ => throw new NotSupportedException($"Unsupported mul operand types: {context.ReverseTypes[a.TypeId]} and {context.ReverseTypes[b.TypeId]}"),
};
return new SpirvValue(result);
}
public override SpirvValue CompileReflect(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue i, SpirvValue n, TextLocation location = default)
{
var instruction = builder.Insert(new GLSLReflect(i.TypeId, context.Bound++, context.GetGLSL(), i.Id, n.Id));
return new(instruction.ResultId, instruction.ResultType);
}
public override SpirvValue CompileRefract(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue i, SpirvValue n, SpirvValue ri, TextLocation location = default)
{
var instruction = builder.Insert(new GLSLRefract(i.TypeId, context.Bound++, context.GetGLSL(), i.Id, n.Id, ri.Id));
return new(instruction.ResultId, instruction.ResultType);
}
public override SpirvValue CompileFaceforward(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue N, SpirvValue I, SpirvValue Ng, TextLocation location = default)
{View on GitHub (pinned to 96fad776d2)