stride3d/stride · error · InvalidOperationException
Multiple matrix with different generators
Error message
Multiple matrix with different generators
What it means
When a matrix-typed parameter is generated from a size generator (e.g. __any row/column patterns used by mul()), the expander remembers one generator in autoMatrixLoop so it can lower the call into per-vector calls. If a second, different generator appears for another parameter of the same intrinsic, the expansion would be ambiguous, so it throws.
Solutions
- Make the matrix operand types consistent (same generator pattern) at the call site
- Annotate the matrix types with explicit dimensions instead of relying on __any generators
- Verify the intrinsic's declared matrix type match() chain so all operands derive from the same generator
Example fix
// before float2x3 r = mul(anyMatrix, float3x2(...)); // conflicting generators // after float3x3 r = mul(float3x3(a), float3x3(b)); // consistent types
Defensive patterns
Strategy: validation
Validate before calling
// Verify all matrix operands share the same size generator before expansion
var gens = paramTypes.OfType<MatrixType>()
.Select(m => m.Size1.Generator).Where(g => g != null).Distinct().ToList();
if (gens.Count > 1) throw new InvalidOperationException("Operands use different matrix generators"); Type guard
bool SameGenerator(MatrixType a, MatrixType b) => Equals(a.Size1.Generator, b.Size1.Generator);
Try / catch
try { Expand(intrinsic, args); }
catch (InvalidOperationException ex) when (ex.Message == "Multiple matrix with different generators") { /* report mismatched operand types */ } Prevention
- Use explicitly sized matrix types in calls to generator-based intrinsics like mul
- Keep operand matrix dimensions consistent within one intrinsic call
- Avoid mixing __any-generated matrices with concrete dimensions
When it happens
Trigger: An intrinsic (typically mul or similar) whose matrix parameters resolve to different size generators (e.g. one __anyVM and one __anyVC pattern, or one anonymous and one named) in a single call.
Common situations: Multiplying matrices with incompatible wildcard size patterns; mixing a fully-specified matrix with a generator-based one in a way the expander cannot loop over uniformly.
Related errors
- Can't resolve thisType base type for
- [Color] attribute can only be applied on float3/float4…
- Composition variable
- Could not find cbuffer member link info for
- $funcT not supported for
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/b32d990ca93574cc.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/IntrinsicTemplateExpander.cs:349
firstIteration = false;
SizePermutationGenerator? autoMatrixLoop = null;
int autoMatrixLoopSize = 0;
// Generate real types using sizes
for (var index = 0; index < intrinsicDefinition.Parameters.Length + 1; index++)
{
ref var resolvedBaseType = ref parameterTypeHelper[index];
if (resolvedBaseType.Size1.Value > 1 && resolvedBaseType.Size2.Value > 1)
{
if (resolvedBaseType.Size1.Generator is { } gen1 && (gen1.Name == null || gen1.Name.StartsWith("__any")))
{
// If matrix types are generated from a <> size generator (without a specific row/column pattern like in mul()),
// we can automatically convert a call to multiple calls on each inner vector.
// So we try to remember this info here
if (autoMatrixLoop != null && autoMatrixLoop != gen1)
throw new InvalidOperationException("Multiple matrix with different generators");
autoMatrixLoop = gen1;
autoMatrixLoopSize = resolvedBaseType.Size1.Value;
}
parameterTypes[index] = new MatrixType((ScalarType)resolvedBaseType.BaseType, resolvedBaseType.Size2.Value, resolvedBaseType.Size1.Value);
}
// Note: since in HLSL float4x1 and float1x4 maps to SPIR-V float4, we will have duplicates (but not a big deal)
else if (resolvedBaseType.Size1.Value > 1 || resolvedBaseType.Size2.Value > 1)
{
parameterTypes[index] = new VectorType((ScalarType)resolvedBaseType.BaseType, Math.Max(resolvedBaseType.Size1.Value, resolvedBaseType.Size2.Value));
}
else
{
parameterTypes[index] = resolvedBaseType.BaseType;
}
}
// Note: we remove auto matrix loop if result type is not either void or matrix of the desired size
if (autoMatrixLoop != null)View on GitHub (pinned to 96fad776d2)