stride3d/stride · error · NotSupportedException

Unsupported resource class

Error message

Unsupported resource class {binding.Class}

What it means

Thrown by the descriptor-type mapping in VulkanFrameRenderer when an EffectParameterClass (resource kind from the shader bytecode) is not one of the handled classes (CBV, SRV, UAV, etc.). The switch translates HLSL-style binding classes into VkDescriptorType; any unrecognized class falls to the NotSupportedException arm.

Solutions

  1. Extend the switch to map the missing EffectParameterClass (e.g. Sampler => VkDescriptorType.Sampler) to its VkDescriptorType.
  2. Log binding.Class and binding.Type at the throw site to identify which resource kind is unmapped, then add the case.
  3. If the resource is irrelevant to the frame test, skip bindings with unmapped classes instead of throwing.

Example fix

// before
_ => throw new NotSupportedException($"Unsupported resource class {binding.Class}"),
// after
EffectParameterClass.Sampler => VkDescriptorType.CombinedImageSampler,
_ => throw new NotSupportedException($"Unsupported resource class {binding.Class}"),
Defensive patterns

Strategy: validation

Validate before calling

static readonly HashSet<EffectParameterClass> SupportedClasses = new()
{ EffectParameterClass.ConstantBuffer, EffectParameterClass.Texture, EffectParameterClass.UnorderedAccessView };

if (!SupportedClasses.Contains(binding.Class))
    throw new InvalidOperationException($"Binding {binding.Name} uses unmapped class {binding.Class}");

Try / catch

try { renderer.RenderFrame(output); }
catch (NotSupportedException ex) when (ex.Message.StartsWith("Unsupported resource class"))
{
    // log binding.Class, skip test or update the mapping table
}

Prevention

When it happens

Trigger: A shader whose reflection metadata contains a resource class not covered by the switch (e.g. samplers, acceleraton structures, or an unhandled EffectParameterClass value) reaching SetupDescriptors during descriptor-set layout construction.

Common situations: Tests exercising shaders with sampler or texture arrays beyond the mapped subset; new shader effect kinds added upstream without updating this mapping; typos in effect parameter classification producing unexpected class values.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Tests/FrameRenderer.Vulkan.cs:575

    }

    private static VkDescriptorType GetDescriptorType(EffectResourceBindingDescription binding) => binding.Class switch
    {
        EffectParameterClass.ConstantBuffer => VkDescriptorType.UniformBuffer,
        EffectParameterClass.Sampler => VkDescriptorType.Sampler,
        EffectParameterClass.ShaderResourceView => binding.Type switch
        {
            EffectParameterType.Buffer => VkDescriptorType.UniformTexelBuffer,
            EffectParameterType.StructuredBuffer or EffectParameterType.ByteAddressBuffer => VkDescriptorType.StorageBuffer,
            _ => VkDescriptorType.SampledImage,
        },
        EffectParameterClass.UnorderedAccessView => binding.Type switch
        {
            EffectParameterType.RWBuffer => VkDescriptorType.StorageTexelBuffer,
            EffectParameterType.RWStructuredBuffer or EffectParameterType.RWByteAddressBuffer => VkDescriptorType.StorageBuffer,
            _ => VkDescriptorType.StorageImage,
        },
        _ => throw new NotSupportedException($"Unsupported resource class {binding.Class}"),
    };

    public override void RenderFrame(Span<byte> result)
    {
        SetupDescriptors();

        // Quad geometry, same as the D3D11 renderer
        ReadOnlySpan<float> vertices =
        [
            1f,  1f, 0f,  1.0f, 1.0f,
            1f, -1f, 0f,  1.0f, 0.0f,
            -1f,-1f, 0f,  0.0f, 0.0f,
            -1f, 1f, 1f,  0.0f, 1.0f,
        ];
        ReadOnlySpan<uint> indices = [0, 1, 3, 1, 2, 3];
        var (vertexBuffer, _) = CreateHostBuffer((ulong)(vertices.Length * sizeof(float)), VkBufferUsageFlags.VertexBuffer, MemoryMarshal.AsBytes(vertices));
        var (indexBuffer, _) = CreateHostBuffer((ulong)(indices.Length * sizeof(uint)), VkBufferUsageFlags.IndexBuffer, MemoryMarshal.AsBytes(indices));

View on GitHub (pinned to 96fad776d2)