CNA-BUG-264: Vulkan passes XNA's normalised RasterizerState.DepthBias to vkCmdSetDepthBias unscaled, so a realistic bias has no effect
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 c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
VulkanRenderer hands DepthBias to vkCmdSetDepthBias raw, but that constant factor counts minimum depth steps; EasyGL, SDL_GPU, Metal and Direct3D 11 scale XNA's normalised value by the depth format, so -0.0001 offsets nothing on Vulkan.
- Identifier
CNA-BUG-264- Category
- Bug
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
c1c316b9(c1c316b9c7a846ce8002809c151fcd1af14942c9) - Severity
- Medium (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- Microsoft::Xna::Framework::Graphics::RasterizerState::DepthBias and SlopeScaleDepthBias on the VULKAN renderer (VulkanRenderer::ApplyRasterizerState)
Expected behaviour
XNA 4.0 is Direct3D 9, where DepthBias is a normalised depth value added to the depth. CNA's renderer contract says so indirectly: IGraphicsRenderer.hpp documents in IRenderTargetRenderer::DepthBufferBitsEXT that an API whose bias is a multiple of the smallest resolvable depth step, naming Vulkan's depthBiasConstantFactor, needs the depth width to convert. FNA3D multiplies the XNA value by 65,535 (16-bit depth) or 16,777,215 (24-bit), and CNA's EasyGL, SDL_GPU, Metal and Direct3D 11 renderers convert it as well, so a sample that lifts a flat shadow with DepthBias = -0.0001f lifts it on each of them.
Actual behaviour at TARGET
VulkanRenderer::ApplyRasterizerState stores DepthBias and SlopeScaleDepthBias as given, and the draw replay calls vkCmdSetDepthBias(cb, draw.depthBias, 0.0f, draw.slopeScaleDepthBias) with no depth-format scale; no Vulkan render-target class overrides DepthBufferBitsEXT. A constant factor of -0.0001 is about 1e-4 of one depth step, that is, no bias. vulkan_depth_bias_test.cpp uses -1e6 and -2e3 on purpose (“bias magnitudes are deliberately large”) and so cannot see the defect, and CNA's records close the failing Vulkan_DepthBias case as a test defect (VULKAN-091) without examining the product behaviour. The source comment that says the mapping matches FNA omits the scale. EasyGL's EasyGLDepthBiasToPolygonOffsetUnits carries the 16/24-bit depth-format scale Vulkan lacks.
Source locations
modules/renderers/vulkan/src/VulkanRenderer.cpp— ApplyRasterizerState stores the bias raw; the draw replay calls vkCmdSetDepthBias with itmodules/renderers/vulkan/examples/vulkan_depth_bias_test.cpp— deliberately huge magnitudes, so it cannot see the missing scalemodules/graphics/include/CNA/Internal/Renderers/Common/IGraphicsRenderer.hpp— IRenderTargetRenderer::DepthBufferBitsEXT documents the conversion that Vulkan's depthBiasConstantFactor needsmodules/renderers/sdl-gpu/src/SdlGpuRenderer.cpp— XnaToSdlDepthBiasScaledocs/easygl_bugs.md— CNA's own record (2026-09-08): Vulkan and DirectX 11 still carry the unscaled premisemodules/renderers/easygl/include/CNA/Internal/Renderers/EasyGL/EasyGLRenderer.hpp— EasyGLDepthBiasToPolygonOffsetUnits: the depth-format scale Vulkan lacks
Evidence
Read at c1c316b9; nothing was built or executed. Reported as a RESTORE-ISSUE by the C05 conservation reviewer (an earlier absorption record had closed the extreme-bias Vulkan failure as a test defect) and re-verified by the orchestrator against the Vulkan and EasyGL sources, CNA's docs/easygl_bugs.md and the Direct3D 11 mapping (D3DCommon, which scales it at this snapshot although CNA's 2026-09-08 note still lists DirectX 11 as unscaled).
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
Vulkan_DepthBias uses deliberately huge magnitudes and still fails on CNA's own record; no test uses a realistic normalised bias on Vulkan, whereas EasyGL has EasyGLDepthBias.IsScaledByTheDepthBuffersOwnResolution.
Regression test
Draw a quad slightly in front of a coplanar one with DepthBias = -0.0001f on VULKAN and expect it to win the depth test, as on EasyGL; or unit-test the conversion the way EasyGL's EasyGLDepthBias tests do.
Blast radius
Content on VULKAN that relies on DepthBias for decals, planar shadows or z-fight avoidance; any value inside XNA's normalised range has effectively no effect there, while the same content works on the renderers that scale.
Workaround
Prefer offsetting the geometry, or, on VULKAN only, a bias several orders of magnitude larger (the test uses -1e6); both are renderer-specific hacks.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- XNA compatibility
- Internals
- Vulkan internals
- Deep dives
- Vulkan: deferred state and descriptors
- Known issues
- Bug index