[NOM-5453] Fix depth handling when chaining passes with different sample counts - #195
Open
LukPopp0 wants to merge 4 commits into
Open
[NOM-5453] Fix depth handling when chaining passes with different sample counts#195LukPopp0 wants to merge 4 commits into
LukPopp0 wants to merge 4 commits into
Conversation
added 2 commits
August 17, 2026 12:38
The generalized sample-count fix (#184) allocates a fresh buffer on a mismatch but then lets _PrepareBuffersFromInputs copy the resolved depth into it. That copy binds the depth texture as a float-sampled texture in the fullscreen copy shader, which WebGPU rejects (depth is Depth/UnfilterableFloat) - producing an invalid bind group and a blank frame. Metal tolerates it, so it only broke on web. Skip the depth copy on a mismatch, as the original depth-specific change did: the fresh MSAA depth buffer is left uninitialised and the overlay clears it before drawing. Color priming is unaffected.
Adds TestMsaaChainedPassResolvedToMsaa, TestMsaaChainedPassMsaaToResolved and TestMsaaChainedPassMatchingSampleCount to cover the render buffers a frame pass ends up drawing into when it is chained after a pass with a different multisample state. The tests assert the buffer allocation rather than comparing images, so they need no baselines: attaching buffers of differing sample counts is invalid, but backends disagree on whether they reject it, tolerate it, or render something plausible. Each mismatch case checks that the second pass allocated its own buffers at its own sample count, and the matching case guards against the mismatch detection allocating buffers the passes could have shared.
hodoulp
approved these changes
Aug 18, 2026
Skipping the copy left the freshly allocated depth buffer with no initialisation at all, so the chained pass depth-tested against undefined contents on the first frame and after every resize. Give the depth AOV its default clear value in exactly that case: a fresh buffer that received neither a copy nor pre-existing depth. Also narrow the skip back to the same-renderer case. With the clear in place, the multisample-mismatch term only affected chaining across different render delegates, where the resolved copy remains the only mechanism carrying depth between them. Minor test tidy-ups: drop a dead initialiser and a tautological assertion in testMultiSampling.cpp.
Contributor
|
As human reviewer, the code is fine & the logic is improved and unit tests validate the fix. That's fine. |
The clear added for the skipped depth copy was driven by the multisample mismatch alone, but the fresh buffer it was meant for is only allocated when the input bindings or output tokens also changed. A pass that toggles its own MSAA setting while its bindings stay identical hits the mismatch without allocating anything, and the clear then landed on the buffer it is still sharing with the previous pass. Gate the clear on the pass actually owning an output buffer for that AOV. Also record the two limitations the code left implicit: chaining across render delegates still copies the depth, so it still binds it as a sampled texture and can still fail on WebGPU, and the buffer sharing rules in docs/renderbuffermgr.md never mentioned the same-renderer or matching-sample-count requirements, nor that a same-renderer mismatch now discards the previous pass's depth instead of copying it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
A buffer that was freshly allocated and then got no copy has no initialization at all, so the depth AOV takes its default clear value in that one case. The clear is additionally gated on this pass owning an output buffer for that AOV, because the mismatch and the allocation are decided by different conditions: the allocation is skipped when the input bindings and output tokens are unchanged, so without the ownership test the clear would land on the buffer still shared with the previous pass.
In
RenderBufferManager::Impl::SetRenderOutputs, the same-renderer test is hoisted into its own local so the depth decision can be stated directly:A buffer that was freshly allocated and then got no copy has no initialization at all, so the depth AOV takes its default clear value in that one case:
Changes Made
Behavior change
In the same-renderer, mismatched-sample-count case the previous pass's depth is now discarded rather than copied forward, so geometry in the second pass is no longer occluded by geometry from the first. This is intended for overlay passes such as the ViewCube, and is what docs/renderbuffermgr.md now describes.
Known limitations
Testing
Test Configuration
Tests Performed
Documentation
Checklist