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

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

✓

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 009d40f5; 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 SupportsShaderLanguageEXT(SpirV) answer true whenever a device exists, but compute pipelines and ShaderEffect SPIR-V payloads reach SDL_gpu as raw SPIR-V, which its Direct3D 12 and Metal drivers reject.

Identifier
CNA-BUG-094
Category
Bug
Subsystem
Graphics & renderers
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
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), GraphicsDevice::SupportsShaderLanguageEXT and CNA::Graphics::ComputeShader 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 accepts SpirV for vertex and fragment whenever a device exists (compute follows SupportsComputeShadersEXT). Stock shaders reach a non-SPIR-V driver through CreateSdlGpuShaderEXT, which chooses SDL_shadercross when the device does not accept SPIR-V. The other two intakes do not: SdlGpuComputeShaderRenderer::CompileProgram creates the compute pipeline with SDL_GPU_SHADERFORMAT_SPIRV, and the ShaderEffect SPIR-V route (SdlGpuEffectRenderer::CompileProgram to CreateShaderFromRemappedSpirvEXT) does the same. 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 the capability is true and creation fails, so CNA::Graphics::ComputeShader throws ShaderCompilationExceptionEXT carrying SDL's error instead of the NotSupportedException a false capability would give, and a shader package that prefers its SPIR-V variant selects a payload the device cannot load.

Source locations

Evidence

Checked by reading at 009d40f5; not executed; no Direct3D 12 or Metal run 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, in modules/renderers/sdl-gpu/CMakeLists.txt 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 has both Vulkan and Direct3D 12 was not established; on macOS the device is Metal. Engine-layer consumers mostly survive the claim: ClusteredLightCompute catches the failure and uses its CPU path, and the passes that also require CustomEffects are off because that capability is false on Windows and Apple builds.

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 claimed = device.SupportsCapability(CNA::GraphicsCapability::ComputeShaders); // true
CNA::Graphics::ComputeShader shader(device, spirvComputeSource);
// Expected with a truthful capability: NotSupportedException before any creation.
// Actual: ShaderCompilationExceptionEXT carrying "SDL_CreateGPUComputePipeline failed: ...".

Current tests

sdlgpu_smoke_test.cpp asserts that the device-level ComputeShaders and IndirectDraw answers equal the renderer's and are true, on Vulkan. SdlGpu_HeadlessGraphicsDevice and SdlGpu_BackbufferFormat are portable to a headless Direct3D 12 run through CNA's isolated Wine/vkd3d launcher, but neither creates a compute pipeline or a SPIR-V ShaderEffect. No test runs either intake on a non-SPIR-V driver.

Regression test

Make both answers depend on SDL_GetGPUShaderFormats(device_) including SDL_GPU_SHADERFORMAT_SPIRV (or route both intakes through SDL_shadercross), and extend the Direct3D 12 probe run to assert 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): CNAEXT ComputeShader, storage-buffer compute work and shader packages that select a SPIR-V variant. 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, use another renderer for CNAEXT compute.

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

Known issues
Bug index