CNA-BUG-103: VULKAN clears every colour attachment of a multiple-render-target set, so PreserveContents targets lose their contents when bound as part of an MRT set
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.
GetOrCreateMRTRenderPass begins each colour attachment with LOAD_OP_CLEAR from an undefined layout (except split-pass continuations), and its cache key has no usage flag, unlike the single-target pass that honours DiscardContents versus PreserveContents.
- Identifier
CNA-BUG-103- 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
- GraphicsDevice::SetRenderTargets with two or more RenderTarget2D bindings whose RenderTargetUsage is PreserveContents, on VULKAN
Expected behaviour
A PreserveContents render target keeps its pixels when it is bound again (XNA's RenderTargetUsage contract, which CNA's single-target Vulkan path implements through GetOrCreateRTRenderPass(depthFormat, discardContents)).
Actual behaviour at TARGET
In VulkanRenderer.cpp, GetOrCreateMRTRenderPass keys passes by colour formats, sample count, depth format and split role only, and for a non-continuation pass sets every colour attachment to loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR with initialLayout = VK_IMAGE_LAYOUT_UNDEFINED (depth and stencil likewise). Re-binding an MRT set therefore discards what each target held, whatever its usage.
Source locations
modules/renderers/vulkan/src/VulkanRenderer.cpp— VulkanRenderer::GetOrCreateMRTRenderPass (attachment load operations and RTPassKey)
Evidence
Checked by reading the named sources at 009d40f5; nothing was built or executed for this entry. A grep of the Vulkan and shared MRT fixtures found PreserveContents targets used in MRT sets (mrt_stock_effect_contract_test.cpp) but no leg that draws, unbinds, re-binds the same set and checks the earlier pixels; that search was not exhaustive.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
Vulkan_MRT_* fixtures (vulkan_mrt_msaa_test.cpp and siblings) check writes within one binding.
Regression test
An MRT fixture: bind two PreserveContents targets, draw, unbind, re-bind without clearing, draw elsewhere, and assert both draws survive on both targets.
Blast radius
Deferred-rendering and accumulation techniques on VULKAN that build G-buffers over several MRT passes; single-target rendering is unaffected.
Workaround
Composite into a separate target after each MRT pass, or re-bind MRT targets only when you intend to overwrite them.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Internals
- Vulkan internals: targets
- Deep dives
- Vulkan deferred state: usage · Render targets: MRT
- Known issues
- Bug index