stride3d/stride · error · NotSupportedException
Unsupported StreamsKindSDSL for output parameter
Error message
Unsupported StreamsKindSDSL for output parameter: {t.Kind} What it means
When generating the SPIR-V wrapper, entry-point parameters that are 'out' parameters (like 'out HS_OUTPUT output' or 'out HS_CONSTANTS constants') are mapped to a stream layout member via their StreamsKindSDSL kind. Only Output and Constants kinds are supported; any other kind in an output parameter position throws NotSupportedException.
Solutions
- Change the out parameter to use the proper output or constants structure type so its kind resolves to StreamsKindSDSL.Output or StreamsKindSDSL.Constants.
- Remove invalid out parameters that are neither the shader output nor the patch-constants struct from the entry-point signature.
- If a new kind legitimately needs support, add it to the switch in EntryPointWrapperGenerator.cs:237 mapping it to the correct struct type.
- Verify the SDSL parser's kind classification for your parameter type (debug why t.Kind got the unexpected value) before touching the signature.
Example fix
// before void HSMain(InputPatch<VS_OUTPUT, 3> input, out Streams stream, out HS_CONSTANTS constants) // Streams kind unsupported for out // after void HSMain(InputPatch<VS_OUTPUT, 3> input, out HS_OUTPUT output, out HS_CONSTANTS constants)
Defensive patterns
Strategy: type-guard
Validate before calling
// Only Output and Constants kinds are valid as out parameters
static readonly HashSet<StreamsKindSDSL> AllowedOutKinds = new() { StreamsKindSDSL.Output, StreamsKindSDSL.Constants };
bool outKindsValid = entryPoint.Parameters.Where(p => p.IsOut).All(p => AllowedOutKinds.Contains(p.TypeKind)); Type guard
static bool IsSupportedOutKind(StreamsKindSDSL kind) =>
kind == StreamsKindSDSL.Output || kind == StreamsKindSDSL.Constants; Try / catch
try
{
var wrapper = EntryPointWrapperGenerator.GenerateWrapper(...);
}
catch (NotSupportedException ex) when (ex.Message.StartsWith("Unsupported StreamsKindSDSL"))
{
log.Error($"Entry point uses an out parameter with unsupported stream kind: {ex.Message}");
throw new ShaderCompilationException("Unsupported out-parameter kind in entry point signature", ex);
} Prevention
- Only pass the shader output struct or patch-constants struct as out parameters; never a Streams composite.
- Validate entry-point signatures against allowed out kinds before wrapper generation.
- Keep a whitelist mapping signature roles to StreamsKindSDSL values in your shader tooling.
- When adding new StreamsKindSDSL members, extend the wrapper generator's switch and add a regression test in the same change.
When it happens
Trigger: GenerateWrapper encounters an out parameter whose parsed SDSL type kind is neither StreamsKindSDSL.Output nor StreamsKindSDSL.Constants — e.g. an out parameter typed with a Streams kind, a stream composite, or an unrecognized custom kind in a hull/domain shader signature.
Common situations: Custom SDSL stream types passed as out parameters; mistyped signatures where a Streams struct was accidentally used as an out param; API changes in StreamsKindSDSL introducing kinds the wrapper generator does not yet handle; generator bugs in kind classification for hull-shader parameter structs.
Related errors
- Unsupported geometry input execution mode
- Unsupported geometry stream output kind
- spirv_to_dxil_pipeline failed; SPIR-V dumped to
- Can't OpLoad with cbuffer
- Unsupported symbol type
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/ac25d465152d9d94.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Generation/EntryPointWrapperGenerator.cs:237
arguments[i] = constantVariable;
// Copy back values from semantic/builtin variables to Constants struct
foreach (var stream in streamLayout.PatchInputStreams)
{
var inputPtr = buffer.Add(new OpAccessChain(context.GetOrRegister(new PointerType(stream.Info.Type, Specification.StorageClass.Function)), context.Bound++, constantVariable, [context.CompileConstant(stream.Info.StreamStructFieldIndex).Id])).ResultId;
var inputResult = buffer.Add(new OpLoad(context.GetOrRegister(stream.Info.Type), context.Bound++, stream.Id, null, [])).ResultId;
inputResult = BuiltinProcessor.ConvertInterfaceVariable(buffer, context, stream.InterfaceType, stream.Info.Type, inputResult);
buffer.Add(new OpStore(inputPtr, inputResult, null, []));
}
break;
}
case StreamsType t when t.Kind is StreamsKindSDSL.Output or StreamsKindSDSL.Constants && parameterModifiers == ParameterModifiers.Out:
{
// Parameter is "out HS_OUTPUT output" or "out HS_CONSTANTS constants"
var structType = t.Kind switch
{
StreamsKindSDSL.Output => streamLayout.OutputType,
StreamsKindSDSL.Constants => streamLayout.ConstantsType!,
_ => throw new NotSupportedException($"Unsupported StreamsKindSDSL for output parameter: {t.Kind}"),
};
var outVariable = buffer.Insert(variableInsertIndex++, new OpVariable(context.GetOrRegister(new PointerType(structType, Specification.StorageClass.Function)), context.Bound++, Specification.StorageClass.Function, null)).ResultId;
arguments[i] = outVariable;
break;
}
case var t when arguments[i] == 0:
throw new NotImplementedException($"Can't process argument {i + 1} of type {parameterType} in method {entryPoint.Id.Name}");
}
}
}
void ProcessTessellationArguments(Symbol function, Span<int> arguments)
{
var functionType = (FunctionType)function.Type;
for (int i = 0; i < functionType.ParameterTypes.Count; i++)
{
var parameterType = ((PointerType)functionType.ParameterTypes[i].Type).BaseType;
var parameterModifiers = functionType.ParameterTypes[i].Modifiers;View on GitHub (pinned to 96fad776d2)