diff --git a/docs/dev/GRAPHICS-BACKLOG.md b/docs/dev/GRAPHICS-BACKLOG.md index 8a077a59..91f91fc3 100644 --- a/docs/dev/GRAPHICS-BACKLOG.md +++ b/docs/dev/GRAPHICS-BACKLOG.md @@ -17,7 +17,7 @@ once the game is playable start-to-finish without crashes. | **D148** | Level-end cinematics don't play. Dam: hitting the exit trigger should show Bond rappelling down the dam (the bungee jump); instead it cuts straight to the mission-complete report. **Broader (M-49 full playthrough): cutscenes are buggy in many places across the game**, not just the Dam ending — the user reports frequent cutscene glitches (skipped, wrong camera, misplaced/hovering actors, timing). Treat D148/D160 as the tracking entry for the whole cutscene-reliability problem, not just Dam. | Scripted cutscene / cinematic-camera + Bond rappel anim. Found M-27 during the first full Dam→Facility playthrough. Progression is unaffected — the report and next briefing load fine. The widespread nature (M-49) points at a systemic cause: the propDef/`sizepropdef` stride desync (D122/D132 family) that misreads `CutsceneRecord` lookups, and/or D75 anim-model + D173 actor-position bugs showing up wherever a cutscene puts a character on screen, and/or the D155/D156/D193 timing family driving cutscene camera/anim pacing. **M-31 (§F D160):** static-traced the Dam end ailists (`ai_24`→`ai_17`, `camera_switch`→`CutsceneRecord` type-46 lookup). Diagnostic `GE_D160=1` shipped (`c95713f5`) — user runs Dam to the exit with it set; the trace pins whether the cutscene AI runs, and whether the propDef-index walk (D122/D132 family) hands `camera_switch` a bogus cutscene record. Leading hypothesis: propDef `sizepropdef` stride desync (medium confidence), not D75 anim-model. **M-87 user playtest:** Bond floating/hover cutscene glitch (D173) still present; new specific instance — **Bond spins in circles in some cutscenes**, named example the end-of-Cradle Trevelyan-falls cutscene. Likely the same actor-position/anim-root cause manifesting as bad rotation instead of bad height. | | ~~**D149**~~ | ~~Front-end MISSION COMPLETE / mode-select 3D models (dossier, wallets) render as garbled full-screen geometry or not at all.~~ | **CLOSED — user-verified fixed (M-87 playtest).** No longer reproduces; presumably fixed as a side effect of other front-end/D75-family work since M-49. D75 family. §F D146. | | **D170** | Named-NPC "flee" scripted behavior looks wrong on PC: on Silo, Ourumov breaks into a full run the instant he alerts ("Ourumov: Kill him!") rather than the N64 walk/retreat; developer reports Trevelyan behaves the same way on Cradle. **M-49 full playthrough: escalated — Cradle (`-level_51`) is "bugged out completely" from Trevelyan's behavior; the final level's scripted progression breaks. Now folded into / superseded by §F D193 (NPC AI locomotion too slow).** | **Observed, not investigated** (M-34, from a Silo playtest capture; user bug report — no fix wanted yet). Could be a genuine ailist / `chrTick` divergence, OR the D155/D156 wall-clock `deltaFrames` locomotion-anim speed-up (a catch-up spike playing the walk cycle at 2–3×). **Verify first:** capture the same beat against N64 reference footage before assuming it diverges — Ourumov may be scripted to flee. If it's real, suspect the frametiming clamp (§F D155/D156) or the Cradle-family AI path (§F D123). | -| **D171** | Silo missile-shaft: a large translucent grey triangle sweeps across the lower frame while panning down the shaft (~3 s of the capture). Looks like a stray poly / near-plane clip fan, same family as D106 (portal near-plane min>max). | **Observed, not investigated** (M-34, Silo capture). Cosmetic, intermittent, tied to camera angle in the open vertical shaft. | +| **D171** | Silo missile-shaft: a large triangle sweeps across the frame while panning down the shaft. **Promoted to `docs/dev/findings.md` §F D288 (M-141)** with a user-reproduced, precisely-bounded, visually-documented repro (frames ~562-741 of a bare `-level_20` boot) — read that entry for the current state, not this row. | See D288. | | **D172** | Bullet-impact / blood particle spray renders magenta or cyan instead of dark red (visible on guards hit at close range on Silo). | **M-82: ROOT CAUSE FOUND + FIXED (PR #34).** `GE_D172` probe on a user Silo firefight: 40/40 particle tris configure tile 1 = RGBA16 fire @ tmem 392 but fast3d **samples tile 0 (smoke) for both texunits** — `gfx_lod_tile_offset()` returns 0 unconditionally (D107 blurry-ceiling fix; `video.c:225` disables `gfx_detail_textures_enabled`). `G_CC_INTERFERENCE` = `smoke*smoke` → magenta/cyan. Fix: `return rdp.tex_lod ? 0 : i` — only fold to base tile for real LOD/mip draws. (0xB9 + cycle-type were both false trails, ruled out earlier in M-82.) **Owed: in-game eyeball — blood should be dark red.** Detail: `D172-PARTICLE-COLOR-RESEARCH.md`. | | ~~**D178**~~ | ~~Objectives not listed correctly on the pre-mission briefing screen (the mission overview shown before starting a level).~~ | **CLOSED — user-verified fixed (M-87 playtest): "main menu text is good now."** No longer reproduces. M-36 triage below kept for reference. **M-36 triage: the objective lines are BLANK, not wrong.** `GE_STARTMENU=10` Dam briefing renders the header fine ("OHMSS / Agent: James Bond / Mission 1: Arkangelsk / Part i: Dam / PRIMARY OBJECTIVES:") then just the bullet "a." with no text and no b/c/d. → **D143/D151 blank-text family** (`langGet()` → NULL → silent blank), *not* a propDef walk / difficulty decode. **Family B** in `docs/dev/M-36-TRIAGE.md` — find which lang bank the front-end briefing flow fails to load. Re-confirm the exact shape in a *real* briefing (the `GE_STARTMENU` boot skips real save state). Close relatives: D151 (watch objective text blank — type-35/23 `text` slot u16→u32 fix, M-28; interactive re-verify was still pending), D143 (briefing/objective text blank via `langGet` NULL), D157 (objective difficulty byte offset — could make difficulty-gated objectives appear/disappear wrongly). The pre-start briefing is a *different surface* from the in-level watch, so D151's fix may not cover it. **Next:** ask user which level + what exactly shows vs expected; compare against `docs/dev/LEVEL-OBJECTIVES.md` (regenerated post-D157); if lines are blank → D143/D151 family (`langGet` NULL guard = silent blank), if wrong objectives listed → propDef type-23 record walk / difficulty decode. | | **D175** | In-game stutter / brief hang during normal play — observed opening a door on Runway (mission 3, `-level_35`) and also on Surface. No backtrace captured (gdb attach missed the window; it self-recovered). | **Observed, not investigated** (user QA report). Matches known transient-hang classes rather than looking new: D155 (post-slow-load catch-up spiral — clamped), D156 (anim NaN loop — guarded, prints one-shot stderr diag if it fires), D134 (SP/DP task-done event swallowed — fixed M-22, Runway was an original victim), D147/D152 (audio `s_imLock` steal = ~2 s hiccup). Door-open specifically = new room first visible → one-off texture-import/frame spike (likely benign). **Next:** reproduce under `tools_pc/debug.ps1` with the box idle; check console for the D156 stderr diag; if it recurs, attach gdb mid-hang and pattern-match `bt` (import_texture = benign slow frame; model.c:3131 spin = D156; pthread_mutex_lock on s_imLock = D147/D152). | diff --git a/docs/dev/findings-index.csv b/docs/dev/findings-index.csv index 9a8d495d..5b1f00c2 100644 --- a/docs/dev/findings-index.csv +++ b/docs/dev/findings-index.csv @@ -165,3 +165,4 @@ D284,FIXED,"port/src/random.c's MIPS64 dsll32/dsrl32 shift helpers were backward D285,FIXED,"A real Steam Deck SIGSEGV caught during D255 live-testing (v0.2.1 published binary, symbolized on-device via addr2line against its own debug symbols) is a SEPA…","FIXED (M-141, src/snd.c) —" D286,OPEN,"User-confirmed real (not system-side) ~8s frame freeze on Caverns, Steam Deck, caught during the same live session as D255/D285 —","OPEN — one confirmed occurrence, no repro trigger identified, not root-caused; distinct from D255/D285." D287,OPEN,"User-confirmed real, non-self-recovering freeze on Windows (M-141, 2026-09-15/16) after ~15-20 minutes with no input, triggered by clicking back into the windo…","OPEN — one confirmed occurrence, real (not self-recovering), not root-caused; gfxFrameMsgQ full is a lead, not a confirmed cause." +D288,OPEN,"Silo intro: a huge, flat-shaded, untextured brown/tan triangle sweeps across the frame during the camera pan down the missile shaft (M-141, user report —","OPEN — visually confirmed and precisely bounded (frames ~562-741 of a bare -level_20 boot), root cause not yet identified; promoted from the long-parked GRAPHICS-BACKLOG.md D171 entry with real evide…" diff --git a/docs/dev/findings.md b/docs/dev/findings.md index 35f0d10e..1ee62ded 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -563,6 +563,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D285 | **A real Steam Deck SIGSEGV caught during D255 live-testing (v0.2.1 published binary, symbolized on-device via `addr2line` against its own debug symbols) is a SEPARATE bug from D255** — `FAULT ADDR: 0x62` inside the **audio thread** (`sndHandleEvent`, `src/snd.c:366`, via `amMain`/`portThreadWrapper`), not D255's `0x10`/`vtxstore_fix_refs` on the render/game-logic thread. Root cause (static, not yet gdb-confirmed): the pool-exhaustion preempt-scan in `sndHandleEvent` reads/walks the shared `D_800243E4` active-`ALSoundState` list with **no `osSetIntMask` lock at all** (checked: absent from the function's entire body), while the list's insert path (`sndSetupSound`, reached from 15 different `src/game/*.c` files' direct `sndPlaySfx` calls, e.g. `explosion.c` — i.e. from whatever thread the caller runs on) **does** lock it — an asymmetric-locking gap, the same D4/D147/D152 "N64 interrupts-off is not a real lock on PC" class. Fits the repro pattern (explosion SFX bursts = high-contention window; Frigate's lower SFX load not reproducing it fits a timing race, not a deterministic trigger). Full body below. | **FIXED (M-141, `src/snd.c`)** — `osSetIntMask` lock added around the preempt-scan, matching `sndSetupSound`'s existing unconditional (no `#ifdef PORT`) pattern in the same file; build green, `-level_09`/`-level_20` unregressed (1400+ frames, no crash, no D152 lock-stuck warnings). Not yet gdb/live-confirmed against a real reproduced crash — see M-141 body. Do not conflate with D255 — different thread, different subsystem. | | D286 | **User-confirmed real (not system-side) ~8s frame freeze on Caverns, Steam Deck, caught during the same live session as D255/D285 — self-recovered, not a crash.** The game's own hang watchdog (`portHeartbeatCheck`) fired once (no frame for ~8s, `frames=46404`), dumped all-thread state via `crashDumpThreads`, then rendering resumed normally and the session continued to a clean close. Not tied to an explosion/terminal (rules out D255/D285). Not root-caused — no distinguishing log line precedes it; leading unconfirmed guess is a heavy room/asset stream-in stall (Caverns is a large level, cross-ref D250's FPS lineage, though the symptom shape differs). Also fixed in passing: the heartbeat log printed a raw microsecond value with a `ms` label (cosmetic, `port/src/libultra.c`). Full body below. | OPEN — one confirmed occurrence, no repro trigger identified, not root-caused; distinct from D255/D285. Do not chase a repro without a better lead. | | D287 | **User-confirmed real, non-self-recovering freeze on Windows (M-141, 2026-09-15/16) after ~15-20 minutes with no input, triggered by clicking back into the window.** Caught live under `tools_pc/debug.ps1` (gdb-attached), evidence preserved at `scratch/d287_freeze_gdb.txt`. Last real `frame N rendered` log line: frame 17616. The heartbeat (`portHeartbeatCheck`) then fired 3 times with a **growing** stall (8001ms → 13017ms → 18021ms, `frames=17616` unchanged all 3 times) and then stopped logging entirely, while the VI-retrace pacemaker (`D51 vi post #N`) kept incrementing at its normal ~60 Hz rate for well over 100 more real seconds until the user closed the window — i.e. the pacemaker/OS-timer side is alive, the sim/render side is genuinely wedged, not the D286 shape (which self-recovered after one dump). **Different from D286**: no explosion/level-streaming context (idle + refocus, not combat), and the growing-then-silent heartbeat pattern (vs. D286's single fire-then-recover) points at a different mechanism. **Leading lead, not yet confirmed:** at freeze time, `gfxFrameMsgQ` (`src/init.c`, the scheduler's 32-slot client completion queue, registered via `osScAddClient`) shows `valid=32/32` — completely full — while the VI-retrace queue (8-slot) is not (`valid=1/8`). A full *client* queue with the producer (scheduler) still ticking implies the **consumer** (the main thread's `osRecvMesg(&gfxFrameMsgQ, ...)` in the frame loop) stopped draining it — consistent with the main/render thread blocking on something else (a lock, a GL call, a Windows message-pump stall) during or after a long-idle refocus, not with the scheduler itself stalling. Not yet identified what that something is. A pre-existing, currently-unused diagnostic (`GE_D60`, `port/src/libultra.c:630+`) already watches `gfxFrameMsgQ` receives and looks like the right next probe to enable. **Next, concrete:** reproduce with `GE_D60=1` (and ideally `GE_INPUTLOG=1`) running under `debug.ps1`, leave the window idle+unfocused 15-20 min, refocus, and once frozen `bt full` the actual game/render thread (not just the auto-dump's generic `WaitForMultipleObjects` frames for `shedThread`/`audioThread`) to find what it's blocked on. Cross-ref D134's superficially-similar-sounding-but-different mechanism (a different, 8-slot queue, already fixed) — do not assume the same fix applies here without confirming the actual blocked call site. | OPEN — one confirmed occurrence, real (not self-recovering), not root-caused; `gfxFrameMsgQ` full is a lead, not a confirmed cause. | +| D288 | **Silo intro: a huge, flat-shaded, untextured brown/tan triangle sweeps across the frame during the camera pan down the missile shaft (M-141, user report — "weird triangle drawn on silo intro randomly when the camera pans around the rocket"; previously catalogued as `GRAPHICS-BACKLOG.md` D171, "observed, not investigated" since M-34, never given a full findings.md entry until now).** Reproduced headlessly this session: `GE_PCDUMP=1-2000:10 ./build-pc/ge007.x86_64.exe -level_20` (run backgrounded, not foregrounded — see the environment note below), captured to `./ppm/`. Visual sweep (contact-sheet montages, `docs/img/bugs/D288-silo-stray-triangle-sheet.png` covers frames 571-751; `-closeup.png` is a full-res crop of frame 691) shows: **clean at frames 481-561** (no triangle), **first appears between frame ~562-601**, grows continuously in screen size through frame ~711 (by which point it covers roughly a third of the frame), then **shrinks and is gone by ~731-741** as the scene cuts to the first-person shaft-corridor view. Sampled pixel color is **exactly uniform** across the whole triangle (`RGB(83,62,44)` / `#533E2C` at two different sample points) — no gradient, no texture detail — i.e. this is a flat-shaded (no per-vertex color variance, no texture bound) single triangle, not garbage/noisy vertex-color data. **Reading of the evidence:** the grow-then-shrink-then-vanish arc across ~15 real seconds of camera motion is the classic signature of a genuine 3D triangle in world space that the camera flies close to/through during the scripted pan — not a 2D HUD/UI element (which would stay roughly fixed in screen size) and not obviously a `D146`-class freed-memory read (which reads as noisy garbage bytes, not a clean uniform flat color). The flat uniform color argues this is a REAL, correctly-colored asset triangle whose position/transform is wrong, which points at the same neighborhood as D106/D233 (near-plane / w-clip mishandling in `port/fast3d/gfx_pc.cpp`) rather than a game-code or converter data bug — but this is a read of the visual evidence, not a code-level confirmation; no probe has been run yet. **Not yet identified:** which model/prop this triangle belongs to (nothing in `UsetupsiloZ.c` was grepped for a matching solid-brown material this session), and no `port/fast3d/` tracing was done to catch the actual triangle at draw time. **Environment note (new, useful beyond this bug):** launching `ge007.x86_64.exe` in the **foreground** under this session's Bash tool with `timeout N ...` produced **zero** `ppm/` output despite `GE_PCDUMP` being set and verified exported — the `ppm/` directory was never even created (`GE_MKDIR` never ran or `frames`-gated capture never fired). Backgrounding the same invocation (`... &`, `sleep N`, `kill`) worked immediately and reliably. Not root-caused (didn't block this investigation), but worth remembering for the next session that needs `GE_PCDUMP` from this same tool. **Next, concrete:** (1) grep `assets/obseg/setup/UsetupsiloZ.c` / the missile-shaft model's material table for a solid `RGB(83,62,44)`-ish prim/vertex color to identify the source asset; (2) add a temporary `#ifdef PORT` probe in `gfx_sp_tri1` logging any triangle whose post-transform screen-space bounding box exceeds some fraction of the viewport together with each vertex's `w`, gated to `-level_20` frames ~560-740, to catch the culprit triangle's `w` sign/magnitude at the moment it blows up — same style as the existing `GE_D271`/`GE_D104` probes; (3) cross-check against D233's `w<0` trivial-reject fix and D106/D271's near-plane portal-bound clamp to see if this is a third site with the same underlying class of bug, or a genuinely new mechanism. | OPEN — visually confirmed and precisely bounded (frames ~562-741 of a bare `-level_20` boot), root cause not yet identified; promoted from the long-parked `GRAPHICS-BACKLOG.md` D171 entry with real evidence. | Phase 2 replaced the Phase-1 demo loop with the real `mainproc()` on real OS threads, compiled GE's real `src/sched.c`, and brought in PD's fast3d software diff --git a/docs/img/bugs/D288-silo-stray-triangle-closeup.png b/docs/img/bugs/D288-silo-stray-triangle-closeup.png new file mode 100644 index 00000000..d9b64429 Binary files /dev/null and b/docs/img/bugs/D288-silo-stray-triangle-closeup.png differ diff --git a/docs/img/bugs/D288-silo-stray-triangle-sheet.png b/docs/img/bugs/D288-silo-stray-triangle-sheet.png new file mode 100644 index 00000000..7959df42 Binary files /dev/null and b/docs/img/bugs/D288-silo-stray-triangle-sheet.png differ