Skip to content

PostProcessingEffects renders a garbage frame when FXAA is enabled over GraphicsCompositorHelper.CreateDefault (disabled private range passes leave FXAA reading an unwritten render target) #3316

Description

@jpenberthy

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

  1. Code-only game, GraphicsCompositorHelper.CreateDefault(enablePostEffects: true).
  2. post.Antialiasing = new FXAAEffect { Enabled = true };
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions