CNA-BUG-094: SDL_GPU claims compute shaders and SPIR-V compute intake on every device, including Direct3D 12 and Metal drivers that cannot take its raw SPIR-V compute pipelines

CNA snapshot c1c316b9  ·  Known Issues › Current bugs  ·  source links pinned to c1c316b9

✓

Evidence basis: source-verified at the pinned commit; inferred from the source (the behaviour was not run); tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

SupportsComputeShadersEXT() and the SPIR-V compute-stage answer are true whenever a device exists, but compute pipelines still reach SDL_gpu as raw SPIR-V, which its Direct3D 12 and Metal drivers reject; ShaderEffect SPIR-V is now routed through the shader cross-compiler.

Identifier
CNA-BUG-094
Category
Bug
Subsystem
Graphics & renderers
Status
Narrowed (partially fixed; describes only what survives)
Verified against
CNA c1c316b9 (c1c316b9c7a846ce8002809c151fcd1af14942c9)
Severity
Low (a triage suggestion, not a project priority)
Evidence basis
Inferred (strong): follows from the code, but the behaviour was not run
Tests touching this area
Yes: see Current tests
Affected contract
GraphicsDevice::SupportsCapability(GraphicsCapability::ComputeShaders) and GraphicsDevice::SupportsShaderLanguageEXT(SpirV, Compute) on SDL_GPU

Expected behaviour

IGraphicsRenderer::SupportsComputeShadersEXT() answers "whether this renderer really implements compute", and SupportsShaderLanguageEXT is true "only when the implemented shader intake consumes that exact pair". GraphicsDevice::SupportsCapability(ComputeShaders) is derived from the former precisely so that compute is never claimed by default.

Actual behaviour at TARGET

SdlGpuRenderer::SupportsComputeShadersEXT() returns device_ != nullptr, and SdlGpuRenderer::SupportsShaderLanguageEXT answers the compute stage with it. Stock shaders and, since AM4-068, ShaderEffect SPIR-V reach a non-SPIR-V driver through CreateRoutedSpirvShaderEXT, which uses SDL_shadercross when the device does not accept SPIR-V. The compute intake does not: SdlGpuComputeShaderRenderer::CompileProgram still creates the pipeline with SDL_GPU_SHADERFORMAT_SPIRV. With CNA_SDL_GPU_SHADERCROSS=ON, the default on Windows and macOS, the device may be created on SDL_gpu's Direct3D 12 or Metal driver; there both compute answers are true while a compute pipeline cannot be created from the raw SPIR-V. No public CNA API creates compute pipelines, so the effect is on callers that trust SupportsCapability(ComputeShaders) and on shader packages that select a SPIR-V compute variant.

Source locations

Evidence

Checked by reading at c1c316b9; not executed; no compute run on SDL_gpu's Direct3D 12 driver or on its Metal driver exists for this entry. That SDL_gpu's Direct3D 12 and Metal drivers need translated shaders is CNA's own statement in cmake/RendererSelection.cmake and in the constructor's refusal when no driver accepts SPIR-V. On Linux SDL_gpu offers only its Vulkan driver, where both answers are correct and sdlgpu_smoke_test.cpp asserts them. Which driver SDL picks on a Windows host that offers both a Vulkan and a Direct3D 12 driver was not established; on macOS the device is Metal.

Narrowed at c1c316b9: 8a5e6e220 (AM4-068) routes ShaderEffect SPIR-V (and the libshaderc GLSL path) through CreateRoutedSpirvShaderEXT, the shadercross route the stock shaders already took, so the vertex and fragment SPIR-V answers now describe an intake the device can serve; SdlGpuComputeShaderRenderer::CompileProgram was not changed. Read at c1c316b9; not executed.

Focused reproduction

// Illustrative; not compiled or run for this entry. SDL_GPU build with CNA_SDL_GPU_SHADERCROSS=ON,
// on macOS (SDL_gpu's Metal driver) or on Windows with SDL_GPU_DRIVER=direct3d12.
using namespace Microsoft::Xna::Framework::Graphics;
GraphicsDevice device;
bool compute = device.SupportsCapability(CNA::GraphicsCapability::ComputeShaders);                         // true
bool spirv = device.SupportsShaderLanguageEXT(CNA::ShaderLanguageEXT::SpirV, CNA::ShaderStageEXT::Compute); // true
// Expected with truthful answers: both false on a driver that cannot create a pipeline from SPIR-V.
// Actual: SdlGpuComputeShaderRenderer::CompileProgram hands SDL raw SPIR-V, which the driver rejects.

Current tests

sdlgpu_smoke_test.cpp asserts that the device-level ComputeShaders and IndirectDraw answers equal the renderer's and are true, on Vulkan. No test creates a compute pipeline on a non-SPIR-V driver.

Regression test

Make the compute answers depend on SDL_GetGPUShaderFormats(device_) including SDL_GPU_SHADERFORMAT_SPIRV (or route the compute intake through SDL_shadercross as the graphics stages now are), and assert, on SDL_gpu's Direct3D 12 driver and on its Metal driver, that SupportsCapability(ComputeShaders) equals whether a trivial compute pipeline can be created.

Blast radius

SDL_GPU on a Direct3D 12 or Metal driver only (a shadercross build, the default on Windows and macOS): callers that trust SupportsCapability(ComputeShaders) and shader packages that select a SPIR-V compute variant. ShaderEffect SPIR-V payloads, Vulkan-driver SDL_GPU (every Linux build) and stock drawing are unaffected.

Workaround

On Windows, select SDL_gpu's Vulkan driver (SDL_GPU_DRIVER=vulkan) where one is installed; on macOS, do not rely on the ComputeShaders answer of SDL_GPU.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Known issues
Bug index