From d5fd08f40c2aad59816072dc78b25631104d4029 Mon Sep 17 00:00:00 2001 From: James Dansereau <106631954+jkdansereau@users.noreply.github.com> Date: Wed, 16 Sep 2026 18:10:43 -0400 Subject: [PATCH] D288: frame-gate the GE_D288 probe, re-run, still inconclusive Gated GE_D288 to num_dls 550-755 (the reported bug window, same pattern GE_D236RM already uses) and raised the bbox threshold from 0.15 to 0.5. Volume dropped 116k -> 28,883, but that's still not the isolated signal -- traced the remaining noise to a bad assumption in the probe itself: bbox_frac from a raw x/w divide is meaningless once any_behind_camera=1 (w<0 or near-zero), which is exactly why the surrounding D233 code already defers to GL's own clipper for that case rather than trusting the divide. Restricting to any_behind_camera=0 (2,128 hits) still found no match for the target color (83,62,44); the persistent hits across the window look like static level geometry, not the transient bug triangle. Working theory: the bare -level_20 boot's scripted intro camera may not reach the same state the original visual bug report came from -- the same "deterministic boot flag != deterministic camera path" pattern this session's D236 passes independently hit on a different level. Recorded a revised next-step list in findings.md; a live human repro is now more promising than further headless probing of this specific approach. No src/game changes. findings-index.csv regen was a no-op. --- docs/dev/findings.md | 4 +++- port/fast3d/gfx_pc.cpp | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/docs/dev/findings.md b/docs/dev/findings.md index dacbe1cb..878938b2 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -11075,7 +11075,9 @@ if that's recorded anywhere in the D280 write-up above. - **Next, concrete:** gate the probe to the actual bug window before re-running — extend `GE_D288` with a `num_dls` (frame counter) check bounding it to roughly 560-745 (same pattern `GE_D236RM` already uses for its own frame gating, `gfx_pc.cpp` ~line 1648), and/or tighten the bbox threshold well above the apparent ~0.15 "normal" baseline this run established. Confirm the correct `GE_PCDUMP` output-directory env var (see `docs/dev/GE-ENV-PROBES.md`'s `GE_PCDUMP` row) before relying on visual frame dumps again. - **Environment note, reinforcing the existing one:** the launched `ge007.x86_64.exe` process does **not** reliably die with `pkill -f ge007.x86_64.exe` from this Bash tool (process shows in `ps aux` as bare `ge007.x86_64`, no `.exe` suffix) — a stray instance ran ~90s longer than intended this session before being caught via `taskkill //F //IM ge007.x86_64.exe`. Use `taskkill //F //IM ge007.x86_64.exe` (not `pkill`) to reliably terminate a backgrounded launch from this shell. -**Status (from §F table):** OPEN — visually confirmed and precisely bounded (frames ~562-741 of a bare `-level_20` boot); M-152 narrowed to two live candidates (fast3d backface-cull NaN leak, or the D106/D271 portal-BFS family) via static review; M-155's probe run was inconclusive (probe not frame-gated, fires too broadly to isolate the signal) — root cause still not identified. A frame-gated `GE_D288` re-run is the next concrete step. Promoted from the long-parked `GRAPHICS-BACKLOG.md` D171 entry with real evidence. +**M-155 follow-up (same session): frame-gated re-run also inconclusive — bbox_frac is not a meaningful signal when `any_behind_camera=1`.** Gated `GE_D288` to `num_dls` 550-755 (matching the reported window) and raised the threshold to `bbox_frac > 0.5`, then re-ran the same 25s bare `-level_20` boot. Volume dropped from 116k to 28,883 hits — still far too many to be the single reported triangle. Root cause of the remaining noise: for `any_behind_camera=1` triangles (a vertex behind the camera plane, `w<0`), the perspective-divide math `x/w` this probe uses to estimate screen coverage is **not meaningful in the first place** — dividing by a near-zero or negative `w` produces arbitrarily large/nonsensical "bbox_frac" values for perfectly ordinary near-camera geometry, which is exactly why the surrounding code already defers to GL's own clipper for these triangles rather than trusting a raw NDC divide (see the D233 comment just above this block). This isn't evidence of the bug; it's the probe's own math breaking down in a case it was never valid for. Restricting to `any_behind_camera=0` (2,128 of the 28,883 hits) still found **no match for the target color** `(83,62,44)`; the largest/most persistent hits (`(82,94,89)`, `(70,70,70)`, repeating identically across every sampled frame in the window) look like static level geometry, not the transient grow/shrink/vanish triangle. **Working theory, unconfirmed:** the bare `-level_20` boot's scripted intro camera may not reach the same in-game state the visual bug report was captured from — the same "deterministic boot flag ≠ deterministic/representative camera path" caveat this session's D236 passes (10/11) independently ran into on a different level. **Confidence: unchanged, LOW-MEDIUM; probe volume is now sane but still hasn't isolated the signal.** **Next, concrete, revised:** (1) restrict the probe to `any_behind_camera==0` only (the `w<0` case needs a different, GL-clip-aware approach or should be dropped entirely as a false lead); (2) get a real `GE_PCDUMP` PPM capture working (confirm the output-dir env var) to visually confirm which `num_dls`/frame the boot's camera is actually at when the bug is visible, rather than assuming the frame-range label transfers directly to `num_dls`; (3) if headless deterministic-boot probing keeps missing it, this may need a live human repro with `GE_PCDUMP`/F12 at the moment the triangle is visible, same as D290's falsifier plan. + +**Status (from §F table):** OPEN — visually confirmed and precisely bounded (frames ~562-741 of a bare `-level_20` boot); M-152 narrowed to two live candidates (fast3d backface-cull NaN leak, or the D106/D271 portal-BFS family) via static review; two M-155 probe runs (ungated, then frame-gated) were both inconclusive — the `any_behind_camera=1` case's bbox math is a false lead, and the `any_behind_camera=0` subset found no match for the target color. Root cause still not identified; a live human repro is now the more promising next step over further headless probing. Promoted from the long-parked `GRAPHICS-BACKLOG.md` D171 entry with real evidence. ## D289 — Dam: a crash in the computer room, not reproducible on a second attempt (M-141, Steam Deck user playtest). diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 79a39d4e..b3c932bf 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -1614,25 +1614,35 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo return; } - /* D288 diag (M-152): the silo intro's screen-filling stray triangle - * (bounded to level_20 frames ~562-741) isn't explained by this - * function's existing D233/D106 guards on static review -- log any - * triangle whose clip-space NDC bbox covers an unreasonable chunk - * of the screen, or whose bbox math goes non-finite, together with - * each vertex's w and any_behind_camera, to catch it at draw time. - * Remove once D288 is root-caused. */ + /* D288 diag (M-152, frame-gated M-155): the silo intro's + * screen-filling stray triangle (bounded to level_20 frames + * ~562-741) isn't explained by this function's existing D233/D106 + * guards on static review -- log any triangle whose clip-space NDC + * bbox covers an unreasonable chunk of the screen, or whose bbox + * math goes non-finite, together with each vertex's w and + * any_behind_camera, to catch it at draw time. M-155: the first + * ungated run fired 116k times in ~1500-2000 frames -- bbox_frac + * >0.15 alone is a common occurrence for ordinary near-camera + * geometry, not a distinguishing signature. Gated to the reported + * frame window (num_dls, same pattern as GE_D236RM below) and the + * threshold raised well above the ~0.15 "normal" baseline M-155 + * established, so a hit here is actually rare. Remove once D288 is + * root-caused. */ static int ge_d288 = -1; if (ge_d288 < 0) ge_d288 = getenv("GE_D288") != NULL; if (ge_d288) { - float minx = std::fmin(std::fmin(v1->x / v1->w, v2->x / v2->w), v3->x / v3->w); - float maxx = std::fmax(std::fmax(v1->x / v1->w, v2->x / v2->w), v3->x / v3->w); - float miny = std::fmin(std::fmin(v1->y / v1->w, v2->y / v2->w), v3->y / v3->w); - float maxy = std::fmax(std::fmax(v1->y / v1->w, v2->y / v2->w), v3->y / v3->w); - float bbox_frac = (maxx - minx) * (maxy - miny) / 4.0f; // NDC quad is [-1,1]^2 - if (!std::isfinite(bbox_frac) || bbox_frac > 0.15f) { - fprintf(stderr, "D288: tri w=(%.6f,%.6f,%.6f) bbox_frac=%.3f any_behind=%d color=(%d,%d,%d)\n", - v1->w, v2->w, v3->w, bbox_frac, (int)any_behind_camera, - v1->color.r, v1->color.g, v1->color.b); + extern uint32_t num_dls; + if (num_dls >= 550 && num_dls <= 755) { + float minx = std::fmin(std::fmin(v1->x / v1->w, v2->x / v2->w), v3->x / v3->w); + float maxx = std::fmax(std::fmax(v1->x / v1->w, v2->x / v2->w), v3->x / v3->w); + float miny = std::fmin(std::fmin(v1->y / v1->w, v2->y / v2->w), v3->y / v3->w); + float maxy = std::fmax(std::fmax(v1->y / v1->w, v2->y / v2->w), v3->y / v3->w); + float bbox_frac = (maxx - minx) * (maxy - miny) / 4.0f; // NDC quad is [-1,1]^2 + if (!std::isfinite(bbox_frac) || bbox_frac > 0.5f) { + fprintf(stderr, "D288: dl=%u tri w=(%.6f,%.6f,%.6f) bbox_frac=%.3f any_behind=%d color=(%d,%d,%d)\n", + num_dls, v1->w, v2->w, v3->w, bbox_frac, (int)any_behind_camera, + v1->color.r, v1->color.g, v1->color.b); + } } } }