D75 Bug 2: runtime probe + triage update

Adds env-gated GE_D75 probe in title.c sub_GAME_7F007F30 (capped 8 lines).
Booted the bare front end through the gun-barrel sequence:

- Bond chr model + gun model entirely absent; both Model instances are
  valid (non-NULL obj, numMatrices 21/1) -> 'model not loaded' ruled out.
- chrModelInstance->render_pos is valid and freshly written each frame
  (== that frame's dynAllocate mtxlist base, clean double-buffer swap,
  o2p returns it unchanged) -> the 'render_pos = stale dynAllocate arena'
  hypothesis (D115 #5) is RULED OUT; do NOT land a persistent render_pos
  buffer.
- Zero fast3d DL warnings during the sequence -> not the D144/D146
  corrupt-sub-DL family.

Failure is downstream in drawjointlist/dotube vtx/node-DL resolution or an
off-screen basemtx. Next step: a drawjointlist-level probe. Full write-up
in PCPortResearch.md 'D75 Bug 2 - RUNTIME PROBE'.

-level_09 nonclear stable (91.66->91.62, D117 pan noise); build green.
This commit is contained in:
James Dansereau committed 2026-08-31 15:53:05 -04:00
1 parent cde5505840
commit 652663aac6
3 files changed
+77 -10

No files matched your search

+8 -9
View File
@@ -33,12 +33,12 @@ Two classes:
| Env var | File:line | Finding / what it logged | Status |
|---|---|---|---|
| `GE_D51` | `port/src/libultra.c:496`, `src/game/model.c:125,244,544` | msgQ 32-slot overflow watch / ModelSlot layout | dead (D51 closed) |
| `GE_D54` | `src/libultra/audio/seqplayer.c:468`, `load.c:369`, `csplayer.c:452` | music seq-table ABI / endianness (`ALMidiHdr`) | dead (D54 closed) |
| `GE_D54` | — (all blocks stripped M-32, commit `49ce620a`) | music seq-table ABI / endianness (`ALMidiHdr`) | dead (D54 closed) — fully removed |
| `GE_D56` | `src/game/model.c:227,830` | watch `Model` raw-offset reads | dead (D56 closed) |
| `GE_D60` | `port/src/libultra.c:521,735` | gfx frame msgQ delivery trace | dead (D60 closed) |
| `GE_D61` | `port/src/libultra.c:795` (`s_d61opened`) | opens a one-shot log file | dead (D61 closed) |
| `GE_D62` | `port/src/libultra.c:477` | osRecvMesg trace | dead (D62 closed) |
| `GE_D63` | `src/memp.c:214`, `src/game/bg.c:2525,2880,2908,2953`, `blood_animation.c:237,253`, `dyn.c:103,150`, `front.c:1410,1416,7814,7889,8083,8091,8099,8366`, `image.c:2453`, `language.c:431`, `model.c:4340`, `rsp.c:234,286`, `title.c:607` | gun-barrel sub-DL clobber hunt (D63/D64/D65/D66 — the labels drift within the blocks). **Also `port/fast3d/gfx_pc.cpp` had a D63 branch-trail — stripped M-30, commit `d0789358`.** | dead (D63 closed) — **strip candidate**, see §3 assessment in the session report / PORT-LEARNINGS §E. NB `bg.c:2876/2880` are **not `#ifdef PORT`-guarded** |
| `GE_D63` | remaining: `src/game/bg.c:2525,2908,2953`, `front.c:1410,1416,7814,7889,8083,8091,8099,8366`, `image.c:2453`, `language.c:431`, `model.c:4340`, `title.c:607` | gun-barrel sub-DL clobber hunt (D63/D64/D65/D66 — the labels drift within the blocks). Stripped M-30 (`d0789358`, `gfx_pc.cpp` trail). Stripped M-32 (`49ce620a`): `memp.c`, `bg.c:2880` (incl. the bare non-PORT `d63bgprimarycount` static + entry log), `blood_animation.c`, `dyn.c`, `rsp.c`. **Remaining blocks are all `#ifdef PORT` + getenv-guarded and inert — strip candidates for a later pass.** | dead (D63 closed) — partially removed |
| `GE_D69` | `src/game/ob.c:165,227` | stage-load (D69) object trace | dead (D69 closed) |
| `GE_D69BB` | `src/game/bg.c:2460,2479,3020` | D69 bg-binary layout trace | dead |
| `GE_D69STAN` | `src/game/stan.c:266,276` | D69 stan-tile trace | dead |
@@ -47,19 +47,18 @@ Two classes:
| `GE_D86` | `src/game/model.c:6295`, `src/game/objecthandler_2.c:143` | D86 model rwdata trace | dead (D86 closed) |
| `GE_D87` | `src/game/ramromreplay.c:296,363,381` | D87 `ramromfilestructure` endianness | dead (D87 closed) |
| `GE_D88` | `src/game/prop.c:1367`, `src/game/stan.c:3090` | D88 `Usetup*Z` propDef stream | dead (D88 family closed; D88.4 resolved) |
| `GE_D90` | `src/game/bondview_r.c:190,474`, `src/game/bondview2.c:2146`, `src/game/prop.c:1391` | D90 bondview / prop NULL trace | dead (D90 closed) |
| `GE_D90` | remaining: `src/game/bondview2.c:2146`, `src/game/prop.c:1391` (bondview_r.c blocks stripped M-32, `49ce620a`) | D90 bondview / prop NULL trace | dead (D90 closed) — partially removed |
| `GE_D96` | `src/game/chrprop.c:436,507` (cached `probe`) | D96 chrprop trace | dead (D96 closed) |
| `GE_D104` | `src/game/bg.c:654` (rate-limited, `d104c`) | D104 depth-clear trace | dead (D104 closed) |
| `GE_D71LOG` | `port/fast3d/gfx_pc.cpp:645` | D71 fast3d trace | dead (D71 closed) |
| `GE_D75` | `src/game/title.c` `sub_GAME_7F007F30` (capped 8) | D75 Bug 2 gun-barrel model probe: logs `chrModelInstance`/`gunModelInstance` ptr+obj+numMatrices, `render_pos`, `renderData.mtxlist`, `g_GfxMemPos`, `osVirtualToPhysical(render_pos)` | **LIVE** (D75 Bug 2 OPEN — see §F "D75 Bug 2 — RUNTIME PROBE") |
## Notes
- `GE_D63` in `bg.c` at lines 2876 (`static int d63bgprimarycount = 0;`) and
2880-2881 (`if (getenv("GE_D63") && (d63bgprimarycount++ % 500 == 0))`) is
**outside any `#ifdef PORT`** — it currently compiles into the N64 build
path too. Every other `GE_D63` block is `#ifdef PORT` / `#if defined(PORT)`
wrapped. When these are stripped, that one needs the whole 3-line span
removed, not just an inner block.
- The bare non-`#ifdef PORT` `GE_D63` block in `bgRenderRoomPrimary`
(`d63bgprimarycount` static + entry log, was ~`bg.c:2876/2880`) was
removed M-32 (`49ce620a`). Every remaining `GE_D63` block is
`#ifdef PORT` / `#if defined(PORT)` wrapped and inert.
- `[Debug]` ini keys (`Debug.FrameDump`, `Debug.InputLog`) mirror
`GE_PCDUMP` / `GE_INPUTLOG` as a fallback (env var wins) — M-26,
`port/src/config.c`.
+49 -1
View File
@@ -802,7 +802,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D59–D68 | intro render: blood-RLE clobber, DMA validate, OSMesgQueue, HEADS/BODIES sentinels, romCopy width, image_entry, Globalimagetable BE→LE | resolved |
| D69 · D78–D84 | stage load (`load_bg_file`): bg/stan offline sidecar (`d69_emit.py`) + StandTile/bg_room_data ABI | resolved |
| D70–D74 | intro-logo pixels: C-array bswap, UV path, sinf/cosf `DVAL()`, texture-import truncation | resolved |
| D75 · D77 | front-end 3D model transforms · audio | OPEN (parked). **M-32 triage (see §F "D75 ADDENDUM"): (a) D73-scope-gap RULED OUT (gu tree fully endian-clean). Splits in two: Bug 1 = logo/photo transform = the parked D114/D116 fast3d viewport mirror (not game code). Bug 2 = absent animated models = category (b), lead suspect `render_pos`=transient `dynAllocate` arena (D115 MED #5), in-scope fix candidate.** |
| D75 · D77 | front-end 3D model transforms · audio | OPEN (parked). **M-32 triage (see §F "D75 ADDENDUM"): (a) D73-scope-gap RULED OUT (gu tree fully endian-clean). Splits in two: Bug 1 = logo/photo transform = the parked D114/D116 fast3d viewport mirror (not game code). Bug 2 = absent animated models = category (b). M-32b runtime probe (`GE_D75=1`): `render_pos`/`dynAllocate`-arena hypothesis RULED OUT (render_pos valid + fresh each frame), model instances valid (nMtx 21/1), zero fast3d DL warnings — failure is downstream in `drawjointlist`/`dotube` vtx/node-DL resolution or an off-screen `basemtx`. Needs a drawjointlist-level probe.** |
| D76 · D164 | disclaimer/legal screen only draws line 1 — **root-caused (M-31)**: `constructor_menu00_legalscreen` text loop bounds `legal_text_end` on `&legalscreen_MRD`, a linker-adjacency assumption that mingw breaks (`legalscreen_MRD` links 0x60 *before* `legalpage_text_array`) → `do{}while(ptr<end)` runs once. NOT an image-table bug (screen references zero `sImageTableEntry`). | fix proposed (not applied — `front.c` owned by another agent) |
| D159 | front-end wallet-Bond photo "interlaced"/combed (RC1 / D149) — `texSwapAltRowBytes` odd-row 8-byte pre-swap (N64 RDP odd-line TMEM XOR compensation) not reversed by fast3d | FIXED (`#ifdef PORT` no-op the swap in `image.c`) |
| D161 | Depot (`-level_30`) ceiling = bright-blue speckle + radial rays (B2). A CI8 tile drawn with `gsDPSetTextureLUT(G_TT_NONE)` was decoded against the stale `rdp.palette` → garbage. Fix: `#ifdef`-free narrow route CI→I when `palette_fmt == G_TT_NONE` in `gfx_pc.cpp import_texture()`. | FIXED (`port/fast3d/gfx_pc.cpp`) |
@@ -2657,6 +2657,54 @@ real, in-scope lead at `title.c:220` `(s32)&symbol` truncation +
`#ifdef PORT` `(uintptr_t)` cast there and a capped probe, not a static pass.
Confidence overall: **medium** (triage solid, no runtime confirmation).
**D75 Bug 2 — RUNTIME PROBE (session M-32b, `GE_D75=1` in `title.c`
`sub_GAME_7F007F30`, kept env-gated).** Booted the bare front end
(`GE_D75=1 GE_PCDUMP="1-1200:120"`, no `-level`) and captured through the
gun-barrel sequence. Findings:
- **Visually confirmed:** the gun-barrel spiral circles (2D backdrop DL)
render fine; the animated **Bond chr model AND the gun model are
entirely absent** — no silhouette, no muzzle. `chrModelInstance`
(`obj=0x14012da80`, `numMatrices=21`) and `gunModelInstance`
(`obj=0x140148620`, `numMatrices=1`) are **both non-NULL with valid
`obj` pointers and sane matrix counts** — so mechanism (2) "model file
not loaded / manifest row missing" is **ruled out**.
- **`render_pos` is NOT stale / clobbered — mechanism (1) as stated is
ruled out.** Per-frame `chrModelInstance->render_pos` alternates cleanly
between `0x700a8f10` and `0x700a3f10` (delta `0x5000` = the double-buffer
swap). On each frame `render_pos` == the `renderData.mtxlist` base that
`dynAllocate(21<<6)` returned *that same frame* (`gfxpos 0x700a9490` −
`0x540` chr − `0x40` gun = `0x700a8f10` exactly), i.e. it points at the
freshly-`subcalcmatrices`-written matrices, exactly as on N64. It is a
real low-DRAM (`0x700xxxxx`) address; `osVirtualToPhysical(render_pos)`
returns it **unchanged** (no D131 truncation). Nothing overwrites the
arena between the write and the draw within the frame.
- **fast3d logs ZERO DL warnings** during the whole sequence (no
"ending DL" / unknown-opcode / `fast3d_ptr_ok` / bad-matrix-substitution
lines) — so Bug 2 is **not** the D144/D146 corrupt-front-end-sub-DL
family either. The Bond/gun DL is submitted and consumed silently but
emits no visible geometry.
- Mechanism (3), the `(s32)&ANIM_DATA_bond_eye_fire` truncation, was not
the probe's focus but the model has valid matrices regardless, so a
broken anim would at worst freeze a pose, not delete the model.
**Where that leaves Bug 2:** the failure is **downstream of matrix setup**
— inside `drawjointlist` / `modelRenderNodeDl` / `dotube` for these
title-screen `Model` instances: either the joint **vertex / node-DL
segmented-pointer resolution** produces no tris, or the model is
transformed off-screen / to zero scale by `renderData.basemtx`
(`= matrix` from `manipulateGunbarrelAndLogoMatrices`, which folds
compiled DL pointers through `OS_K0_TO_PHYSICAL` at `title.c:121/123/138`
— a D58/D84-class `(u32)`-wrap candidate, though the backdrop DLs it
feeds *do* render). **Next probe:** inside `drawjointlist`/`dotube` at the
gun-barrel frame, log the resolved `vtx`/`nodeDl` pointers and whether
`modelRenderNodeDl` emits any `gSPVertex`/`gSP1Triangle`, plus the
composed `basemtx * render_pos` for joint 0 (is it in the view frustum?).
Confidence the cause is joint vtx/DL resolution vs off-screen transform:
**low** — needs the drawjointlist-level probe. The `render_pos`-arena
in-scope fix hypothesised above is **no longer the lead** — do not land a
persistent `render_pos` buffer, it would not change anything.
**D76 (OPEN: 2D graphics — disclaimer/legal screen only partially drawn). ROOT-CAUSED (M-31) → D164.**
The image-table/D68 hypothesis is **wrong**: the legal screen (`constructor_menu00_legalscreen`,
`front.c:1523`) references **zero** `sImageTableEntry`s — it is 12 lines of `langGet()` font text
+20
View File
@@ -26,6 +26,10 @@
#include "title2.h"
#include "title3.h"
#ifdef PORT
#include <stdlib.h>
#endif
extern signed short sins(unsigned short x);
@@ -266,6 +270,22 @@ Gfx *sub_GAME_7F007F30(Gfx *gdl, s32 count, Mtxf *matrix)
renderData.zbufferenabled = FALSE;
renderData.gdl = gdl;
renderData.flags = 1;
#ifdef PORT
{
extern u8 *g_GfxMemPos;
static int s_d75n = 0;
if (getenv("GE_D75") && s_d75n < 8) {
osSyncPrintf("D75 gb#%d chrMI=%p obj=%p nMtx=%d rp=%p | gunMI=%p obj=%p nMtx=%d rp=%p | mtxlist=%p gfxpos=%p o2p(rp_chr)=%08x\n",
s_d75n, chrModelInstance, chrModelInstance->obj,
(int)chrModelInstance->obj->numMatrices, chrModelInstance->render_pos,
gunModelInstance, gunModelInstance->obj,
(int)gunModelInstance->obj->numMatrices, gunModelInstance->render_pos,
renderData.mtxlist, (void *)g_GfxMemPos,
(unsigned)osVirtualToPhysical(chrModelInstance->render_pos));
s_d75n++;
}
}
#endif
drawjointlist(&renderData, entry);
renderData.flags = 2;