stride3d/stride · error · NotImplementedException

Assign back to matrix swizzle is not implemented yet

Error message

Assign back to matrix swizzle is not implemented yet

What it means

During SPIR-V codegen of an assignment, the compiler pattern-matches the assignment target. When the target is a matrix swizzle (e.g. m._m00_m11 = v) it has no implementation, so it throws NotImplementedException — matrix swizzle write-back is simply not yet supported by this SDSL compiler stage.

Solutions

  1. Rewrite the shader to assign matrix rows/elements individually instead of via swizzle
  2. Use a temporary: compute the swizzled result into locals, then assign each element
  3. Express the operation with matrix constructors or index assignment
  4. Implement the missing codegen case in Expression.cs if you control the compiler

Example fix

// before
m._m00_m11 = vec2(a, b);
// after
m[0][0] = a;
m[1][1] = b;
Defensive patterns

Strategy: fallback

Validate before calling

static bool AssignableViaSwizzle(object target) => target is VectorType or ScalarType or PointerType;

Type guard

bool IsMatrixSwizzleTarget(Identifier id, MatrixType t) => id.IsMatrixSwizzle(t, out _);

Try / catch

try { EmitAssignment(target, value); } catch (NotImplementedException e) when (e.Message.Contains("matrix swizzle")) { EmitElementWiseAssignment(target, value); }

Prevention

When it happens

Trigger: Assigning to a matrix swizzle lvalue (pattern: target is MatrixType or pointer-to-matrix with an identifier that IsMatrixSwizzle) inside an SDSL shader being translated to SPIR-V.

Common situations: Writing GLSL-style code like mat._11_22 = ... ported from other shading languages; auto-translated shaders that assume swizzle assignment works for matrices.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/53d7ee158502dc88. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/Expression.cs:792

                        var bufferValue = builder.Convert(context, rvalue, resultType);
                        builder.Insert(new OpImageWrite(buffer.Id, location.Id, bufferValue.Id, null, []));
                        // We stop there
                        return;
                    }
                // ImageWrite
                case (PointerType { BaseType: TextureType textureType }, IndexerExpression indexer):
                    {
                        var resultType = textureType.ReturnType;
                        var image = builder.AsValue(context, lvalueBase);

                        var imageCoordValue = ConvertTexCoord(context, builder, textureType, indexer.Index.CompileAsValue(table, compiler), ScalarType.Int);
                        var texelValue = builder.Convert(context, rvalue, resultType);
                        builder.Insert(new OpImageWrite(image.Id, imageCoordValue.Id, texelValue.Id, null, []));
                        // We stop there
                        return;
                    }
                case (PointerType { BaseType: MatrixType } or MatrixType, Identifier { Name: var swizzle } id) when id.IsMatrixSwizzle((MatrixType)currentValueType.GetValueType(), out var swizzles):
                    throw new NotImplementedException("Assign back to matrix swizzle is not implemented yet");
                case (PointerType { BaseType: VectorType or ScalarType } or VectorType or ScalarType, Identifier { Name: var swizzle } id) when id.IsVectorSwizzle():
                    // Swizzle: we transform the value to assign accordingly

                    // We load the original value (if pointer)
                    var lvalueType = currentValueType;
                    if (lvalueType is PointerType p)
                    {
                        lvalueBase = new(builder.InsertData(new OpLoad(context.GetOrRegister(p.BaseType), context.Bound++, lvalueBase.Id, null, [])));
                        lvalueType = p.BaseType;
                    }

                    // Shuffle with new data
                    switch (lvalueType)
                    {
                        case VectorType v:
                            var shuffleIndices = shuffleBuffer[..v.Size];
                            // Default: lvalue
                            for (int j = 0; j < v.Size; ++j)

View on GitHub (pinned to 96fad776d2)