fix(render): §4 outdoor full-world flap — empty Transparent pass leaked DepthMask(false), no-oping the frame depth clear
ROOT CAUSE (pinned by the [clip-route] probe run + [gl-state] tripwire, one capture): EnvCellRenderer.RenderModernMDIInternal established the Transparent pass state (Enable(Blend) + DepthMask(false)) BEFORE the batch pass-filter, so a cell whose batches are ALL opaque (a plain cottage interior) hit the totalDraws==0 early-out and returned without ever reaching the end-of-pass restore. The frame ended with dmask=0 + blend=1; the NEXT frame's glClear(GL_DEPTH_BUFFER_BIT) silently no-oped (depth clears honor glDepthMask), and every world fragment — terrain, entities, player, sky — failed GL_LESS against its own previous-frame depth ghost. Screen = the fog-tinted clear color. Onset locks to the building-flood merge because that is the first frame the flooded building shell draws; holds while merged (the leak re-arms every frame); camera rotation recovers because the cell drops from the flood and the restore-skipping path stops running. Capture evidence (flap-cliproute-capture.log): all three draw-input suspects exonerated — landscape scissor full-screen all run, terrain-UBO/region-SSBO planes full-screen on both sides of every merge, all 41,373 instances on the correct repacked slot with cullEnt=0 — while [gl-state] showed frames entering with dmask=0 blend=1 for exactly the merged stretches (145,238 consecutive frames in the held window, flipping with each merge boundary at the end-of-run strobe cycles). Fix (all paths root-cause, no suppression): - EnvCellRenderer: move the pass-state establish BELOW the totalDraws==0 early-out so state is only set on a path that always reaches the restore; hoist the globalVao==0 check (the second leak-shaped early-out) above the state set. - GameWindow frame clear: assert DepthMask(true) before glClear — the clear DEPENDS on the depth write mask, so it sets the state it depends on (feedback_render_self_contained_gl_state; this is the 4th instance of the class, in the same function as the 1st). Very likely the same family as the "parts of the screen flash while running past cottages" and cottage enter/exit artifacts (every brief merge = a 1-frame no-op depth clear). Visual gate pending. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
682cba36f1
commit
c4df241690
2 changed files with 47 additions and 23 deletions
|
|
@ -7093,6 +7093,15 @@ public sealed class GameWindow : IDisposable
|
|||
System.Math.Clamp(fogColor.Z, 0f, 1f),
|
||||
1f);
|
||||
|
||||
// §4 outdoor full-world flap (2026-06-10): the depth clear DEPENDS on the depth
|
||||
// write mask — glClear(GL_DEPTH_BUFFER_BIT) is silently gated by glDepthMask.
|
||||
// A pass that leaked DepthMask(false) at frame end (EnvCellRenderer's empty
|
||||
// Transparent pass, fixed same-day) turned this clear into a no-op and the whole
|
||||
// world failed GL_LESS against its own previous-frame depth ghost. Per
|
||||
// feedback_render_self_contained_gl_state: the clear site asserts the state it
|
||||
// depends on rather than inheriting it. The [gl-state] tripwire still detects
|
||||
// any future leak.
|
||||
_gl.DepthMask(true);
|
||||
_gl!.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
|
||||
|
||||
// WB GameScene.cs:830-843 establishes CW as the frame-global
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue