`PostProcessingEffects` renders a garbage frame when FXAA is enabled over `GraphicsCompositorHelper.CreateDefault` (disabled private range passes leave FXAA reading an unwritten render target)
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 7.8k
- Forks
- 1.2k
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 49
Description
Release Type: Official Release
Version: 4.3.0.2507
Platform(s): All backends (verified Vulkan + D3D11); code-only compositor path
Describe the bug
CreateDefault(enablePostEffects: true) calls PostProcessingEffects.DisableAll(), which also
disables the private rangeCompress/rangeDecompress passes — and nothing can re-enable
them (no public accessor). DrawCore then chooses the "anti-alias before bloom" branch based on
bool stableBloom = Bloom != null && Bloom.StableConvolution; // Bloom.Enabled is NOT consulted
StableConvolution defaults to true, so the branch is taken even with bloom disabled. Inside
it, rangeCompress.Draw() is a no-op (disabled renderers draw nothing, not even a blit), FXAA
reads the unwritten scoped render target, and currentInput = compressed; discards the real
scene. Everything downstream runs on allocator garbage.
To Reproduce
- Code-only game,
GraphicsCompositorHelper.CreateDefault(enablePostEffects: true). post.Antialiasing = new FXAAEffect { Enabled = true };- Frame is garbage/black. Measured on a fixed camera: mean frame luma 0.4775 → 0.0755 with
FXAA as the only change.
Expected behavior
FXAA over the default compositor antialiases the frame.
Additional context / workaround
One-line app-side workaround (verified: luma unchanged 0.4784 → 0.4807; edge-aliasing metrics
−39% to −52%): set post.Bloom.StableConvolution = false before enabling FXAA — that selects
the other DrawCore branch, which doesn't touch the disabled private passes. Upstream fix
shapes (any one suffices): gate the branch on Bloom.Enabled && Bloom.StableConvolution; have
DrawCore enable the range passes it is about to use (they're private plumbing — their
Enabled flag is meaningless as public state); or make DisableAll() leave them alone. A
defensive log/throw on drawing a disabled internal pass would have made this a one-line
diagnosis instead of a silent black frame. Happy to PR.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at GraphicsCompositorHelper.CreateDefault and trace PostProcessingEffects.DisableAll into DrawCore, focusing on the private rangeCompress and rangeDecompress passes and the stable-bloom branch. Reproduce with FXAA enabled and bloom left at its default, then verify that the default compositor produces a valid antialiased frame rather than reading an unwritten render target.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- computer-graphics, game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100