CNA-BUG-264: Vulkan passes XNA's normalised RasterizerState.DepthBias to vkCmdSetDepthBias unscaled, so a realistic bias has no effect

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

✓

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

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.

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

Known issues
Bug index