CNA-PLAT-019: FNA3D refuses a PbrEffect or SkinnedPbrEffect draw whose vertex declaration has no Tangent0 on its SDL_GPU and Direct3D 11 drivers, where every other renderer draws it with a neutral tangent
Evidence basis: source-verified at the pinned commit; recorded by CNA's own run (not repeated here); 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.
FNA3D's SDL_GPU and Direct3D 11 drivers cannot build a pipeline for a shader input the declaration lacks, so the FNA3D renderer throws NotSupportedException (FNA3D-MISSING-STOCK-INPUT) for a PBR draw over tangent-free vertices such as VertexPositionNormalTexture; its OpenGL driver and the other renderers supply a neutral tangent.
- Identifier
CNA-PLAT-019- Category
- Platform limitation
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
3b43bd86(3b43bd8687ed46523d873f9bec4b32bd8481dcb5) - Evidence basis
- Recorded by CNA: CNA's own recorded run, not repeated here
- Tests touching this area
- Yes: see Current tests
- Affected contract
- PbrEffect and SkinnedPbrEffect (CNAEXT) draws on the FNA3D renderer with a VertexDeclaration that has no Tangent element at usage index 0, when FNA3D runs its SDL_GPU or Direct3D 11 driver
Expected behaviour
Since 91612a0a3 (museum rv-shading, 2026-10-22) CNA's PBR effects do not depend on whether a mesh stores a tangent: a renderer supplies the neutral tangent the GL path reads for an absent input, and pbr_vertex_contract_test.cpp draws the same surface from VertexPositionNormalTexture and from VertexPositionNormalTangentTexture. A tangent-free mesh should draw the same on every renderer that ships PbrEffect.
Actual behaviour at TARGET
Before it binds the vertex buffers of a stock draw, Fna3dDraw.cpp checks that every input the selected effect variant reads is declared (RequireStockVertexInputsDeclared); for CnaPbrEffect and CnaSkinnedPbrEffect that includes Tangent0. A missing input throws System::NotSupportedException (“FNA3D renderer (FNA3D-MISSING-STOCK-INPUT): ... FNA3D's SDL_GPU and Direct3D 11 drivers cannot create a pipeline for it (only its OpenGL driver reads a default for a missing input)”). The check is skipped only where the driver reads a default, which Fna3dRenderer.cpp records for FNA3D's OpenGL driver alone (driverDefaultsMissingVertexInputs_). FNA3D tries its SDL_GPU driver first (fna3d-renderer.md), so on a default FNA3D device a PBR draw over a tangent-free declaration, such as XNA's VertexPositionNormalTexture, throws, where FNA3D's OpenGL driver and every other renderer supply a neutral tangent. CNA lists the limitation in handoff.md section 5.2.
Source locations
modules/renderers/fna3d/src/Fna3dDraw.cpp— RequireStockVertexInputsDeclared: Tangent0 for CnaPbrEffect/CnaSkinnedPbrEffect; the FNA3D-MISSING-STOCK-INPUT refusalmodules/renderers/fna3d/src/Fna3dRenderer.cpp— driverDefaultsMissingVertexInputs_ is true for the OpenGL driver onlydocs/fna3d-renderer.md— FNA3D's driver order, its SDL_GPU driver first, and the FNA3D_FORCE_DRIVER hinthandoff.md— section 5.2: FNA3D refuses a PbrEffect or SkinnedPbrEffect draw without TANGENT0 on its SDL_GPU and Direct3D 11 driversmodules/graphics/examples/pbr_vertex_contract_test.cpp— the tangent-free and tangent-carrying PBR draws must agree (91612a0a3)
Evidence
Read at 3b43bd86: the check and the driver probe above, and the commit that introduced the refusal (84bf6fc4a, AM4-190, 2026-10-09: a stock draw missing a shader input is refused by name where the driver would otherwise crash). The refusal predates the previous pin; CNA's handoff lists it among the current limitations only from this snapshot, measured by the museum's rv-shading on RADV (2026-10-25). Recorded by CNA; nothing was built or executed for this entry, and no run of the Direct3D 11 driver on Windows is recorded.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
pbr_vertex_contract_test.cpp (CnaPbrVertexContractTest, and a WEBGPU registration) requires a tangent-free and a tangent-carrying PBR mesh to draw alike; no test pins the FNA3D refusal or its dependence on the driver.
Regression test
Run the PBR vertex contract on FNA3D with FNA3D_FORCE_DRIVER set to its SDL_GPU driver: it refuses today and passes once the FNA3D renderer binds a neutral tangent stream for a declaration without one.
Blast radius
Games that draw PbrEffect or SkinnedPbrEffect over vertex data without a tangent (XNA's stock vertex types, hand-built geometry) on the FNA3D renderer with its SDL_GPU driver (FNA3D's first choice, and its driver on Apple) or its Direct3D 11 driver. Declarations that carry Tangent0, FNA3D's OpenGL driver, compiled effects and the other renderers are unaffected.
Workaround
Supply a Tangent0 element (for example VertexPositionNormalTangentTexture), pin FNA3D's OpenGL driver with the FNA3D_FORCE_DRIVER hint, or use another renderer.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Internals
- Graphics backends
- Deep dives
- Vertex streams and declarations
- Known issues
- Platform limitation index