CNA-BUG-257: PORTABLEGL depth clears force glDepthMask(GL_TRUE) and never restore it, although their own comment says both masks are restored as EasyGL does
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.
ClearColorAndDepth, ClearDepth, ClearDepthAndStencil and ClearColorDepthAndStencil call glDepthMask(GL_TRUE) and never put the depth write mask back; only the colour mask is restored.
- Identifier
CNA-BUG-257- Category
- Bug
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - 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
- GraphicsDevice::Clear with a depth option on the PORTABLEGL renderer (PortableGLRenderer::ClearColorAndDepth, ClearDepth, ClearDepthAndStencil, ClearColorDepthAndStencil)
Expected behaviour
The comment in ClearColorAndDepth states the rule: XNA's Clear ignores DepthBufferWriteEnable and ColorWriteChannels, so both masks are “neutralized here and restored afterwards, exactly as EasyGL does”. EasyGL implements the restore with RestoreWriteMasksAfterClear (REMED-GFX-237: “restores the write masks a clear had to force open”), so a clear never changes what a later draw's depth/stencil state says.
Actual behaviour at TARGET
In PortableGLRenderer.cpp the four clears that touch depth call glDepthMask(GL_TRUE) before glClear. Only the colour mask is put back afterwards (from colorWriteChannels); the depth write mask is left GL_TRUE until ApplyDepthStencilState next runs glDepthMask(depthWriteEnable ? GL_TRUE : GL_FALSE). A later draw through a state with DepthBufferWriteEnable false can therefore write depth after such a clear, if the state has not been re-applied in between.
Source locations
modules/renderers/portablegl/src/PortableGLRenderer.cpp— the four depth-touching clears force glDepthMask(GL_TRUE); ApplyDepthStencilState sets it from the statemodules/renderers/easygl/include/CNA/Internal/Renderers/EasyGL/EasyGLRenderer.hpp— RestoreWriteMasksAfterClear (REMED-GFX-237), the rule the PortableGL comment cites
Evidence
Read at 009d40f5; nothing was built or executed. Whether a later draw is actually affected depends on when the depth/stencil state is next applied, which was not traced through GraphicsDevice. Reported as an unpublished observation by the independent dismissal review (D1) and re-verified by the orchestrator against the source.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
The PORTABLEGL examples exercise clears and depth state separately (portablegl_blend_test.cpp covers the colour mask through Clear, portablegl_raster_state_test.cpp depth state), but none clears depth and then draws through a state with DepthBufferWriteEnable false.
Regression test
Clear depth, then draw a quad through a DepthStencilState with DepthBufferWriteEnable false and expect the depth buffer unchanged. The fix is to restore the depth mask after each of the four clears, as EasyGL does.
Blast radius
PORTABLEGL only (a CPU rasteriser renderer); games that clear depth and rely on read-only depth for a following pass.
Workaround
Re-apply the depth/stencil state after a clear that touches depth.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Graphics state: DepthStencilState
- Internals
- Renderer backends internals
- Known issues
- Bug index