CNA-PLAT-002: SDL_GPU honours BlendState.MultiSampleMask only as all-or-none and refuses a partial mask, and FNA3D's SDL_GPU driver ignores it, because SDL_gpu reserves its sample-mask fields
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 3b43bd86; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
SDL 3.5.0 still documents SDL_GPUMultisampleState::sample_mask/enable_mask as reserved, so on a multisampled target SDL_GPU draws normally for a mask keeping every sample, drops the draw for a mask keeping none and throws NotSupportedException for any other; FNA3D's SDL_GPU driver writes the reserved field without effect. RendererFeature::MultiSampleMask reports both.
- Identifier
CNA-PLAT-002- Category
- Platform limitation
- Subsystem
- Graphics & renderers
- Status
- Narrowed (partially fixed; describes only what survives)
- Verified against
- CNA
3b43bd86(3b43bd8687ed46523d873f9bec4b32bd8481dcb5) - Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- BlendState.MultiSampleMask / GraphicsDevice.MultiSampleMask on SDL_GPU and on the FNA3D renderer's SDL_GPU driver
Expected behaviour
XNA's HiDef profile restricts a draw to the samples a partial MultiSampleMask keeps. A renderer that cannot should say so: refuse the mask and report the boundary through its capabilities.
Actual behaviour at TARGET
SDL 3.5.0, the revision CNA pins (86296ac8), still documents SDL_GPUMultisampleState::sample_mask and enable_mask as reserved (“must be set to 0” / “false”). Since c7f6c68e5 (CNA-DEMOS DC-R2, on the owner's decision) SdlGpuRenderer.cpp records the mask in ApplyBlendState and judges it for every queued draw in PushDrawOrder against the bound target: on a multisampled target a mask that keeps every sample draws as before, one that keeps none drops the draw (exact, since such a draw writes no colour, depth, stencil or occlusion sample), and any other throws System::NotSupportedException; a single-sample target ignores the mask, as in XNA. RendererFeature::MultiSampleMask (C CNA_RENDERER_FEATURE_MULTI_SAMPLE_MASK) reports Restricted there. FNA3D's SDL_GPU driver writes the mask into the same reserved field, where it has no effect, so the FNA3D renderer reports the feature Supported on its OpenGL driver only (Fna3dRenderer.hpp, MultiSampleMaskSupportEXT); on the SDL_GPU driver a partial mask is ignored without an exception. EasyGL (where the context has glSampleMaski), WEBGPU, SOFTWARE and DIRECTX9 report and apply arbitrary masks.
Narrowed since first recorded: SDL_GPU no longer drops the mask silently: masks keeping every sample or none are applied exactly, a partial mask is refused by name, and the support is queryable. CNA records the boundary in handoff.md section 5.2.
Source locations
modules/renderers/sdl-gpu/src/SdlGpuRenderer.cpp— ApplyBlendState records the mask; PushDrawOrder applies all-or-none and refuses a partial mask (c7f6c68e5)modules/renderers/fna3d/include/CNA/Internal/Renderers/Fna3d/Fna3dRenderer.hpp— MultiSampleMaskSupportEXT: Supported on FNA3D's OpenGL driver onlymodules/graphics/tests/CNA/CrossRendererContractTests.cpp— MultiSampleMaskSupportMatchesWhatTheResolvedTargetShowshandoff.md— section 5.2: SDL_GPU applies a MultiSampleMask only when it keeps every sample or noneCNA_DEMOS_REPAIR_MATRIX.json— additional_validation_findings DC-R2: UNSUPPORTED_CONTRACT_CORRECTED
Evidence
Checked by reading the named sources at 3b43bd86; nothing was built or executed for this entry.
Narrowed at 3b43bd86: read c7f6c68e5's code at this snapshot (the judgement in PushDrawOrder, the feature in BuildRendererCapabilityProfileEXT, each renderer's MultiSampleMaskSupportEXT) and the cross-renderer test; the SDL pin moved to 86296ac8, whose SDL_gpu.h still marks both fields reserved; FNA3D's driver at the fork pin 10f650b9d0f6 sets them when the mask is not all ones. The test results are CNA's own record; not executed here.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
CrossRendererContractTests.cpp (MultiSampleMaskSupportMatchesWhatTheResolvedTargetShows) draws a red quad into a 4x target under masks keeping every sample, none and one, and holds each compiled-in renderer's RendererFeature::MultiSampleMask answer to the resolved pixels: a Restricted renderer must honour the first two and refuse the third, an Unsupported one must ignore all three. The shared msaa_fragment_contract_test.cpp is registered for EasyGL and SOFTWARE only.
Regression test
The cross-renderer test above; once SDL_gpu exposes the mask, SDL_GPU's answer moves to Supported and the same test requires a single kept sample to resolve to a quarter of the colour.
Blast radius
MSAA techniques that rely on partial sample masks (alpha-to-coverage emulation, stippled transparency) on SDL_GPU, the default renderer on Windows, macOS and iOS, where they now throw, and on FNA3D's SDL_GPU driver, where the mask is ignored. Masks keeping every sample or none, single-sample targets and the other renderers are unaffected.
Workaround
Ask GraphicsDevice::GetRendererFeatureSupportEXT(RendererFeature::MultiSampleMask) and fall back to blending or to dithering with discarded pixels where the answer is not Supported.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Known issues
- Platform limitation index