CNA-BUG-281: FNA3D's Direct3D 11 driver cannot build some valid compiled effects: a ps_3_0 shader that reads two vertex outputs packed in one register fails to compile, and the integer input-layout rewrite can retype the wrong semantic
Evidence basis: source-verified at the pinned commit; recorded by CNA's own run (not repeated here). 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.
the MojoShader code behind FNA3D's Direct3D 11 driver, in CNA's pinned fork, names a struct member that does not exist when a ps_3_0 shader reads, from one register, semantics the vertex shader wrote to separate registers, so the generated HLSL fails to compile; and it finds the semantic of an integer vertex element by substring, so DEPTH1 can match an earlier DEPTH10 and swap their integer and float declarations.
- Identifier
CNA-BUG-281- Category
- Bug
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
3b43bd86(3b43bd8687ed46523d873f9bec4b32bd8481dcb5) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Recorded by CNA: CNA's own recorded run, not repeated here
- Tests touching this area
- None
- Affected contract
- Compiled XNA effects (Effect Framework bytecode) drawn on the FNA3D renderer when FNA3D runs its Direct3D 11 driver (Windows; FNA3D tries its SDL_GPU driver first, or the driver is selected with FNA3D_FORCE_DRIVER)
Expected behaviour
A compiled effect that Direct3D 9 runs should run on every FNA3D driver: a vertex shader may write the semantics a ps_3_0 pixel shader reads in any register layout, and an integer vertex element should change the declaration of exactly the semantic it names.
Actual behaviour at TARGET
The FNA3D renderer builds FNA3D and MojoShader from CNA’s forks (ThirdPartyFNA3D.cmake, MojoShader 03b686fe1a33). In that MojoShader, the code behind FNA3D's Direct3D 11 driver (mojoshader_d3d11.c) links a vertex shader’s output struct to the pixel shader’s input struct by name; when a ps_3_0 shader reads two semantics packed into one register (FOG in its x, TEXCOORD0 in yzw, both from v0) that the vertex shader wrote to separate registers (o1.x, o2.yzw), the generated HLSL names a member that does not exist and does not compile (R9-01; CNA records it as present before the review too). When the input layout has an integer element, the same file rewrites the declaration of its semantic in the HLSL source by locating <name><index> with strstr, so DEPTH1 is found inside an earlier DEPTH10 and the integer and float declarations of the two are swapped (R9-03). CNA lists both in handoff.md section 5.2 as found in the review’s third round and not fixed, and notes that CNA’s committed effects contain neither shape. The same section records that the rewrite looks for PSIZE0 where the generated HLSL writes PSIZE.
Source locations
handoff.md— section 5.2, MojoShader's D3D11 glue: R9-01 (packed ps_3_0 inputs) and R9-03 (substring match), found in the review's third round, not fixed; CNA's committed effects contain neithercmake/ThirdPartyFNA3D.cmake— the FNA3D pin 10f650b9d0f6 whose MojoShader submodule is 03b686fe1a33docs/fna3d-renderer.md— the forks, FNA3D's driver order and FNA3D_FORCE_DRIVER
Evidence
Read at 3b43bd86: the handoff entry and the pin. In the pinned fork (03b686fe1a33, read in a local clone of libcna/mojoshader) the integer rewrite builds the semantic name with snprintf(sem, ..., "%s%d", SemanticName, SemanticIndex) and locates it with strstr(newSource, sem), which matches a prefix of a longer name. The ps_3_0 packing case rests on CNA’s record of the review, not on a reproduction here. Nothing was built or executed for this entry; no run on Windows is recorded for either case.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
No test in CNA or in the fork’s tests/cna covers either shape; FNA3D’s Direct3D 11 driver runs the fork’s eight test executables under Wine with DXVK (recorded by CNA), none with an integer DEPTH1/DEPTH10 pair or a packed ps_3_0 input.
Regression test
A fork test that compiles, through the code behind FNA3D's Direct3D 11 driver, a ps_3_0 shader reading FOG and TEXCOORD0 from one register against a vertex shader writing them separately, and a vertex declaration with integer DEPTH1 beside float DEPTH10; both must link with the declarations they name.
Blast radius
Games that load custom compiled effects of those shapes and run on the FNA3D renderer with its Direct3D 11 driver. CNA’s committed effects, FNA3D’s OpenGL and SDL_GPU drivers, and the other renderers are unaffected.
Workaround
Use FNA3D’s SDL_GPU or OpenGL driver (the FNA3D_FORCE_DRIVER hint) or another renderer for such effects, or give the vertex shader the register packing the pixel shader reads and avoid semantics whose names are prefixes of each other.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Tutorial 108: FNA3D
- Internals
- Graphics backends
- Deep dives
- Compiled effects semantics
- Known issues
- Bug index