stride3d/stride · error · NotSupportedException

Unsupported element type for max

Error message

Unsupported element type for max: {context.ReverseTypes[a.TypeId].GetElementType()}

What it means

CompileMax maps max() to GLSL.FMax (float/double), GLSL.UMax (uint), or GLSL.SMax (int). Any other element type (bool, half, custom scalars) falls to the default arm and throws NotSupportedException at IntrinsicImplementations.cs:125.

Solutions

  1. Use int/uint/float/double operands (scalars or vectors) with max().
  2. Cast unsupported types to a supported numeric type before calling max().
  3. Add a corresponding GLSL extended-op arm in CompileMax if the element type should be supported.

Example fix

// before
half2 h = max(h1, h2);      // if half is unsupported
// after
float2 h = max((float2)h1, (float2)h2);
Defensive patterns

Strategy: type-guard

Validate before calling

// max supports float/double/uint/int element types only
if (aType.GetElementType() is not ScalarType { Type: Scalar.Float or Scalar.Double or Scalar.Int or Scalar.UInt })
    throw new ShaderCompileHint("max requires numeric scalar element type");

Type guard

static bool IsMaxSupported(BaseType t) => t.GetElementType() is ScalarType s && s.Type is Scalar.Float or Scalar.Double or Scalar.Int or Scalar.UInt;

Try / catch

try { result = intrinsic.CompileMax(table, context, builder, functionType, a, b); }
catch (NotSupportedException ex) when (ex.Message.Contains("element type for max"))
{ diagnostics.Report(location, ex.Message); }

Prevention

When it happens

Trigger: Calling max(a, b) where a's element scalar type is not Float, Double, UInt, or Int in the SPIR-V type table.

Common situations: Taking max of boolean or half-precision values not yet mapped in the SPIR-V backend, or after adding new scalar types without updating the intrinsic dispatch.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/IntrinsicImplementations.cs:125

    {
        var instruction = context.ReverseTypes[a.TypeId].GetElementType() switch
        {
            ScalarType { Type: Scalar.Float or Scalar.Double } => builder.InsertData(new GLSLFMin(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), a.Id, b.Id)),
            ScalarType { Type: Scalar.UInt } => builder.InsertData(new GLSLUMin(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), a.Id, b.Id)),
            ScalarType { Type: Scalar.Int } => builder.InsertData(new GLSLSMin(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), a.Id, b.Id)),
            _ => throw new NotSupportedException($"Unsupported element type for min: {context.ReverseTypes[a.TypeId].GetElementType()}"),
        };
        return new(instruction);
    }

    public override SpirvValue CompileMax(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue a, SpirvValue b, TextLocation location = default)
    {
        var instruction = context.ReverseTypes[a.TypeId].GetElementType() switch
        {
            ScalarType { Type: Scalar.Float or Scalar.Double } => builder.InsertData(new GLSLFMax(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), a.Id, b.Id)),
            ScalarType { Type: Scalar.UInt } => builder.InsertData(new GLSLUMax(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), a.Id, b.Id)),
            ScalarType { Type: Scalar.Int } => builder.InsertData(new GLSLSMax(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), a.Id, b.Id)),
            _ => throw new NotSupportedException($"Unsupported element type for max: {context.ReverseTypes[a.TypeId].GetElementType()}"),
        };
        return new(instruction);
    }

    public override SpirvValue CompileClamp(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue x, SpirvValue min, SpirvValue max, TextLocation location = default)
    {
        var instruction = context.ReverseTypes[x.TypeId].GetElementType() switch
        {
            ScalarType { Type: Scalar.Float } => builder.InsertData(new GLSLFClamp(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), x.Id, min.Id, max.Id)),
            ScalarType { Type: Scalar.UInt } => builder.InsertData(new GLSLUClamp(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), x.Id, min.Id, max.Id)),
            ScalarType { Type: Scalar.Int } => builder.InsertData(new GLSLSClamp(context.GetOrRegister(functionType.ReturnType), context.Bound++, context.GetGLSL(), x.Id, min.Id, max.Id)),
            _ => throw new NotSupportedException($"Unsupported element type for clamp: {context.ReverseTypes[x.TypeId].GetElementType()}"),
        };
        return new(instruction);
    }

    public override SpirvValue CompileRadians(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue x, TextLocation location = default) => CompileGLSLFloatUnaryCall(table, context, builder, functionType.ReturnType, Specification.GLSLOp.GLSLRadians, x);
    public override SpirvValue CompileDegrees(SymbolTable table, SpirvContext context, SpirvBuilder builder, FunctionType functionType, SpirvValue x, TextLocation location = default) => CompileGLSLFloatUnaryCall(table, context, builder, functionType.ReturnType, Specification.GLSLOp.GLSLDegrees, x);

View on GitHub (pinned to 96fad776d2)