feat(render): Phase A8 Wave 5 — probe trail ([envcells]/[stencil]/[draworder]/[buildings])

Probe emitters wired (replaces the Task 8 stubs). All gated on
ACDREAM_PROBE_VIS=1 (everything) or ACDREAM_PROBE_ENVCELL=1
([envcells] only):

- [envcells] frame=N cells=N tris=N ourBldgs=N otherBldgs=N filterCnt=N
  Fires once per Render call inside RenderInsideOutAcdream Step 3.
  Reads CellsRendered + TrianglesDrawn from EnvCellRenderer.Stats.

- [stencil] op={mark|punch} bld=0xHHHHHHHH verts=N
  Fires after every IndoorCellStencilPipeline.RenderBuildingStencilMask
  call (Steps 1, 2, 5a, 5b, 5d) — surfaces LastStencil* probe fields
  added in Wave 1's Task 7 extension.

- [draworder] frame=N step=Xy stencil={on|off} depthFn=0xHHH depthMask={true|false}
  Fires at each step boundary (entry to Step 1/2/3/4/5{a,b,c,d}).
  Reads live GL state via glGetInteger so divergence between assumed
  vs actual state is immediately visible.

- [buildings] camCell=0xHHHHHHHH camBldgs=[0x1,0x2,...] otherBldgs=N totalKnown=N
  Fires once per indoor frame at the top of RenderInsideOutAcdream.
  totalKnown sums BuildingRegistry.Count across all loaded landblocks.

Per-frame counter _phaseA8DrawOrderFrame incremented once per render
tick after the existing [vis] probe block (line 7104).

New env-var flag ACDREAM_PROBE_ENVCELL in RenderingDiagnostics +
ProbeEnvCellEnabled property (true OR ProbeVisibilityEnabled).

Mandatory acceptance criteria (process rule "no visual-gate launch
without probe data first") to check FROM the log BEFORE asking the
user for visual verification:
  - [buildings] camBldgs=[0x...] non-empty when inside a cottage
  - [envcells] cells>=1 tris>=1 filterCnt>=1 for at least one indoor frame
  - [stencil] op=mark verts>0 fires per camera-building
  - [draworder] shows the full Step 1 → 2 → 3 → 4 → 5{a,b,c,d} cycle

Build green. 82/82 App.Tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-27 15:14:45 +02:00
parent f9a644a366
commit 8532c84f57
2 changed files with 81 additions and 5 deletions

View file

@ -7138,6 +7138,10 @@ public sealed class GameWindow : IDisposable
$"cell=0x{cellId} visN={visCount} {visList}");
}
// Phase A8 Task 9: increment the [draworder] frame counter once per render
// tick. Used by EmitDrawOrderProbe to attribute step transitions to a frame.
_phaseA8DrawOrderFrame++;
// Lighting decisions (sun zeroed, indoor ambient applied) must
// track the PLAYER's cell, not the camera's. In third-person
// chase mode the camera enters interiors before the player body
@ -10760,14 +10764,69 @@ public sealed class GameWindow : IDisposable
}
}
// ── Phase A8 probe stubs (Task 9 wires these up with real output) ────────
// ── Phase A8 Task 9 (2026-05-28): probe trail for RenderInsideOutAcdream ──
//
// Mandatory diagnostic infrastructure per the post-RR7 process rule
// "no visual-gate launch without probe data first" (handoff doc
// 2026-05-27-a8-rr7-reverted-wb-port-handoff.md).
//
// Gating:
// [envcells] — ACDREAM_PROBE_VIS=1 OR ACDREAM_PROBE_ENVCELL=1
// [stencil] — ACDREAM_PROBE_VIS=1
// [draworder] — ACDREAM_PROBE_VIS=1
// [buildings] — ACDREAM_PROBE_VIS=1
//
// Acceptance criteria (read these FROM the launch log BEFORE asking
// the user for visual verification):
// - [buildings] camBldgs=[0x...] non-empty when inside a cottage
// - [envcells] cells>=1 tris>=1 filterCnt>=1 for at least one indoor frame
// - [stencil] op=mark verts>0 fires per camera-building
// - [draworder] shows steps 1 → 2 → 3 → 4 → 5{a,b,c,d} per indoor frame
private int _phaseA8DrawOrderFrame = 0;
private void EmitDrawOrderProbe(int step, char sub)
{
if (!AcDream.Core.Rendering.RenderingDiagnostics.ProbeVisibilityEnabled) return;
_gl!.GetInteger(Silk.NET.OpenGL.GLEnum.StencilTest, out int stOn);
_gl!.GetInteger(Silk.NET.OpenGL.GLEnum.DepthFunc, out int depthFn);
_gl!.GetBoolean(Silk.NET.OpenGL.GLEnum.DepthWritemask, out var depthMask);
string subStr = sub == ' ' ? "" : sub.ToString();
Console.WriteLine(
$"[draworder] frame={_phaseA8DrawOrderFrame} step={step}{subStr} " +
$"stencil={(stOn != 0 ? "on" : "off")} depthFn=0x{depthFn:X} depthMask={depthMask}");
}
private void EmitEnvCellProbe(int ourBldgs, int otherBldgs, int filterCnt)
{
if (!AcDream.Core.Rendering.RenderingDiagnostics.ProbeEnvCellEnabled) return;
var stats = _envCellRenderer?.Stats ?? default;
Console.WriteLine(
$"[envcells] cells={stats.CellsRendered} tris={stats.TrianglesDrawn} " +
$"ourBldgs={ourBldgs} otherBldgs={otherBldgs} filterCnt={filterCnt}");
}
private void EmitStencilProbe(string op)
{
if (!AcDream.Core.Rendering.RenderingDiagnostics.ProbeVisibilityEnabled) return;
if (_indoorStencilPipeline is null) return;
Console.WriteLine(
$"[stencil] op={op} bld=0x{_indoorStencilPipeline.LastStencilBuildingId:X8} " +
$"verts={_indoorStencilPipeline.LastStencilVertexCount}");
}
private void EmitDrawOrderProbe(int step, char sub) { /* Task 9 */ }
private void EmitEnvCellProbe(int ourBldgs, int otherBldgs, int filterCnt) { /* Task 9 */ }
private void EmitStencilProbe(string op) { /* Task 9 */ }
private void EmitBuildingsProbe(uint visibilityCellId,
System.Collections.Generic.List<AcDream.App.Rendering.Wb.Building> camBldgs,
System.Collections.Generic.List<AcDream.App.Rendering.Wb.Building> otherBldgs) { /* Task 9 */ }
System.Collections.Generic.List<AcDream.App.Rendering.Wb.Building> otherBldgs)
{
if (!AcDream.Core.Rendering.RenderingDiagnostics.ProbeVisibilityEnabled) return;
var ids = string.Join(",", camBldgs.ConvertAll(b => $"0x{b.BuildingId:X}"));
int totalKnown = 0;
foreach (var r in _buildingRegistries.Values) totalKnown += r.Count;
Console.WriteLine(
$"[buildings] camCell=0x{visibilityCellId:X8} " +
$"camBldgs=[{ids}] otherBldgs={otherBldgs.Count} totalKnown={totalKnown}");
}
// ────────────────────────────────────────────────────────────────────────────

View file

@ -86,6 +86,23 @@ public static class RenderingDiagnostics
public static bool ProbeVisibilityEnabled { get; set; } =
Environment.GetEnvironmentVariable("ACDREAM_PROBE_VIS") == "1";
private static bool _probeEnvCellEnabled =
Environment.GetEnvironmentVariable("ACDREAM_PROBE_ENVCELL") == "1";
/// <summary>
/// Phase A8 Task 9 (2026-05-28): when true, RenderInsideOutAcdream's
/// <c>[envcells]</c> probe emits one line per indoor frame —
/// CellsRendered / TrianglesDrawn from <see cref="AcDream.App.Rendering.Wb"/>'s
/// <c>EnvCellRenderer.Stats</c> + ourBldgs/otherBldgs/filterCnt.
/// Also enabled implicitly when <see cref="ProbeVisibilityEnabled"/> is true.
/// Initial state from <c>ACDREAM_PROBE_ENVCELL=1</c>.
/// </summary>
public static bool ProbeEnvCellEnabled
{
get => _probeEnvCellEnabled || ProbeVisibilityEnabled;
set => _probeEnvCellEnabled = value;
}
/// <summary>
/// Master toggle. Reading reflects the AND of all five flags
/// (true only when every probe is on). Writing cascades — setting