Docs: track open issues D75-D77 (3D render, 2D partial draw, no audio)

Carry over the logo-pixel session's handoff state: D75-D77 recorded as
OPEN in PCPortResearch.md §F with candidate causes + verification steps,
prioritization guidance (D69 stays primary; render before audio unless a
shared root cause is found - Q1), and matching AGENTS.md phase-status line.
HANDOFF also drops the stale scratch-file list from Task 3 and points at
the relocated N64 reference screenshots.
This commit is contained in:
James Dansereau committed 2026-08-27 19:26:57 -04:00
1 parent 978306d14f
commit d3b3fe53ce
3 files changed
+78 -6

No files matched your search

+1 -1
View File
@@ -48,6 +48,6 @@ Run `/linkcheck` for this sweep. Record new findings in `docs/PCPortResearch.md`
- **Compile+link milestone:** all ~235 TUs compile and `ge007.x86_64.exe` links clean (`ninja ge007 -k 0`, 236/236). Findings D7–D17 in `docs/PCPortResearch.md` §11; asset stubs in `port/src/assetstubs.c`, fast3d no-ops in `port/src/gfxstub.c` (delete when real fast3d lands).
- **Phase 1 (boot to window):** done — ROM loads/validates/maps at cart base 0x10000000 (`romdata.c`), SDL2 window + GL clear loop (`video.c`), absolute asset symbols from `scripts/gen_romassets.py` → `port/src/romassets_<r>.s` (findings D18–D23).
- **Phase 1.5 (boot to first frame):** DONE — boot chain complete AND real frames render (`[NOTE] frame N rendered in … us`). D34–D42 closed the blockers on top of D31–D33: ANIM_DATA lvalues, music seq-table ABI+endianness, music-heap sizing, libaudio bank-tree re-layout, implicit-declaration prototype shim (D38), Globalimagetable rebasing + true segment size (D39), ModelHitEntry pool sizing (D40), cross-thread GL context release (D41), rsp task-settings toggle (D42). ROM dump verified against the No-Intro good dump (byte-identical, header CRCs re-checked — `tools_pc/romverify.c`).
- **Phase 2 (rendering):** IN PROGRESS — fast3d integrated + real frames render. **Plan B EXECUTED (D50, committed):** all 512 NTSC model files converted offline by `tools_pc/d43_emit.py` → `data/pcmodels-ntsc-final/pcmodels.bin` + manifest.csv (single concatenated RZ image; regenerate per region with the script — sidecars are gitignored), served through the existing load path via a port-layer table patch (`port/src/pcmodels.c`, romdata cart-extension, one-shot `pcmodelsPatchTable()` + poolRemaining reset hook in `load_object_fill_header`); runtime C fixups for language-bank BE offset tables + font re-layout (D50.3/D50.4); legal-screen UB seed (D50.5); **D50.6 fixed the first model-render crash** — `texCopyGdls` copied only w0 of each 16-byte Gfx slot on PC (the union's trailing `long long` is 8 bytes), leaving stale mempool w1s in the compacted GDLs; byte-proven against PlegalpageZ, fixed with a full-slot copy under #ifdef PORT. Model GDLs now execute to completion (PlegalpageZ sub-DLs). **D51 RESOLVED** (font `pixeldata` fixup wrote the pointer at the wrong offsets — frame-5 `import_texture_i8` crash gone; GE opcode space decoded along the way, G_TEXRECT=0xE4/0xE5 non-F3DEX numbering), **D52 RESOLVED** (`osGetCount` now advances at the N64 RSP counter rate ≈ 46.5525 ticks/µs — fixed the non-deterministic post-frame-2 hang), **D53 RESOLVED** (model RW-data pool addressing: D53.1 `Model.datas` word-stride → `u32 *` under PORT + casts; D53.2 ModelSlot/AnimModelSlot re-laid on top of the PC struct Model — in-use@0x10 / pool@0x20, slot size = sizeof(Model) = 0xE8 — plus PORT-guarded heap-fallback bumps in model.c), **D54 RESOLVED** (cseq ALCMidiHdr BE header: port-layer `romdataFixupCseq` bswap32 of the first 17 u32s, called from music.c after each decompress), **D54b RESOLVED** (synth param slots sized for ALStartParamAlt = 0x28 in synthesizer.c alSynInit under PORT), **D55 RESOLVED** (RLE folder-menu background BE w/h header: bswap32 of the first word at `(u32 *)&unknown2` at cart-map time in romdataInit, guarded). Build GREEN; game boots, plays intro music, renders through logo/gun-barrel, instantiates Brosnan, and executes the gun-barrel hole DL clean to ENDDL. **D56 RESOLVED** (watch Model/RW-pool raw offsets: field-name Model access + static 0xC8-byte pool under PORT in bondview2.c), **D57 RESOLVED** (pointer-grown rwdata records overflowed N64-sized spare pools — Brosnan PC numRecords 153 > 140: capacities grown in initunk_005520.c + dynamic slot+pool fallback in model.c), **D58 RESOLVED** (gun-barrel DL: vertex-pointer K0 idiom rebuilt via `OS_K0_TO_PHYSICAL(…) | 0x80000000` in title.c + DL reserve 0x100→0x200 because `sizeof(Gfx)` is 16 on PC). **D59–D68 RESOLVED (committed):** the "GL DLL" crash was D64's unbounded blood-RLE write (sentinel section-adjacency lost on PC) clobbering the gun-barrel sub-DL; then D60–D62 (DMA target validation, OSMesgQueue layout), D65/D65b (HEADS/BODIES enum signed sentinels under PORT), D66 (romCopyAligned + ramrom replay 64-bit pointer width), D67 (struct image_entry N64 layout), **D68 (Globalimagetable BE→LE fixup** — `port/src/gimgfixup.c` bswaps IMAGESEG Gfx w1 words + sImageTableEntry.index after texReset's romCopy; compiled globalDL shadows synced for explosion.c). The game now renders the **entire intro** (logo → gun barrel w/ Brosnan → cast; ~frame 2100, ≈2 min wall-clock at the current ~20 fps clean-run rate). **Current blocker D69:** `load_bg_file` (bg.c:830) faults on first stage load — BG-file headers/records are N64 big-endian segment-0x0F offsets, read LE on PC; the bg `.seg` + `Tbg_*_stanZ` format work is next (decode from bg.c/stan.c → offline sidecar conversion per the D43 pattern or runtime port-layer fixup; PD `preprocess/filebg.c` is approach-reference only — its BG format differs). **D70–D74 (intro-logo pixels, RESOLVED):** D70 env-gated PPM frame capture (`GE_PCDUMP` → `./ppm/`, gitignored — kept as permanent dev tooling); **D71** C-array texture sources (the four rarewarelogo.c RGBA16 images) byte-swapped on LE PC → port-layer per-source bswap in `import_texture`; **D72** the UV path (GE always uses authored `tc[]` UVs; `lookat_enabled` defaults false); **D73 = root cause of old D72.3** — sinf/cosf `du` double constants are big-endian word pairs, garbage on LE PC → guMtxF2L emitted −32768 for every sin/cos entry → logo triangles projected off-screen; fixed with the PORT-only `DVAL()` macro in `src/libultra/gu/guint.h` (sinf.c/cosf.c `.d` reads replaced; N64 build untouched); **D74** texture import fallback no longer truncates valid gDPLoadBlock data (was dropping letter mip chains + reducing D_02005FF0 to 32×3), `TextureCacheKey` gained `size_bytes`, and the VBO path wraps UVs by tile size for WRAP sub-tiles (N64 semantics). The Rareware logo now renders its four gold letters on the dark-blue plate (PPM-verified ~frame 555; final pixel-perfect check vs N64 footage optional). D69 remaLine truncated
- **Phase 2 (rendering):** IN PROGRESS — fast3d integrated + real frames render. **Plan B EXECUTED (D50, committed):** all 512 NTSC model files converted offline by `tools_pc/d43_emit.py` → `data/pcmodels-ntsc-final/pcmodels.bin` + manifest.csv (single concatenated RZ image; regenerate per region with the script — sidecars are gitignored), served through the existing load path via a port-layer table patch (`port/src/pcmodels.c`, romdata cart-extension, one-shot `pcmodelsPatchTable()` + poolRemaining reset hook in `load_object_fill_header`); runtime C fixups for language-bank BE offset tables + font re-layout (D50.3/D50.4); legal-screen UB seed (D50.5); **D50.6 fixed the first model-render crash** — `texCopyGdls` copied only w0 of each 16-byte Gfx slot on PC (the union's trailing `long long` is 8 bytes), leaving stale mempool w1s in the compacted GDLs; byte-proven against PlegalpageZ, fixed with a full-slot copy under #ifdef PORT. Model GDLs now execute to completion (PlegalpageZ sub-DLs). **D51 RESOLVED** (font `pixeldata` fixup wrote the pointer at the wrong offsets — frame-5 `import_texture_i8` crash gone; GE opcode space decoded along the way, G_TEXRECT=0xE4/0xE5 non-F3DEX numbering), **D52 RESOLVED** (`osGetCount` now advances at the N64 RSP counter rate ≈ 46.5525 ticks/µs — fixed the non-deterministic post-frame-2 hang), **D53 RESOLVED** (model RW-data pool addressing: D53.1 `Model.datas` word-stride → `u32 *` under PORT + casts; D53.2 ModelSlot/AnimModelSlot re-laid on top of the PC struct Model — in-use@0x10 / pool@0x20, slot size = sizeof(Model) = 0xE8 — plus PORT-guarded heap-fallback bumps in model.c), **D54 RESOLVED** (cseq ALCMidiHdr BE header: port-layer `romdataFixupCseq` bswap32 of the first 17 u32s, called from music.c after each decompress), **D54b RESOLVED** (synth param slots sized for ALStartParamAlt = 0x28 in synthesizer.c alSynInit under PORT), **D55 RESOLVED** (RLE folder-menu background BE w/h header: bswap32 of the first word at `(u32 *)&unknown2` at cart-map time in romdataInit, guarded). Build GREEN; game boots, plays intro music, renders through logo/gun-barrel, instantiates Brosnan, and executes the gun-barrel hole DL clean to ENDDL. **D56 RESOLVED** (watch Model/RW-pool raw offsets: field-name Model access + static 0xC8-byte pool under PORT in bondview2.c), **D57 RESOLVED** (pointer-grown rwdata records overflowed N64-sized spare pools — Brosnan PC numRecords 153 > 140: capacities grown in initunk_005520.c + dynamic slot+pool fallback in model.c), **D58 RESOLVED** (gun-barrel DL: vertex-pointer K0 idiom rebuilt via `OS_K0_TO_PHYSICAL(…) | 0x80000000` in title.c + DL reserve 0x100→0x200 because `sizeof(Gfx)` is 16 on PC). **D59–D68 RESOLVED (committed):** the "GL DLL" crash was D64's unbounded blood-RLE write (sentinel section-adjacency lost on PC) clobbering the gun-barrel sub-DL; then D60–D62 (DMA target validation, OSMesgQueue layout), D65/D65b (HEADS/BODIES enum signed sentinels under PORT), D66 (romCopyAligned + ramrom replay 64-bit pointer width), D67 (struct image_entry N64 layout), **D68 (Globalimagetable BE→LE fixup** — `port/src/gimgfixup.c` bswaps IMAGESEG Gfx w1 words + sImageTableEntry.index after texReset's romCopy; compiled globalDL shadows synced for explosion.c). The game now renders the **entire intro** (logo → gun barrel w/ Brosnan → cast; ~frame 2100, ≈2 min wall-clock at the current ~20 fps clean-run rate). **Current blocker D69:** `load_bg_file` (bg.c:830) faults on first stage load — BG-file headers/records are N64 big-endian segment-0x0F offsets, read LE on PC; the bg `.seg` + `Tbg_*_stanZ` format work is next (decode from bg.c/stan.c → offline sidecar conversion per the D43 pattern or runtime port-layer fixup; PD `preprocess/filebg.c` is approach-reference only — its BG format differs). **D70–D74 (intro-logo pixels, RESOLVED):** D70 env-gated PPM frame capture (`GE_PCDUMP` → `./ppm/`, gitignored — kept as permanent dev tooling); **D71** C-array texture sources (the four rarewarelogo.c RGBA16 images) byte-swapped on LE PC → port-layer per-source bswap in `import_texture`; **D72** the UV path (GE always uses authored `tc[]` UVs; `lookat_enabled` defaults false); **D73 = root cause of old D72.3** — sinf/cosf `du` double constants are big-endian word pairs, garbage on LE PC → guMtxF2L emitted −32768 for every sin/cos entry → logo triangles projected off-screen; fixed with the PORT-only `DVAL()` macro in `src/libultra/gu/guint.h` (sinf.c/cosf.c `.d` reads replaced; N64 build untouched); **D74** texture import fallback no longer truncates valid gDPLoadBlock data (was dropping letter mip chains + reducing D_02005FF0 to 32×3), `TextureCacheKey` gained `size_bytes`, and the VBO path wraps UVs by tile size for WRAP sub-tiles (N64 semantics). The Rareware logo now renders its four gold letters on the dark-blue plate (PPM-verified ~frame 555; final pixel-perfect check vs N64 footage optional). D69 remaLine truncated
- **Phase 3 (audio + input):** libaudio → SDL — largely copy-and-adapt from PD (`mixer.c` 722 lines vs our 31-line stub; `input.c` SDL_GameController backend; §2.4); decide the ASP strategy (C2: `aspMain*` dummies in `ucode.c`).
- **Phase 4 (saves + polish):** file-backed EEPROM — build on PD's `fs.c` (file-backed save dir); PFS/motor already no-op stubs.
+29 -5
View File
@@ -15,8 +15,9 @@ is the summary + the immediate tasks._
- **Secondary (low priority):** final pixel check of the intro logo. D73 +
D74 fixed it at the data level and PPM frames ~550–560 show four gold
letters on the dark-blue plate; compare against N64 reference footage if
time allows (reference screenshots are at repo root: `Graphics Screenshot
2026-08-24 121659.jpg`, `gun barrel.png`).
time allows (N64 reference footage screenshots are in `docs/reference/`:
`n64-footage-2026-08-24.jpg`, `n64-footage-gun-barrel.png`; captured with
the local Mupen64 checkout in `tools_pc/mupen64/`, gitignored).
- Work agentically: decode → implement → build (~5 s) → verify → commit at
each sub-milestone (document findings as D7x in §F).
@@ -51,6 +52,29 @@ is the summary + the immediate tasks._
- **Committed through D74.** This session's TEMP probes are all stripped;
previously committed TEMP diagnostics remain — strip list in Task 3.
## Known issues — open (reported this session; tracked in PCPortResearch.md §F as D75–D77)
Not part of the D69 task, but reported alongside it and **not yet root-caused** (OPEN):
- **D75 (HIGH):** 3D rendering still wrong — Nintendo logo misplacement + intro cutscene
player models absent (Rareware logo is fine). Suspected D73 matrix-path scope gap *or* a
separate model/RW-pool bug (cf. D56) — the 75a/75b split must be decided first.
- **D76 (MED):** 2D partial draw — disclaimer screen shows only "game classification" + one
line. Suspected incomplete D68 image-table fixup for some entries this screen references.
- **D77 (LOW):** no audible music on PC despite a clean audio thread. Suspected SDL device /
mixer not wired up (distinct from D54/D54b, which only stopped crashes).
**Prioritization guidance (owner, this session):**
- **D69 (BUNKER1 `load_bg_file` crash) stays the primary milestone task** — do not let the
D75–D77 visual/audio items displace it.
- Among D75–D77: **rendering (D75) is prioritized over audio (D77)** on the assumption the
render pipeline is the harder/riskier PC-port work and audio is simpler.
- **Exception:** first spend one check on Q1 (shared root cause across audio + rendering). If a
single blocker affects both, resolve it before splitting effort. Evidence so far says they are
independent subsystems → default to render-first.
- Each fix remains a narrow `#ifdef PORT` ABI/endianness exception documented as its own D7x
finding when resolved (N64 build untouched; game logic unmodified).
## The blocker, precisely (D69)
`load_bg_file` (src/game/bg.c:800+) for level BUNKER1:
@@ -146,9 +170,9 @@ are already stripped. Previously committed TEMP diagnostics still in the tree
n64stubs.c, libultra.c, romdata.c: leftover TEMP blocks from D51–D66
(decide per item; D60's DMA target validation is a permanent safety net and
should stay).
- Scratch files at repo root: `run_*.log`, `d62mesg.log`, `all.txt`, `b3.c`,
`btest*.c`, `buildtest.txt`, `err.txt`, `gcout.txt`, `preproc.txt`,
`vsize.c/.exe`, `scratch-logs/` — delete (add to .gitignore if they recur).
- Scratch files at repo root (`run_*.log`, `all.txt`, `b3.c`, `buildtest.txt`,
etc. from earlier sessions) have been deleted; if new scratch files appear,
delete them before committing (patterns are already in .gitignore).
## Standing procedure (per AGENTS.md)
+48
View File
@@ -2435,6 +2435,54 @@ is still open (see HANDOFF Task 1). All env-gated probes added for D72.3/D74
were stripped with this change; the previously committed TEMP D63 blocks and
the GE_D71LOG normalize log remain on the HANDOFF strip list.
**D75 (OPEN: 3D rendering — Nintendo logo misplacement + missing intro player models).**
Post-D74 the Rareware logo is correct (gold letters on dark blue), but two other intro 3D
elements are still wrong: the **Nintendo logo is not placed correctly**, and the **intro
cutscene player models do not appear at all**. Two candidate causes — distinguish before
any fix:
- **(a) D73 scope gap.** D73 (`DVAL()` in `src/libultra/gu/guint.h`, PORT-only) was
documented as fixing *"all scenes using guRotate/guLookAt-derived matrices … not just the
logo."* If these elements still fail, either their matrix path bypasses that fix or a
second coordinate defect remains.
- **(b) Separate model/RW-pool path.** The player models specifically may be on the
`animInit` + embedded raw-offsets-into-`struct player` path (cf. D56), which is *not* the
guMtxF2L sin/cos path — i.e. an independent bug, not "the same coordinate issue."
Files to check: `src/libultra/gu/guint.h`, `src/game/model.c`, `bondview2.c` (animInit /
modelSetScale sites), `port/fast3d/gfx_pc.cpp`. Verify: determine whether the Nintendo logo
and intro player models build matrices via guRotate/guLookAt (→ 75a) or another transform
(→ 75b); capture `GE_PCDUMP` frames across the logo transition and the gun-barrel/cast
segments to localize.
**D76 (OPEN: 2D graphics — disclaimer/legal screen only partially drawn).**
On the opening disclaimer (legal text) screen, only the **"game classification"** line and
**one line below it** draw correctly; the rest of the 2D graphics do not render. Likely the
same image-table/endianness class as D68 but incomplete: D68 (`port/src/gimgfixup.c`) bswaps
IMAGESEG Gfx w1 words + `sImageTableEntry.index` after texReset's romCopy and syncs compiled
globalDL shadows — if a subset of the entries this screen references is missed (or its shadow
not synced), exactly this "only a couple of lines render" symptom results. Secondary
possibility: D74 sub-tile UV wrapping, if those lines use WRAP sub-tiles (was 3D-logo
specific, so lower likelihood). Files to check: `port/src/gimgfixup.c`, `src/game/tex.c`, the
image-table consumers. Verify: enumerate the image entries the disclaimer screen references and
confirm each is covered by the D68 fixup; PPM frames f20–f100 (legal-text window per the D70
timeline).
**D77 (OPEN: audio — music runs in code but no audible output on PC).**
Intro music is processed without fault, but **nothing reaches the PC speakers.** This is
distinct from the earlier audio work: D54/D54b only stopped the audio-thread SIGSEGVs
(`__getTrackByte`, `alLoadParam`); they do not imply the mixed output is routed to a device.
Per §6 Audio the intended path is libaudio (CPU synth) → PD's `audio.c` (SDL device) +
`mixer.c`; the likely gap is that the SDL audio device / mixer queue is never opened or fed —
synthesis runs but the AI-DMA→device handoff never happens. Files to check: `port/src/audio.c`,
`port/src/mixer.c`, `src/audi.c` (`OUTPUT_RATE`), and the AI shim in `port/src/libultra.c`.
Verify: confirm an SDL audio device is opened and the mix buffer is written/pushed; check
`OUTPUT_RATE` match (PD = 22020 Hz stereo s16) and that the AI-DMA shim feeds it.
**Cross-cutting (Q1 — shared blocker?):** before ordering D75 vs D77, spend one check on whether
any single root cause touches both audio and rendering. Current evidence says **independent**
(audio = libaudio→SDL device; 3D = fast3d RSP emulation; 2D = image-table fixup + texture
import) — default to render-first if no shared cause is found.
**Non-negotiable #2 refinement (applied to AGENTS.md).** The original "game code
compiles unmodified / fix belongs in port/" is too absolute: pointer-width layout
cannot be isolated in `port/` (no hook between the romCopy and the first read).