stride3d/stride · error · InvalidOperationException
Execution mode primitive is missing for first parameter of g
Error message
Execution mode primitive is missing for first parameter of geometry shader
What it means
When wrapping a geometry-shader entry point, GenerateWrapper reads the input primitive type from the modifiers of the first parameter (point/line/triangle/adjacency forms) so it can emit the matching SPIR-V OpExecutionMode (InputPoints, InputLines, Triangles, ...). If that parameter has ParameterModifiers.None, there is no primitive topology to encode, and the generator throws this InvalidOperationException. In SDSL/HLSL convention the first GS parameter must carry the input-primitive modifier.
Solutions
- Add the input primitive modifier to the first geometry shader parameter: point, line, triangle, lineadj, or triangleadj
- Verify the SDSL source actually parses the modifier (check for typos like 'triangles' vs the recognized forms)
- Confirm the shader is genuinely a geometry shader — for other stages remove the GS-style parameter so this path is not taken
Example fix
// before void GSMain(StreamsInputStream inputs) // after void GSMain(triangle StreamsInputStream inputs)
Defensive patterns
Strategy: validation
Validate before calling
// Caller-side check before generating the wrapper bool hasPrimitiveModifier = entryPointFunctionType.ParameterTypes[0].Modifiers != ParameterModifiers.None;
Type guard
static bool HasInputPrimitive(ParameterType p) => p.Modifiers is
ParameterModifiers.Point or ParameterModifiers.Line or ParameterModifiers.LineAdjacency
or ParameterModifiers.Triangle or ParameterModifiers.TriangleAdjacency; Try / catch
try { wrapperGen.GenerateWrapper(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Execution mode primitive is missing"))
{
// report: GS entry point missing input primitive modifier on first parameter
} Prevention
- Always declare the GS input primitive modifier (point/line/lineadj/triangle/triangleadj) on the first parameter
- Copy signatures from working Stride GS examples rather than adapting vertex/fragment signatures
- Add a pre-validation pass over entry-point signatures before invoking wrapper generation
When it happens
Trigger: Declaring a geometry shader entry point whose first parameter (the input patch/stream parameter) is written without a primitive modifier (e.g. missing `triangle`, `point`, `lineadj`, etc.) so its ParameterModifiers is None when the wrapper generator runs.
Common situations: Hand-porting an HLSL geometry shader where the primitive-type modifier was dropped or renamed; copying a vertex/fragment-style signature into a GS; SDSL parse layers that silently strip unknown modifiers so the generator sees None.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Second parameter of geometry shader must be a GeometryStream
- Unsupported geometry input execution mode: {executionMode}
- Unsupported geometry stream output kind: {outputStreamType.K
- spirv_to_dxil_pipeline failed; SPIR-V dumped to {dumpPath} {
- Can't OpLoad with cbuffer
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/7fe48b9796762b77.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Generation/EntryPointWrapperGenerator.cs:354
buffer.Add(new OpFunctionCall(voidType, context.Bound++, patchConstantEntryPoint.IdRef, new(patchArguments)));
ProcessTessellationArguments(patchConstantEntryPoint, patchArguments);
buffer.Add(new OpBranch(mergeLabel));
// Merge block
buffer.Add(new OpLabel(mergeLabel));
}
}
else if (executionModel == ExecutionModel.Geometry)
{
// Change signature of main() to not use the output Stream anymore
// TODO: Check it's really the 2nd parameter
SpirvBuilder.FunctionRemoveParameter(context, buffer, entryPoint, 1);
// Extract and remove execution mode (line, point, triangleadj, etc.)
var executionMode = entryPointFunctionType.ParameterTypes[0].Modifiers;
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}"),
}, []));View on GitHub (pinned to 96fad776d2)