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

  1. Make the matrix operand types consistent (same generator pattern) at the call site
  2. Annotate the matrix types with explicit dimensions instead of relying on __any generators
  3. 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

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


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)