CNA-BUG-246: docs/graphics-resource-lifetime.md says existing XNA resources hold a unique_ptr renderer and names a non-existent ITexture2DRenderer; Texture2D, Texture3D and TextureCube hold shared_ptr renderers and Texture2D's public copies share one
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 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 document's Ownership Model gives unique_ptr renderer ownership for existing XNA resources, a list its scope sentence extends to Texture2D and RenderTarget2D, and knows only one kind of sharing: an internal record on non-copyable modern resources. Texture2D, Texture3D and TextureCube hold shared_ptr renderers, and Texture2D's public copies share the renderer and CPU shadow.
- Identifier
CNA-BUG-246- Category
- Bug
- Subsystem
- Documentation & release tooling
- Status
- Open
- Verified against
- CNA
3b43bd86(3b43bd8687ed46523d873f9bec4b32bd8481dcb5) - Severity
- Low (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
- docs/graphics-resource-lifetime.md section 1 (Ownership Model) against Microsoft::Xna::Framework::Graphics::Texture2D (copy constructor, copy assignment, GetRendererWeak, GetCpuPixelsWeak), Texture3D and TextureCube
Expected behaviour
The lifetime document describes the ownership that the resource classes implement, so that a maintainer reasoning about disposal, copies and native-handle retention starts from the right model.
Actual behaviour at TARGET
graphics-resource-lifetime.md section 1 says existing XNA resources hold a std::unique_ptr<IXxxRenderer> (for example IVertexBufferRenderer or ITexture2DRenderer) and that a renderer may hand its native handles to an internal retained record that “is not a second public owner”; its scope sentence names Texture2D and RenderTarget2D among the covered types. At TARGET no type named ITexture2DRenderer exists under modules/ (the real interface is ITextureRenderer). Texture2D.hpp holds std::shared_ptr<ITextureRenderer> renderer_, a shared cpuPixels_ vector and shared extraMipLevels_; its public CNAEXT copy constructor and copy assignment (user-defined since af3c5037c so that every live copy registers with the device for disposal, as TextureCube's now do too) are documented as 'a second handle to the same texture' (shared until a full-level SetData, KF-4), and GetRendererWeak()/GetCpuPixelsWeak() hand out weak references. Texture3D.hpp and TextureCube.hpp hold std::shared_ptr renderers too. Of the five resource headers read, only VertexBuffer.hpp and IndexBuffer.hpp follow the unique-ownership rule, which is the shape section 5's move example uses. The document has no account of the texture family's public value-copy sharing.
Source locations
docs/graphics-resource-lifetime.md— section 1, Ownership Modelmodules/graphics/include/Microsoft/Xna/Framework/Graphics/Texture2D.hpp— renderer_, cpuPixels_, extraMipLevels_, copy operations that share the renderer, GetRendererWeak, GetCpuPixelsWeakmodules/graphics/include/Microsoft/Xna/Framework/Graphics/Texture3D.hpp— renderer_ is a shared_ptrmodules/graphics/include/Microsoft/Xna/Framework/Graphics/TextureCube.hpp— renderer_ is a shared_ptrmodules/graphics/include/Microsoft/Xna/Framework/Graphics/VertexBuffer.hpp— renderer_ is a unique_ptrmodules/graphics/include/Microsoft/Xna/Framework/Graphics/IndexBuffer.hpp— renderer_ is a unique_ptrmodules/graphics/include/CNA/Internal/Renderers/Common/IGraphicsRenderer.hpp— ITextureRenderer, the real texture renderer interface
Evidence
Checked by reading at 3b43bd86; not executed. Read the document's sections 1, 2 and 5 and the member declarations and Doxygen of the five resource headers; searched modules/ for ITexture2DRenderer (only the document names it). The defect is that the document's ownership model has no place for the texture family's shared_ptr holders and public copies; the copy operations of Texture2D and TextureCube are user-defined (af3c5037c) but still share one renderer and CPU shadow. Another sentence of the same document is tracked separately.
Re-verified at c6dec91f: e60fa35f7 (2026-10-11) folded GPU ordering rules into the document and replaced its example of a retired resource class with a general sentence about renderer-internal retained records; section 1 still prescribes std::unique_ptr<IXxxRenderer> and still names ITexture2DRenderer. Not executed.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
Texture2DTests.cpp checks that copies preserve width, height and format; nothing checks the document.
Regression test
Documentation fix: state per resource family which holder is used (shared for the texture family, with value copies sharing the renderer and CPU shadow; unique for buffers) and replace ITexture2DRenderer with ITextureRenderer.
Blast radius
Maintainers and extension authors who reason about texture disposal, copying or native-handle retention from this document; no runtime behaviour is affected.
Workaround
Read the ownership from the headers: textures are shared value wrappers; buffers own their renderer uniquely.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- 3D rendering guide
- Deep dives
- Texture data transfer: Texture2D shape
- Known issues
- Bug index