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

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

✓

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 009d40f5; 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, OpenGL4, SDL_GPU and Direct3D 11/12 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 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
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, OpenGL4, SDL_GPU and Direct3D 11/12 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. OpenGL4Renderer::ApplyCurrentDepthBias carries the rule Vulkan lacks: passing the XNA value through raw “is indistinguishable from no bias at all”.

Source locations

Evidence

Read at 009d40f5; 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 OpenGL4 sources, CNA's docs/easygl_bugs.md and the Direct3D 11/12 mapping (D3DCommon, which scales it at this snapshot although CNA's 2026-09-08 note still lists DirectX 11 as unscaled). The same note lists PortableGL, whose glPolygonOffset(slopeScaleDepthBias, depthBias) call is raw in the source too; PortableGL's offset units were not analysed here.

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