fix(render): FW4 slice 2 - exit seals stamp the walk''s own flood
The cathedral falls shine-through (owner report at the #456 terrace seam, toggling with the camera''s side of the seam): the probe''s new phase tags pinned the falls emitters to the cell-owners route submitting POST-depth-clear on interior roots - retail''s own timing, safe only because seals own the aperture depth by the end-of-frame alpha drain. Our seal SET still came from the old apparatus''s flood, which misses exit portals at the #456 seam band (its never-drawn panel family), so the drain z-passed across the unsealed opening. DrawWalkExitPortalMasks now stamps the walk''s own ordered interior flood (WalkFrameDriver.InteriorFloodCells, captured at OnInteriorFloodDrawTurn - retail PView::DrawCells pc:432785-432786), keeping the old assembly''s per-cell slice clips where present and sealing unclipped where the old apparatus had no entry (benign: the exact dat aperture polygon, z-tested). The legacy path keeps the old seal draw. Also: ACDREAM_PROBE_WALK_ROOT gains [walk-part]/[walk-alpha] phase-tagged submission/drain lines (the apparatus that pinned this). Hermetic 6,762/0, Walk lane 213/1, InstalledDat walk conformance 40/1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
37febd1fe6
commit
c40aecfc8c
8 changed files with 136 additions and 4 deletions
|
|
@ -315,7 +315,7 @@ issue is closed, the strip was missed; delete both.
|
|||
| `ACDREAM_PROBE_CHILD_CELL` | c4 route 7 | `=1` | gates one `[child-cell]` line per Runtime committed-child canonical-cell write in `RuntimeLiveEntitySessionController`, `RuntimeEntityObjectLifetime`, `RuntimeEntityDirectory` (parent/child guid, old/new cell, cause tag) | print-only | `PhysicsDiagnostics.ProbeChildCellEnabled` |
|
||||
| `ACDREAM_PROBE_CLIPROUTE` | "throwaway apparatus — strip once §4 ships" | `=1` | print-on-change `[clip-route]` / `[clip-route-disp]` / `[clip-route-scis]` lines: outside-slice clip routing, region-SSBO bytes, terrain-UBO head, actual GL/RHI scissor state | print-only | `RenderingDiagnostics.ProbeClipRouteEnabled` |
|
||||
| `ACDREAM_PROBE_WALK_SHADOW` | Campaign FW3.2b-2 flip apparatus — dies with the flip commit | `=1` | runs the PRODUCTION retail frame walk per frame in SHADOW (no draws change) and prints one `[walk-shadow]` line per frame whose visited cell/building sets diverge from the old visibility path (the I5 dual-shadow pattern applied to the FW3 static cutover) | print-only; adds the per-frame CPU cost of the shadow walk while set | `RenderingDiagnostics.ProbeWalkShadowEnabled` |
|
||||
| `ACDREAM_PROBE_WALK_ROOT` | FW3 visual-gate apparatus (stairwell-transition defect) — dies with that fix | `=1` | after every interior/outdoor root flip, prints 8 `[walk-root]` lines (one per frame): viewer cell, root cell, camera-cell resolution, slice count, eye position, and the walk's visited cell list — pins which crossing frames root wrong or flood short | print-only | `RenderingDiagnostics.ProbeWalkRootEnabled` |
|
||||
| `ACDREAM_PROBE_WALK_ROOT` | FW3 visual-gate apparatus (stairwell-transition + cathedral-falls defects) — dies with those fixes | `=1` | after every interior/outdoor root flip, prints 8 `[walk-root]` lines (one per frame): viewer cell, root cell, camera-cell resolution, slice count, eye position, and the walk's visited cell list; also prints `[walk-part]` lines at every particle submission route (route name, owner ids, pre/post-depth-clear phase) and `[walk-alpha]` lines at every retail alpha-queue drain — together they pin which crossing frames root wrong, flood short, or submit particles after the interior depth clear | print-only; chatty near particle-heavy scenes while set | `RenderingDiagnostics.ProbeWalkRootEnabled` |
|
||||
| `ACDREAM_PROBE_CONTACT_PLANE` | spike-only, 2026-05-20 | `=1` | gates one `[cp-write]` line per write to `CollisionInfo.ContactPlane*`/`LastKnownContactPlane*` fields (field, old→new, caller method via stack walk, source line); only logs on actual value changes | print-only, but performs a stack walk to identify the caller method when firing — real CPU cost per write while on (not just a string format); suppresses no-op writes to bound volume | `PhysicsDiagnostics.ProbeContactPlaneEnabled` |
|
||||
| `ACDREAM_PROBE_ENT` | #138 | `="1"` | Traces the persistent player entity across teleport streaming churn: presence in the render draw-set flat view vs. survival of the dynamics cull, to distinguish "missing from draw set" vs "present but culled" | print-only, "Observation-only — emits no behavior change" (doc comment). `LogPlayerDynOnChange` dedupes by transition to avoid per-frame spam. Marked STRIP-once-root-caused (like the dense-town FPS apparatus). | `EntityVanishProbe.Enabled` (`EntityVanishProbe.cs:23-24`), issue #138-B |
|
||||
| `ACDREAM_PROBE_FLAP` | "throwaway apparatus — strip once the flap mechanism is confirmed" | `=1` | EVERY FRAME (unthrottled, not change-gated) while the camera root is indoor: `[flap]` from `PortalVisibilityBuilder.Build` (portal side-test/traverse/cull/projection) + paired `[flap-cam]` from `PhysicsCameraCollisionProbe`/`[flap-sweep]` (FindCameraCell resolution, eye positions) | print-only, but unthrottled per-frame `StringBuilder` allocation + `Console.WriteLine` on multiple call sites while indoor — heavy log volume/allocation under sustained indoor play; does not alter rendered output | `RenderingDiagnostics.ProbeFlapEnabled` |
|
||||
|
|
|
|||
|
|
@ -506,6 +506,26 @@ SEALS + cell slices still assemble from the old per-cell views (identical
|
|||
dat portal polygons; only the visible SET can differ), and interior-root
|
||||
look-in seeding still reads the old outside view.
|
||||
|
||||
**FW4 SLICE 2 — the walk-flood seal cutover (2026-08-30, pulled forward
|
||||
from the FW3 visual gate's cathedral round).** The owner's cathedral
|
||||
report (waterfall particles shining through from the terrace — toggling
|
||||
with which side of the #456 seam the CAMERA resolves to) probe-pinned via
|
||||
the `[walk-part]`/`[walk-alpha]` phase tags: the falls emitters ride the
|
||||
cell-owners route and submit POST-depth-clear on interior-rooted frames
|
||||
(retail's own timing — cell-scope alpha drains at the end-of-frame flush
|
||||
against seal-owned depth), but our seal SET still came from the old
|
||||
apparatus's flood, which misses exit portals at the #456 seam band (its
|
||||
never-drawn panel family) — unsealed aperture depth let the end-of-frame
|
||||
drain z-pass across the whole opening. `DrawWalkExitPortalMasks` now
|
||||
stamps THE WALK'S OWN ordered interior flood
|
||||
(`WalkFrameDriver.InteriorFloodCells`, captured at
|
||||
`OnInteriorFloodDrawTurn` — retail pc:432785-432786's reverse
|
||||
cell_draw_list), with the old assembly's per-cell slice clips where
|
||||
present and unclipped seals (benign: exact dat aperture polygon,
|
||||
z-tested) where the old apparatus had no entry. The legacy !walkActive
|
||||
path keeps the old seal draw. Suites: hermetic 6,762/0, Walk lane 213/1,
|
||||
InstalledDat walk conformance 40/1.
|
||||
|
||||
- Entities gate per view via `Render::viewconeCheck` at their cell's walk
|
||||
turn; dynamics-last and alpha interleave per the walk's stages
|
||||
(`RetailAlphaQueue` becomes the stream's alpha stage or is absorbed —
|
||||
|
|
|
|||
|
|
@ -266,7 +266,15 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
if (_submissionScratch.Count == 0)
|
||||
return;
|
||||
|
||||
if (renderPass == ParticleRenderPass.Scene && _alphaQueue?.IsCollecting == true)
|
||||
bool defers = renderPass == ParticleRenderPass.Scene && _alphaQueue?.IsCollecting == true;
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkRootEnabled)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"[walk-part] finish pass={renderPass} n={_submissionScratch.Count} "
|
||||
+ $"branch={(defers ? "defer" : "immediate")} "
|
||||
+ $"phase={AcDream.Core.Rendering.RenderingDiagnostics.WalkRootPhase}");
|
||||
}
|
||||
if (defers)
|
||||
DeferToRetailAlphaQueue(camera);
|
||||
else
|
||||
DrawOrdered(camera);
|
||||
|
|
|
|||
|
|
@ -146,6 +146,12 @@ internal sealed class RetailAlphaQueue : IWorldSceneAlphaFrame
|
|||
{
|
||||
if (!IsCollecting)
|
||||
throw new InvalidOperationException("Retail alpha flush requires an active frame.");
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkRootEnabled && _submissions.Count > 0)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"[walk-alpha] flush n={_submissions.Count} "
|
||||
+ $"phase={AcDream.Core.Rendering.RenderingDiagnostics.WalkRootPhase}");
|
||||
}
|
||||
|
||||
Exception? drawFailure = null;
|
||||
List<Exception>? resetFailures = null;
|
||||
|
|
|
|||
|
|
@ -180,6 +180,8 @@ internal sealed partial class RetailPViewPassExecutor :
|
|||
public void BeginFrame()
|
||||
{
|
||||
_particleClassifications.BeginFrame();
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkRootEnabled)
|
||||
AcDream.Core.Rendering.RenderingDiagnostics.WalkRootPhase = "pre";
|
||||
}
|
||||
|
||||
/// <summary>Campaign FW3.2b-2: the shared dispatcher, for
|
||||
|
|
@ -510,6 +512,7 @@ internal sealed partial class RetailPViewPassExecutor :
|
|||
DisableClipDistances();
|
||||
|
||||
_particleClassifications.ReplaceOutdoor(context.ParticleOwnerIds);
|
||||
ProbeWalkParticleRoute("static-owners", _particleClassifications.Outdoor);
|
||||
if (_particleClassifications.Outdoor.Count > 0
|
||||
&& _particles is not null
|
||||
&& _particleRenderer is not null)
|
||||
|
|
@ -569,7 +572,12 @@ internal sealed partial class RetailPViewPassExecutor :
|
|||
DisableClipDistances();
|
||||
}
|
||||
|
||||
public void ClearInteriorDepth() => _surface.ClearInteriorDepth();
|
||||
public void ClearInteriorDepth()
|
||||
{
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkRootEnabled)
|
||||
AcDream.Core.Rendering.RenderingDiagnostics.WalkRootPhase = "post";
|
||||
_surface.ClearInteriorDepth();
|
||||
}
|
||||
|
||||
public void DrawExitPortalMask(
|
||||
RetailPViewFrameInput frame,
|
||||
|
|
@ -598,6 +606,8 @@ internal sealed partial class RetailPViewPassExecutor :
|
|||
// hardware clip slot made effects vanish by view direction (zero
|
||||
// outside slices in view = zero submissions) — invented behavior.
|
||||
DisableClipDistances();
|
||||
ProbeWalkParticleRoute(
|
||||
outdoorCells ? "unattached-outdoor" : "unattached-interior", null);
|
||||
_particleRenderer.DrawForOwners(
|
||||
frame.Camera,
|
||||
frame.CameraWorldPosition,
|
||||
|
|
@ -610,6 +620,30 @@ internal sealed partial class RetailPViewPassExecutor :
|
|||
: UnattachedEmitterCellScope.InteriorCells);
|
||||
}
|
||||
|
||||
/// <summary>ACDREAM_PROBE_WALK_ROOT companion (throwaway, dies with the
|
||||
/// cathedral falls investigation): logs each particle submission route
|
||||
/// with its owner count + the pre/post-depth-clear phase tag.</summary>
|
||||
private static void ProbeWalkParticleRoute(string route, IReadOnlySet<uint>? owners)
|
||||
{
|
||||
if (!AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkRootEnabled)
|
||||
return;
|
||||
string ids = "";
|
||||
if (owners is not null)
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
int shown = 0;
|
||||
foreach (uint id in owners)
|
||||
{
|
||||
if (shown++ == 6) { sb.Append(",…"); break; }
|
||||
if (sb.Length > 0) sb.Append(',');
|
||||
sb.Append(id.ToString("x"));
|
||||
}
|
||||
ids = $" n={owners.Count} ids=[{sb}]";
|
||||
}
|
||||
Console.WriteLine(
|
||||
$"[walk-part] {route}{ids} phase={AcDream.Core.Rendering.RenderingDiagnostics.WalkRootPhase}");
|
||||
}
|
||||
|
||||
public void FlushLandscapeAlpha() => _alpha.Flush();
|
||||
|
||||
public void FlushLandscapeAlphaFartherThan(float minViewerDistance) =>
|
||||
|
|
@ -633,6 +667,7 @@ internal sealed partial class RetailPViewPassExecutor :
|
|||
return;
|
||||
|
||||
DisableClipDistances();
|
||||
ProbeWalkParticleRoute("cell-owners", visible);
|
||||
// Retail never clips cell particles to a portal view: the owner
|
||||
// cell's walls own occlusion via the depth test at the alpha flush.
|
||||
_particleRenderer.DrawForOwners(
|
||||
|
|
@ -658,6 +693,7 @@ internal sealed partial class RetailPViewPassExecutor :
|
|||
return;
|
||||
|
||||
DisableClipDistances();
|
||||
ProbeWalkParticleRoute("dyn-owners", dynamics);
|
||||
_particleRenderer.DrawForOwners(
|
||||
frame.Camera,
|
||||
frame.CameraWorldPosition,
|
||||
|
|
|
|||
|
|
@ -333,8 +333,11 @@ public sealed class RetailPViewRenderer
|
|||
passes.FlushLandscapeAlpha();
|
||||
passes.ClearInteriorDepth();
|
||||
};
|
||||
// FW4 slice 2: the seals stamp the WALK'S OWN flood cells (see
|
||||
// DrawWalkExitPortalMasks). walkDriver is assigned below, before
|
||||
// any Replay can fire this closure.
|
||||
Action drawExitSeals = () =>
|
||||
DrawExitPortalMasks(ctx, passes, pvFrame, clipAssembly, drawableCells);
|
||||
DrawWalkExitPortalMasks(ctx, passes, clipAssembly, walkDriver!);
|
||||
|
||||
var leafRenderer = new WalkProductionLeafRenderer(
|
||||
walkExecutor!, ctx, clipAssembly, clearInteriorDepth, drawExitSeals);
|
||||
|
|
@ -2035,6 +2038,39 @@ public sealed class RetailPViewRenderer
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>Campaign FW4 slice 2 — the walk-flood seal draw. Retail's
|
||||
/// <c>PView::DrawCells</c> stamps every exit portal of THE FLOOD'S OWN
|
||||
/// cells (pc:432785-432786, reverse cell_draw_list far→near) — one
|
||||
/// visibility structure decides the flood, the seals, and the terrain
|
||||
/// views alike. The old apparatus's flood misses exit portals at the
|
||||
/// #456 cathedral seam band (its never-drawn panel family), leaving
|
||||
/// aperture depth unsealed after the interior clear; the end-of-frame
|
||||
/// alpha drain (cell-owned emitters — retail's own timing) then
|
||||
/// z-passes across the whole opening (the falls shine-through,
|
||||
/// probe-pinned via ACDREAM_PROBE_WALK_ROOT's phase tags). Per-cell
|
||||
/// slice clips still come from the old assembly where present; a cell
|
||||
/// the old apparatus missed seals unclipped (the depth fan is the exact
|
||||
/// dat aperture polygon and z-tests, so over-coverage is benign).</summary>
|
||||
private void DrawWalkExitPortalMasks(
|
||||
RetailPViewFrameInput ctx,
|
||||
IRetailPViewPassExecutor passes,
|
||||
ClipFrameAssembly clipAssembly,
|
||||
Walk.WalkFrameDriver driver)
|
||||
{
|
||||
List<uint> floodCells = driver.InteriorFloodCells;
|
||||
for (int i = floodCells.Count - 1; i >= 0; i--)
|
||||
{
|
||||
uint cellId = floodCells[i];
|
||||
foreach (var slice in GetCellSlicesOrNoClip(clipAssembly, cellId))
|
||||
passes.DrawExitPortalMask(
|
||||
ctx,
|
||||
new RetailPViewCellSliceContext(
|
||||
cellId,
|
||||
slice,
|
||||
NoParticleOwners));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEnvCellShells(
|
||||
IRetailPViewPassExecutor passes,
|
||||
PortalVisibilityFrame pvFrame)
|
||||
|
|
|
|||
|
|
@ -386,6 +386,17 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
// walk pass dedicated to nothing but set-gathering.
|
||||
internal HashSet<uint> VisitedCells { get; } = new();
|
||||
|
||||
/// <summary>FW4 slice 2: the interior root's ORDERED flood cell list,
|
||||
/// exactly as retail's <c>PView::DrawCells</c> iterates it for the
|
||||
/// exit-portal seals (pc:432785-432786) — captured at
|
||||
/// <see cref="IWalkEventSink.OnInteriorFloodDrawTurn"/>. Empty for an
|
||||
/// outdoor-rooted frame. The production seal draw iterates THIS list
|
||||
/// (the walk's own flood), not the old visibility apparatus's — at the
|
||||
/// #456 seam band the old builder's flood misses exit portals the walk
|
||||
/// provably floods, leaving unsealed aperture depth the end-of-frame
|
||||
/// alpha drain splats through (the cathedral falls shine-through).</summary>
|
||||
internal List<uint> InteriorFloodCells { get; } = new();
|
||||
|
||||
internal List<WalkBuilding> VisitedBuildings { get; } = new();
|
||||
|
||||
internal HashSet<uint> VisitedLandscapeCellIds { get; } = new();
|
||||
|
|
@ -498,6 +509,7 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
VisitedCells.Clear();
|
||||
VisitedBuildings.Clear();
|
||||
VisitedLandscapeCellIds.Clear();
|
||||
InteriorFloodCells.Clear();
|
||||
}
|
||||
|
||||
/// <summary>Records the final segment mark (plan §FW3.2b-1's "at frame
|
||||
|
|
@ -691,6 +703,13 @@ internal sealed class WalkFrameDriver : IWalkEventSink
|
|||
MarkIfGrown();
|
||||
_events.Add(WalkFrameEvent.ExitSeals());
|
||||
|
||||
// FW4 slice 2: retain the ordered flood for the seal draw (the
|
||||
// DrawExitSeals leaf runs at Replay, when Collect has long filled
|
||||
// this) — see the property's own doc comment.
|
||||
InteriorFloodCells.Clear();
|
||||
for (int i = 0; i < cells.Count; i++)
|
||||
InteriorFloodCells.Add(cells[i]);
|
||||
|
||||
for (int i = 0; i < cells.Count; i++)
|
||||
EmitCellTurn(WalkDrawStage.CellStatic, cells[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,13 @@ public static class RenderingDiagnostics
|
|||
public static bool ProbeWalkRootEnabled { get; set; } =
|
||||
Environment.GetEnvironmentVariable("ACDREAM_PROBE_WALK_ROOT") == "1";
|
||||
|
||||
/// <summary>Companion scratch for <see cref="ProbeWalkRootEnabled"/>
|
||||
/// (throwaway, same investigation): the frame phase relative to the
|
||||
/// interior depth clear ("pre"/"post"), stamped by the pass executor so
|
||||
/// particle/alpha probe lines can tag WHEN a submission or drain ran.
|
||||
/// Written only while the probe is on.</summary>
|
||||
public static string WalkRootPhase = "";
|
||||
|
||||
/// <summary>
|
||||
/// Bounded-propagation port apparatus (2026-06-08). When true, PortalVisibilityBuilder.Build emits
|
||||
/// one [portal-churn] summary line per call: per-cell pop count (re-pops = churn), total re-enqueues,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue