stride3d/stride · error · NotSupportedException
Unsupported geometry input execution mode
Error message
Unsupported geometry input execution mode: {executionMode} What it means
After reading the input primitive modifier from the first GS parameter, the generator maps it to a SPIR-V input execution mode via a switch over ParameterModifiers: Point, Line, LineAdjacency, Triangle, TriangleAdjacency. Any other modifier value (including compound or unexpected modifier flags) hits the default arm and throws this NotSupportedException. It guards against emitting an invalid OpExecutionMode.
Solutions
- Use exactly one recognized primitive modifier on the GS input parameter: point, line, lineadj, triangle, or triangleadj
- Remove any extra modifier flags accidentally combined onto the parameter (exact switch matching means In|Point will not match Point)
- If a new modifier kind is legitimate, extend the switch in EntryPointWrapperGenerator.cs to map it to the corresponding SPIR-V ExecutionMode
Example fix
// before (combined modifiers fail the exact match) void GSMain(in triangle StreamsInputStream inputs, TriangleStream<GSOutput> outStream) // after void GSMain(triangle StreamsInputStream inputs, TriangleStream<GSOutput> outStream)
Defensive patterns
Strategy: type-guard
Validate before calling
var m = entryPointFunctionType.ParameterTypes[0].Modifiers;
bool ok = m is ParameterModifiers.Point or ParameterModifiers.Line or ParameterModifiers.LineAdjacency
or ParameterModifiers.Triangle or ParameterModifiers.TriangleAdjacency; Type guard
static bool IsExactPrimitiveModifier(ParameterModifiers m) => m is
ParameterModifiers.Point or ParameterModifiers.Line or ParameterModifiers.LineAdjacency
or ParameterModifiers.Triangle or ParameterModifiers.TriangleAdjacency; // exact, no combined flags Try / catch
try { wrapperGen.GenerateWrapper(...); }
catch (NotSupportedException ex) when (ex.Message.Contains("Unsupported geometry input execution mode"))
{
// report: unrecognized/combined modifier on GS input parameter
} Prevention
- Use exactly one primitive modifier; avoid OR-combining flags like In|Triangle
- Keep modifier enums in sync across parser and generator versions
- Exact-match guard the modifier before generation
When it happens
Trigger: The first parameter of a geometry shader carries a modifier that is non-None (passing the earlier check) but not one of the five recognized primitive modifiers — e.g. a combined/flag value, an 'out' modifier on the input parameter, or a custom modifier added in a newer SDSL version that this switch doesn't handle.
Common situations: Custom SDSL dialects adding new primitive modifiers; modifier flags accidentally OR-combined (e.g. In | Point) so the exact-match switch arms fail; version skew between shader parser and generator where a modifier enum was extended.
Related errors
- Unsupported geometry stream output kind
- Unsupported StreamsKindSDSL for output parameter
- Execution mode primitive is missing for first parameter of…
- Second parameter of geometry shader must be a…
- spirv_to_dxil_pipeline failed; SPIR-V dumped to
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/dd051b02e07b7087.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Generation/EntryPointWrapperGenerator.cs:371
if (executionMode == ParameterModifiers.None)
throw new InvalidOperationException("Execution mode primitive is missing for first parameter of geometry shader");
// Extract output topology from the GeometryStreamType parameter before removing it
var outputStreamType = ((PointerType)entryPointFunctionType.ParameterTypes[1].Type).BaseType as GeometryStreamType
?? throw new InvalidOperationException("Second parameter of geometry shader must be a GeometryStreamType");
entryPointFunctionType.ParameterTypes[0] = entryPointFunctionType.ParameterTypes[0] with { Modifiers = ParameterModifiers.None };
entryPointFunctionType.ParameterTypes.RemoveAt(1);
context.ReplaceType(entryPointFunctionType, entryPointTypeId);
context.Add(new OpExecutionMode(entryPoint.IdRef, executionMode switch
{
ParameterModifiers.Point => ExecutionMode.InputPoints,
ParameterModifiers.Line => ExecutionMode.InputLines,
ParameterModifiers.LineAdjacency => ExecutionMode.InputLinesAdjacency,
ParameterModifiers.Triangle => ExecutionMode.Triangles,
ParameterModifiers.TriangleAdjacency => ExecutionMode.InputTrianglesAdjacency,
_ => throw new NotSupportedException($"Unsupported geometry input execution mode: {executionMode}"),
}, []));
context.Add(new OpExecutionMode(entryPoint.IdRef, outputStreamType.Kind switch
{
GeometryStreamOutputKindSDSL.Point => ExecutionMode.OutputPoints,
GeometryStreamOutputKindSDSL.Line => ExecutionMode.OutputLineStrip,
GeometryStreamOutputKindSDSL.Triangle => ExecutionMode.OutputTriangleStrip,
_ => throw new NotSupportedException($"Unsupported geometry stream output kind: {outputStreamType.Kind}"),
}, []));
arguments[0] = inputsVariable;
// Call main(inputs) without 2nd argument
buffer.Add(new OpFunctionCall(voidType, context.Bound++, entryPoint.IdRef, [arguments[0], .. arguments[2..]]));
}
}
else
{
// We assume a void returning function and Input/Output is all handled with streamsView on GitHub (pinned to 96fad776d2)