docs: adopt cheap GEVR-triage items (crash heuristic, frame-rate notes, process lesson, widescreen pre-flight)

Folds in the zero-code-risk ADOPT items from scratchpad/GEVR-TRIAGE.md
(a prior survey of the sibling GEVR VR port, same n64decomp/007
lineage, reference-only): a crash-triage heuristic for non-canonical
x86-64 pointer faults, two frame-rate-assumption notes that pre-empt a
future uncapped/high-refresh rabbit hole, a process lesson about
grep-built site lists standing in for a real read, and the
portal-scissor site map as pre-flight for whenever widescreen work
resumes.

Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
This commit is contained in:
James Dansereau committed 2026-09-15 19:18:07 -04:00
1 parent eb0928889e
commit 8df8ad3c35
3 files changed
+76

No files matched your search

+12
View File
@@ -63,6 +63,18 @@ The classes it currently tracks:
- whole serialized formats are converted by an **offline sidecar** rather than
patched at runtime.
**Two process lessons from the sibling GEVR VR port** (same decomp lineage,
reference-only survey in `scratchpad/GEVR-TRIAGE.md` item D — their corpus
hit both repeatedly enough to name them): (1) **a grep standing in for a
read** — a site list built by grepping one helper name or spelling misses
siblings spelled differently or living in an adjacent file (their own
missed-smoke-scissor-site example); treat a grep-built site list as a draft,
not a census, until it's been read against. (2) **write the falsifier before
the run** — state up front what result would kill the hypothesis ("if X
survives, hypothesis Y is dead"), not just what would confirm it; this fits
the existing budget/findings discipline directly and costs one sentence per
brief.
## 3. Parallelise by file, consolidate often
Lewis ran multiple git worktrees and found the real cost was
+37
View File
@@ -125,6 +125,43 @@ From the `pd_port` checkout (N64 PD had no widescreen; the port added it):
("Decide Phase 1" below) — correcting an earlier note here that overstated
this as settled.
### 6. GEVR portal-scissor findings — read before Phase 2/3 game-code work
The sibling GEVR VR port (same n64decomp/007 lineage, reference-only survey
in `scratchpad/GEVR-TRIAGE.md` item A) independently measured, on the same
decomp, that widescreen "missing wall / see-through slab" artifacts come
from the **per-room portal `SETSCISSOR` rects**, not the room-visibility
pass (their cull census was byte-identical between arms) — giving every room
the full view removed the artifacts (one level, one viewpoint; treat as a
hypothesis, not settled). Re-derived in **our** tree (2026-07):
| Class | Our sites | Notes |
|---|---|---|
| SCISSOR — room passes | `bg.c:685`, `bg.c:747` (`bgScissorCurrentPlayerViewF`) | primary + secondary/xlu |
| SCISSOR — default variants | `bg.c:723`, `bg.c:1306`, `chrprop.c:598` (via `bgScissorCurrentPlayerViewDefault`, `bg.c:1332`) | |
| SCISSOR — characters | `chr.c:3070/3074` (`chrRender`) | |
| SCISSOR — explosions | `explosion.c:876/880` **and `explosion.c:1488/1492` (smoke)** | the smoke site is the one GEVR missed on their first pass |
| CULL (removes props, not pixels) | `propobj.c:13584` `posIsOnScreen` (used at `:5881`) | a too-tight rect *deletes* a prop — GEVR's black-wall candidate |
| **AI / SPAWN logic** | `chraction.c:10628` `chrIsPosOffScreen` → `bgGet2dBboxByRoomId` (`bg.c:573`) | reads the rect for character AI/spawn decisions |
**Design trap (their hardest-won lesson):** do NOT put a clip/widescreen
knob inside `bgGet2dBboxByRoomId` — it's the chokepoint that also feeds
`chrIsPosOffScreen`, so a "clip-only" change there would silently alter what
characters do. Scissor sites can be widened directly; the cull box and the
AI/spawn consumer must be reasoned about separately.
**Caveats:** (1) removing all per-room scissoring has an unknown
overdraw/perf cost — measure before shipping; (2) their fix evidence is one
level + one viewpoint; (3) the "two notions of view width" trap (their doc
278): a port knob that redefines native content width from the *window*
aspect while the game's scissor-tracked canvas stays 4:3 leaves ~29% of
columns undrawn → stale-buffer slabs. Whatever this plan's implementation
does, the game's canvas notion and the window notion must be reconciled
explicitly at one named place — re-verify the line numbers above (cheap
greps: `bgScissorCurrentPlayerView`, `bgGet2dBboxByRoomId`, `posIsOnScreen`,
`chrIsPosOffScreen`) before acting on them, since this table predates any
Phase 2/3 work actually landing.
## Option B — the standard (native 16:9, PD-parity)
### Architecture
+27
View File
@@ -1225,3 +1225,30 @@ and turns every such overrun into a fatal `*** stack smashing detected ***`
path (`cd C:\Users\...`) is unreliable in this same shell and can silently
mis-parse to a mangled path on a later command in the same tool call —
prefer `cd /c/Users/...` (forward slashes) for the build working directory.
- **A crash fault address of `0xffffffffffffffff` on x86-64 usually means a
non-canonical #GP from a garbage-high-bits pointer (bits 63:48 not a sign
extension of bit 47), not a computed `-1` sentinel** (cross-validated
against the sibling GEVR VR port, same decomp lineage — see
`scratchpad/GEVR-TRIAGE.md` item C; we independently hit the same register
shape in D191). Two companion habits worth keeping: re-read map anchors
from the freshly rebuilt map after every rebuild (a stale map silently
resolves the wrong symbol), and confirm the fault PC actually disassembles
on an instruction boundary before trusting a resolved symbol.
- **Frame-rate assumptions — read before proposing any non-60 Hz mode**
(cross-validated against GEVR, `scratchpad/GEVR-TRIAGE.md` item B). GE's
logic is delta-scaled through `g_GlobalTimerDelta` (~216 call sites); the
PAL build (×1.2) is a shipping proof that delta-scaled code tolerates
other rates. But: **Bond's walk is frame-rate dependent by construction**
— `MoveBond` (`bondview2.c`) is an exponential approach toward a target,
advanced once per frame with no timestep, so convergence is measured in
frames, not seconds (GEVR measured ~1.487× walk speed at 90 Hz vs 60 Hz,
≈90/60 exactly). Turn/aim *is* delta-scaled; walk is not. High-refresh or
uncapped presentation modes are therefore out of scope without a
game-logic change, which is forbidden — we tick at fixed 60 Hz (D52
pacing) by design, not as a limitation to fix. Also: `g_ClockTimer` must
stay integer (24 iteration sites depend on it); of 44
`/g_GlobalTimerDelta` divide sites, 40 are guarded (three different
spellings) and 4 are not (front-end cast camera `front.c:8271-8273`,
`propobj.c:~2393`) — those 4 rely on div-by-zero yielding NaN/inf without
trapping on both MIPS and x86-64 SSE, matching retail behavior; do not
"fix" them.