stride3d/stride · error · NotSupportedException

Unsupported output topology value

Error message

Unsupported output topology value '{((StringLiteral)anyAttribute.Parameters[0]).Value}'

What it means

The [outputtopology(...)] attribute on a tessellation-evaluation stage accepts only 'triangle_cw' or 'triangle_ccw', mapping to SPIR-V VertexOrderCw/VertexOrderCcw. Any other value has no execution-mode mapping and throws NotSupportedException.

Solutions

  1. Use triangle_cw or triangle_ccw exactly (lowercase).
  2. Check whether the 'line' case is handled by a preceding branch and route line outputs there.
  3. Fix casing/typos in the attribute string.

Example fix

// before
[outputtopology("triangle")]
// after
[outputtopology("triangle_cw")]
Defensive patterns

Strategy: validation

Validate before calling

var topologies = new HashSet<string> { "triangle_cw", "triangle_ccw" };
if (!topologies.Contains(topologyValue)) throw new ArgumentException($"Unsupported output topology '{topologyValue}'");

Try / catch

try { method.Compile(); }
catch (NotSupportedException ex) when (ex.Message.Contains("Unsupported output topology"))
{
    // use triangle_cw or triangle_ccw, or a branch that handles line
}

Prevention

When it happens

Trigger: A tessellation-evaluation method annotated with e.g. [outputtopology(point)] or a misspelled value.

Common situations: Porting D3D tessellation 'outputtopology' values such as 'line' or 'point' that are valid in HLSL pipelines but not mapped here (note 'line' may be handled by a separate branch above this switch).

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/ShaderElements.MethodOrMember.cs:604

                            "fractional_odd" => Specification.ExecutionMode.SpacingFractionalOdd,
                            "fractional_even" => Specification.ExecutionMode.SpacingFractionalEven,
                            "integer" => Specification.ExecutionMode.SpacingEqual,
                            "pow2" => throw new NotSupportedException("partitioning pow2 is not supported in SPIR-V"),
                            _ => throw new NotSupportedException($"Unsupported partitioning value '{((StringLiteral)anyAttribute.Parameters[0]).Value}'"),
                        }, []));
                    }
                    else if (anyAttribute.Name == "outputtopology")
                    {
                        var value = ((StringLiteral)anyAttribute.Parameters[0]).Value;
                        if (value != "line")
                        {
                            // VertexOrderCw/Ccw are only valid on TessellationEvaluation per
                            // SPIR-V spec; route to DSMain (same reason as partitioning above).
                            context.Add(new OpExecutionMode(GetTessEvaluationFunctionId(table, function.Id), ((StringLiteral)anyAttribute.Parameters[0]).Value switch
                            {
                                "triangle_cw" => Specification.ExecutionMode.VertexOrderCw,
                                "triangle_ccw" => Specification.ExecutionMode.VertexOrderCcw,
                                _ => throw new NotSupportedException($"Unsupported output topology value '{((StringLiteral)anyAttribute.Parameters[0]).Value}'"),
                            }, []));
                        }
                    }
                    else
                    {
                        throw new NotImplementedException($"Can't parse method attribute {anyAttribute} on method {Name}");
                    }
                }
            }
        }

        if (Type is not FunctionType ftype)
            throw new InvalidOperationException();

        table.Push(SymbolFrame!);
        builder.BeginFunction(context, function);

        var functionInfo = new OpFunctionMetadataSDSL(Specification.FunctionFlagsMask.None, 0);

View on GitHub (pinned to 96fad776d2)