D303: investigate extra long muzzle flash — pipeline + data ruled out; GE_D303 capture probe in-tree

This commit is contained in:
James Dansereau committed 2026-09-21 23:41:05 -04:00
1 parent 61766e8aef
commit 2efbbef964
4 files changed
+66 -5

No files matched your search

+19 -1
View File
@@ -29,7 +29,7 @@ Sequencing follows M-139's R → Q → F order, split into four phases below.
| D320 | 17 aim-hold AI lists in 8 levels carry the as-authored D318 softlock race; Facility `ai_19`, Control `ai_9`, Depot `ai_12` high/med-high | Static sweep done; **live probe-verification owed** (GE_D318T-style timeline on the 3 lists). If one freezes: generalize `d318watchdog.c` (parameterize list/offset/chr/entityid), not per-list copies. N64 softlocks permanently — watchdog stays a port-side recovery, disclosed like D318. |
| D252 | Rainbow particles still intermittent on both platforms after the vertex-buffer fix | Second cause unrooted; prime suspect `import_texture_rgba16` fire-tile width/height from tile line size (32×7 vs 16×14). README known issue. |
| D245 | Water seam between two patterns, moves with view (REOPENED) | M-142 probe: tc-shift k flips during ordinary rotation; opt-in `GE_D245_FIXEDSHIFT` candidate build-verified, needs A/B vs N64 reference before making it default. |
| D303 | Wrong extra long muzzle flash (M16 + others) | Reported only, not investigated. |
| D303 | Wrong extra long muzzle flash (M16 + others) | **Investigated — pipeline + data ruled out.** Flash path (`gunUpdateAndFire` → `rwmtx[1]/[2]`, `dorottex` DLPRIMARY arms) is byte-identical game code; M16's `MuzzleFlashExtension`=6.0 is the legitimate max stat; Gm16Z flash-node data byte-faithful through d43. Headless runs can't fire weapons (guards don't shoot an idle player), so a TEMP `GE_D303=1` probe in `gfx_pc.cpp` logs every very-tall-thin emitted triangle with full RDP state — **blocked on a live firing capture** (playtest brief item 17). |
| D306/D308 | Z-fighting: Dam intro/truck wheels + general/broader instances | Two reports, likely one family; investigate together. |
| D307 | In-level security camera props face backwards on some levels (Bunker) | **Investigated 2026-09-21 — no port-side bug found.** Full orientation path traced (`setupCctv` → per-frame `RotY(unkC8)×unk84`); every input verified N64-faithful against the ROM (PcctvZ switch data, boundpads incl. the legitimate load-time room-scale ×1.8542, record config words); all math helpers are byte-identical `src/game` code. Remaining suspect if it genuinely differs from N64: fast3d handling of the non-orthonormal lens matrix. **Blocked on user repro detail** (which camera/level + screenshot + ideally N64 compare). `GE_D307=1` diagnostic kept in-tree. |
| D236 | Surface 1 billboard trees render as a solid wall of texture | **FIXED (M-198, pass 26, `425237f9`):** root cause was a texture-BINDING bug — `TEXTURETYPE_DETAIL` cards drawn from the detail tile (opaque IA8 noise) instead of the base image; `gfx_lod_tile_offset` now samples tile 1 when the pair differs (`Video.DetailBaseTile`, default on). Live-verified Surface 1/2 + Depot; other levels provably untouched. Awaiting user play-test sign-off; probes stripped (`0503d335`). |
@@ -301,6 +301,19 @@ Order by user-visible value:
fast3d's handling of the non-orthonormal lens matrix (`unk84` row 0 scaled
0.1×). Blocked on user repro detail (which camera/level + screenshot).
Findings entry updated; probe kept in-tree (D60/D88 pattern).
- **D303 (extra long muzzle flash) investigated — no port-side bug found yet,**
blocked on live capture. Mapped the full flash pipeline (`gunUpdateAndFire`
builds `rwmtx[1]` = yaw×scale×flashext and `rwmtx[2]` from `Switches[2]`; the
flare arms are `dorottex` DLPRIMARY nodes) — all byte-identical game code,
matrix helpers verified index-for-index. Ruled out: weapon stats (M16's
flashext=6.0 is the legitimate max, sniperrifle matches; the ext≥3 ⊆
CAN_DUAL_WIELD overlap is design coincidence) and model conversion (Gm16Z
DLPRIMARY records + vertex blocks byte-faithful per d43 round-trip). Added a
TEMP `GE_D303=1` probe in `gfx_pc.cpp` (cached-getenv; logs very-tall-thin
emitted triangles with blend/oml/comb/prim/env/w) — 75 s unattended runs on
Bunker1/Dam/Depot show only static scene geometry, so the artifact needs a
live firing repro. Next: user fires the M16 under `GE_D303=1` and shares the
log lines; the spurious quad's RDP state will identify its source.
- **Plan/doc refresh:** D75 (M-197) and D236 (M-198) marked fixed throughout
(Bucket A rows, Phase 1 items 6/7/11, playtest brief); findings index
regenerated; README Known Issues to match.
@@ -354,6 +367,11 @@ Checklist beyond the normal play:
facing backwards, note which level + which camera (screenshot) — the
orientation math is verified N64-faithful, so a concrete repro is what's
needed to keep chasing it.
17. **D303 (extra long muzzle flash)**: run with `GE_D303=1` in your terminal,
fire the M16 (and any other gun that shows the extra upward flash) until
you see it, then share the `D303:` log lines from around that moment —
each line carries the RDP state of a candidate quad and will identify the
spurious draw call's source.
## Conventions reminder
- One findings entry per investigation; next labels after **D322**.
+1 -1
View File
@@ -180,7 +180,7 @@ D299,FIXED,Game.SkipIntro crashed selecting any save slot except one —,"FIXED
D300,FIXED,Hipfire look feels non-uniform (issue #89):,"FIXED, user-confirmed live —"
D301,FIXED,"fileGetIsCheatUnlocked() NULL-deref, unguarded on every call site, not just the D299/SkipIntro one (GitHub #87, two reports with an identical crash PC/fault ad…",FIXED locally on release/v0.3.0 (not pushed) —
D302,FIXED,"Render FPS regression to ~40-45fps on release/v0.3.0 (user QA on the local v0.3.0 pre-release build, 2026-09-18) —","FIXED — 4 uncached getenv() calls added by D236 passes 10/12/14/16 directly inside gfx_sp_tri1 (port/fast3d/gfx_pc.cpp, per-triangle) cached with the same static int x = -1 pattern D250 established e…"
D303,OPEN,"Some muzzle flashes (M16 named specifically, ""and some others"") draw wrong —","OPEN — reported only, not yet investigated."
D303,OPEN,"Some muzzle flashes (M16 named specifically, ""and some others"") draw wrong —","OPEN — investigated: pipeline + weapon stats + model conversion ruled out; GE_D303 capture probe in-tree (port/fast3d/gfx_pc.cpp), blocked on a live firing repro."
D304,FIXED,"Mouse sensitivity menu overhaul (user request, 2026-09-18):","FIXED — see full entry for both the range/parity pass and the same-day follow-up (collapsed to a single Input.MouseSensitivity menu row + fixed overlayUpdateScroll()'s unconditional bottom-anchor, th…"
D305,FIXED,"Steam Deck SIGSEGV on the v0.3.0 pre-release build (Cavern, early in the level, Game.AllUnlocked previously enabled on the session/save) —",FIXED (defensive guard) —
D306,OPEN,"Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).","OPEN — reported only, not investigated."
1 # GENERATED by tools_pc/gen_findings_index.py -- do not hand-edit.
180 D300
181 D301
182 D302
183 D303
184 D304
185 D305
186 D306
+10 -3
View File
@@ -588,7 +588,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D300 | **Hipfire look feels non-uniform (issue #89): mouse px routed through the N64 analog stick's quadratic natural-turn curve, so slow motion is "almost unrecognised" and fast motion saturates at full turn speed by ~13 px/poll.** — full `## D300` entry at file tail | FIXED, user-confirmed live — WI-1 per `docs/dev/GEPD-INPUT-PLAN.md`: new `hipDirectCompute()` (`port/src/input.c`) writes `vv_theta`/`vv_verta` directly, mirroring GEPD's hipfire formula and D194's existing aim-mode direct-write pattern — linear px→degree, FOV-scaled, dt-normalized, bypassing the stick curve entirely. Safety-gated on `bonddead`/`outside_watch_menu`/`pause_state` plus (M-190, 2026-09-18) the scripted-camera-mode check the original safety-gates writeup named but never implemented — mouse could freely move the camera during POSEND/INTRO cutscenes until this session. `Input.MouseDirectLook` (default 1) is the escape hatch back to the legacy stick path. Build/link-verified; user playtested live: "input already feels better," then again post-M-190: "ok yeah looks good." |
| D301 | **`fileGetIsCheatUnlocked()` NULL-deref, unguarded on every call site, not just the D299/SkipIntro one (GitHub #87, two reports with an identical crash PC/fault address).** — full `## D301` entry at file tail | FIXED locally on `release/v0.3.0` (not pushed) — NULL-guarded `fileGetIsCheatUnlocked()` itself (`src/game/file2.c`, `#ifdef PORT`) rather than only its one known trigger route; build-verified, crash-free smoke test. Live confirmation against the actual #87 repro still owed — a synthetic `GE_STARTMENU=6` repro attempt did not reproduce the crash even pre-fix, so the exact #87 trigger condition (why the save lookup fails) remains unconfirmed. |
| D302 | **Render FPS regression to ~40-45fps on release/v0.3.0 (user QA on the local v0.3.0 pre-release build, 2026-09-18) — a reintroduction of D250's own uncached-`getenv()`-in-the-hot-path bug class.** — full `## D302` entry at file tail | FIXED — 4 uncached `getenv()` calls added by D236 passes 10/12/14/16 directly inside `gfx_sp_tri1` (`port/fast3d/gfx_pc.cpp`, per-triangle) cached with the same `static int x = -1` pattern D250 established elsewhere in the file. Verified via `GE_D193=1 -level_33` (Dam): rock-steady `render=59-61` post-fix, matching D250's own post-fix baseline exactly (pre-fix D250 pinned this level at 45-50fps). Not yet re-confirmed by the user's own hands-on playtest. |
| D303 | **Some muzzle flashes (M16 named specifically, "and some others") draw wrong — the flash renders very long, extending straight up from the gun (user QA on the v0.3.0 pre-release build, 2026-09-18).** — full `## D303` entry at file tail | OPEN — reported only, not yet investigated. |
| D303 | **Some muzzle flashes (M16 named specifically, "and some others") draw wrong — the flash renders very long, extending straight up from the gun (user QA on the v0.3.0 pre-release build, 2026-09-18).** — full `## D303` entry at file tail | OPEN — investigated: pipeline + weapon stats + model conversion ruled out; GE_D303 capture probe in-tree (`port/fast3d/gfx_pc.cpp`), blocked on a live firing repro. |
| D304 | **Mouse sensitivity menu overhaul (user request, 2026-09-18): aim speed/turn speed sliders weren't "1:1", had too little range, and (follow-up) risked decoupling into a bad state; F10 menu also had a click-jump bug.** — full `## D304` entry at file tail | FIXED — see full entry for both the range/parity pass and the same-day follow-up (collapsed to a single `Input.MouseSensitivity` menu row + fixed `overlayUpdateScroll()`'s unconditional bottom-anchor, the actual cause of the reported "menu jumps to the setting below on click"). Build-verified (Windows) both passes; headless overlay smoke test clean after each. **Live F10 playtest done (2026-09-18): user confirmed the collapsed single-sensitivity menu works, the click-jump is gone, and the D251 bottom-row duplication no longer occurs.** |
| D305 | **Steam Deck SIGSEGV on the v0.3.0 pre-release build (Cavern, early in the level, `Game.AllUnlocked` previously enabled on the session/save) — same exact FAULT ADDR 0x62 / `sndHandleEvent` signature as D285, reproduced AFTER D285's own lock fix was already live-verified crash-free on real hardware.** — full `## D305` entry at file tail | FIXED (defensive guard) — `sndHandleEvent`'s preempt-scan (`src/snd.c`) dereferenced its list-walk pointer before ever checking it for NULL (a do-while always runs its body once); D285's `osSetIntMask` lock only prevents another thread from emptying the list mid-scan, not a scan that starts with an already-empty list, so the crash could still happen even with that fix in place. Added the missing `iterState != NULL` guard before the loop, matching D255's established skip-instead-of-dereference precedent. Root desync mechanism (why pool-exhaustion accounting and the list can disagree) still not identified; `Game.AllUnlocked` correlation not proven, only reported. **Live-verified on the Deck (2026-09-18):** user ran two test sessions on Cavern with the updated build, plus toggled `Game.AllUnlocked` off then back on and relaunched — no crash in any of them. |
| D306 | **Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).** — full `## D306` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0. |
@@ -12115,9 +12115,16 @@ Adversarial pre-ship review of the whole v0.3.0 window (147 commits since v0.2.2
**Not yet looked at:** which code path renders muzzle flashes (likely a dynamically-built quad/billboard in `src/game`, similar family to the drop-shadow/flare-effect functions already surveyed during the unrelated D236 investigation — see that entry's pass 16 for the list of quad-building functions already read), whether this is a geometry/orientation bug (billboard not facing camera, or built in the wrong basis — "goes straight up" suggests a billboard axis or transform mixup) versus a render-mode/texture-stretch bug, and whether it's PC-port-specific or was already present pre-port (no N64 comparison done yet).
**Repro clarified, same day (follow-up playtest):** the normal, correct muzzle flash still draws — this is an **extra**, erroneous long flash overlaid on top of it, not a corruption/replacement of the one correct effect. This significantly narrows the search: two draw calls are happening where one is expected, one correct and one wrong. Points more strongly at an extra/duplicate quad-builder call site or a second render-mode pass firing unconditionally alongside the correct one (e.g. a "flare arms"-style secondary effect, per the pass-16 D236 survey's `dorottex` muzzle-flash-flare-arms function, distinct from the main flash builder) than at a single corrupted transform. Still not investigated — no code read done yet against this sharper framing.
**Repro clarified, same day (follow-up playtest):** the normal, correct muzzle flash still draws — this is an **extra**, erroneous long flash overlaid on top of it, not a corruption/replacement of the one correct effect. This significantly narrows the search: two draw calls are happening where one is expected, one correct and one wrong. Points more strongly at an extra/duplicate quad-builder call site or a second render-mode pass firing unconditionally alongside the correct one (e.g. a "flare arms"-style secondary effect, per the pass-16 D236 survey's `dorottex` muzzle-flash-flare-arms function, distinct from the main flash builder) than at a single corrupted transform.
**Status:** OPEN — logged, repro description sharpened, no investigation started.
**Investigation (2026-07-19):**
- **Flash pipeline mapped.** `gunUpdateAndFire()` (`gunfire.c`): per shot it builds `flashmtx` = random yaw (bitflag 0x1) × scale `flashscale`∈[1.0,1.25] × `MuzzleFlashExtension` on the Z-row (`matrix_column_3_scalar_multiply(flashext, flashmtx.m[0])`), multiplies into `gunmtx`, copies to `rwmtx[1]`; a second matrix `rwmtx[2]` is built from `mdlhdr->Switches[2]` (the flash-anchor node) with the same scale/extension. The model-side flare arms are the `MODELNODE_OPCODE_DLPRIMARY` nodes rendered by `dorottex()` (`model.c`) — 4-vertex shuffling with per-frame random rotation/scale. **All byte-identical game code; the `matrixmath.c` helpers verified index-for-index.**
- **Data ruled out (two layers).** (a) `MuzzleFlashExtension`: M16 = 6.0, the max in the set (sniperrifle also 6.0; others 1.0–4.0) — a legitimate per-weapon stat from the decompiled `gunWeaponStat.inc.c`, not a misread. All ext≥3 weapons happen to be `CAN_DUAL_WIELD` but so are many short-flash ones, so that's design coincidence, not a lead. (b) Model conversion: Gm16Z's `DisplayListPrimaryRecord` words + vertex blocks are byte-faithful through `d43_emit.py` (numVertices bswap, 16B vertex fields verbatim, GDL pointers remapped; round-trip validated per M-197).
- **Live capture blocked headless.** Added a TEMP env-gated probe in `port/fast3d/gfx_pc.cpp` (`GE_D303=1`, cached-getenv pattern): logs every emitted triangle whose NDC bbox is very tall + thin (h>45% frame, aspect>3) reaching GL, with blend/oml/comb/prim/env/w. Ran `-level_09/-level_05/-level_17` unattended 75s each: **only static scene geometry** (identical across frames — pillars; Bunker1 is full of tall thin quads). Guards do not fire at an idle player, so the artifact cannot be reproduced without live input.
- **Next step (playtest-gated):** user runs with `GE_D303=1`, fires the M16 until the artifact appears, captures the log lines around that moment. The probe prints the RDP state of every candidate quad — if the spurious flash is a distinct draw call its comb/oml/prim/w will differ from the correct one and point straight at the source (model node vs rwmtx slot vs fast3d pass). Fallback suspects if the log shows only ONE tall quad: fast3d handling of the flash texture's S/T wrap, or `rwmtx[1]/[2]` being consumed by the wrong model node.
**Status:** OPEN — investigated (pipeline + data ruled out), GE_D303 capture probe in-tree, blocked on a live firing repro.
**M-191 (2026-09-18, user QA on the v0.3.0 pre-release build): REOPENING the "main fireball" thread — the fresh report matches exactly the condition M-188 said to watch for.** User describes smoke/explosion effects as now looking correct overall, EXCEPT a "weird rainbow confetti looking sprite" that still draws overlaid on top of otherwise-correct smoke/explosion particles, sometimes. M-188 explicitly closed only the "lingering particle residue" manifestation (which turned out to be `s_bullet_spark`/D219, unrelated code) and left this exact scenario — a rainbow artifact riding on the actual explosion/smoke effect itself — open, with the instruction "re-open only if a fireball (not residue/embers) rainbow report comes in again." This report fits that description, not the residue/embers one. **Not yet investigated further this session** — the last concrete lead (before M-188's tangent into D219) was: trace forward from `import_texture_rgba16`'s `upload_texture()` call (`gfx_pc.cpp:718`) through the GL texture object and the `G_CC_INTERFERENCE` (TEXEL0=smoke IA × TEXEL1=fire RGBA16) combiner, since the source ROM data itself was already proven correct by hand-decoding all 14 fire-stage textures (M-156, see above) — the bug is downstream of decode, in upload/cache/combiner. A live `GE_PCDUMP` + `GE_D252=1` capture during an actual reproduction (shoot something that smokes/explodes) is still the next concrete step, unchanged from M-156's own "next, concrete" recommendation.