From e61bc1fae123537d40c75366e2feb748ce4c8c4a Mon Sep 17 00:00:00 2001 From: James Dansereau <106631954+jkdansereau@users.noreply.github.com> Date: Fri, 28 Aug 2026 13:05:16 -0400 Subject: [PATCH] docs: D93 resolved (null-room NULL guards); D85 root cause confirmed (8B vs 16B Gfx) --- docs/HANDOFF.md | 39 +++++++++++++++++++++++++-------------- docs/PCPortResearch.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index a5664247..d1c26485 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -6,14 +6,24 @@ _Paste-ready brief. Authoritative context: `AGENTS.md`, ## READ THIS FIRST — the crash chain is clear; the blocker is now rendering -D88.1–D88.6 + D89 + D90 + D91 + D92 are **committed**. A direct -`-level_09` boot now loads BUNKER1's full stage setup, runs path-table / -intro-section setup, spawns the player and chrs, ticks AI, and reaches -the **first render** — where it hits **D85**: `sysFatalError("Bad size -for RGBA texture in tile 0: 00")` (`gfx_pc.cpp:967`), i.e. the room GDL -binary decodes to a garbage GBI stream. This is 3D-pipeline / render- -milestone work, not a crash-chain fix. Full analysis: `PCPortResearch.md` -§F **D85 revisited**. +D88.1–D88.6 + D89 + D90 + D91 + D92 + **D93** are **committed** (D93 = +`164d7f99`). A direct `-level_09` boot now loads BUNKER1's full stage +setup, runs path-table / intro-section setup, spawns the player and +chrs, ticks AI, and reaches the **first render** — where it hits +**D85**: `sysFatalError("Bad size for RGBA texture in tile 0: 00")` +(`gfx_pc.cpp:967`), i.e. the room GDL binary decodes to a garbage GBI +stream. This is 3D-pipeline / render-milestone work, not a crash-chain +fix. + +**D85 is now root-caused (`PCPortResearch.md` §F "D85 root cause +CONFIRMED").** The decompressed per-room DL blob is raw N64 data (8-byte +BE `Gfx` slots); all PORT consumers (`texCopyGdls`/`texLoadFromGdl`, +`bgApplyDynamicCCRMLUT`, `bgBuildRoomVtxBounds`) assume 16-byte LE PC +`Gfx` slots → 2× stride + unswapped words → garbage opcodes. Fix = +runtime 8→16 widen + `bswap32` in `bgLoadRoomPrimaryGdl` / +`bgLoadRoomSecondaryGdl` (between `bgDecompress` and `texCopyGdls`), plus +a `Vtx` short-field bswap in `bgLoadRoomVtxData`. Implementation in +progress — check `git log` for a `D85:` commit chain. - Build: `export PATH="/c/msys64/mingw64/bin:$PATH" && ./build-pc.sh ntsc-final` - Sidecar regen (REQUIRED after this session — D88.5/D88.6 changed the @@ -47,12 +57,13 @@ milestone work, not a crash-chain fix. Full analysis: `PCPortResearch.md` `Model.unka0` `s32` field truncated a stored function pointer. **Next steps for the resuming session (render milestone):** -1. **D85** — the room GDL binary decodes to a garbage GBI command stream - (`fmt=RGBA siz=0`). Decode what `texLoadFromGdl` does with room- - specific opcodes / CC-RM-LUT markers; verify `csize_*_DL_binary` - sizing. See §F D85 + "D85 revisited". Quick unblock option: soften the - four `sysFatalError("Bad size…")` guards in `gfx_pc.cpp` to - skip-with-warning so the frame renders with placeholder textures. +1. **D85** — root cause confirmed (8-byte N64 `Gfx` vs 16-byte PC `Gfx` + in the unconverted per-room DL blob). Runtime widen+bswap fixup being + implemented; verify with `GE_D69BB=1` (real GBI opcodes, not + 00/01/02/52), then `GE_PCDUMP` + `tools_pc/pixcount.py` for + non-degenerate BUNKER1 geometry. See §F "D85 root cause CONFIRMED". + Fallback if the widen stalls: soften the four `sysFatalError("Bad + size…")` guards in `gfx_pc.cpp` to skip-with-warning. 2. Then the front-end **render bugs (D75)**. **D88.4 loose end (still open):** `PROPDEF_PC_BYTES` for `VEHICHLE`/ diff --git a/docs/PCPortResearch.md b/docs/PCPortResearch.md index 433da9de..08dc54d6 100644 --- a/docs/PCPortResearch.md +++ b/docs/PCPortResearch.md @@ -3012,6 +3012,45 @@ session wants to keep moving past it: soften the four `sysFatalError` safety-net philosophy as the D85 `bgBuildRoomVtxBounds` bounds check) so the frame renders with placeholder textures instead of aborting. +**D93 (RESOLVED — null-room (room 0) NULL-deref sat in front of the D85 +texture wall).** Committed `164d7f99`. On `-level_09` the visible-room +draw list includes room 0, which has no geometry (`csize_*_DL_binary == +0`), so `bgLoadRoomModelData` never assigns `ptr_expanded_mapping_info` +and it stays NULL. Two consumers then walk it unconditionally: +`bgApplyDynamicCCRMLUT` (called `start=NULL, end=NULL` → the `end==NULL` +sentinel-scan branch derefs address 0) and `bgBuildRoomVtxBounds` +(`while (gdl[i].dma.cmd != G_ENDDL)` on `gdl=NULL`). On N64 address 0 is +readable RDRAM so both walks wander harmlessly; PC page 0 is unmapped. +Fixed with narrow `#ifdef PORT` NULL guards (same safety-net class as the +D85 `bgBuildRoomVtxBounds` vtx-bounds check). `-level_09` now reaches the +documented D85 `sysFatalError("Bad size for RGBA texture in tile 0: 00")`. + +**D85 root cause CONFIRMED (was "not yet root-caused").** The +decompressed per-room primary/secondary DL blob is **raw N64 data with +8-byte big-endian `Gfx` slots**, but every PORT-patched consumer +(`texCopyGdls`/`texLoadFromGdl` in `tex.c`, `bgApplyDynamicCCRMLUT`, +`bgBuildRoomVtxBounds`) was patched under `#ifdef PORT` to assume 16-byte +little-endian PC `Gfx` slots — so they stride at 2× the real rate and +read the middle of each N64 command pair as an opcode (the observed +`cmd=00,01,02,52…` garbage), and even at the right stride the `w0/w1` +words are unswapped BE. The model-GDL path is immune only because its +offline sidecar (`tools_pc/d43_*.py`) pre-widens + byteswaps every GDL; +D80 explicitly left the per-room DL/point-index blob unconverted. +**Fix chosen: runtime fixup**, not a sidecar — the blob is RZ-compressed +inside the bg `.seg` and delta-sized (its size is only the offset delta +between consecutive rooms' `pPriMappingBin`), so an offline widen would +force rewriting the whole bg-header offset table / recompression. The +transform is purely mechanical (8→16 byte widen + `bswap32` each word); +room GDLs need no pointer remapping (`G_VTX` seg addresses are resolved +at runtime via `SEGMENT_OFFSET(...) + (u32)vertices`, textures via the +`G_NOOP`+`texnum` marker). Implemented in `bgLoadRoomPrimaryGdl` / +`bgLoadRoomSecondaryGdl` between `bgDecompress` and `texCopyGdls`, plus a +`Vtx` short-field bswap in `bgLoadRoomVtxData` (positions/uv are BE; the +4 rgba `u8`s are fine). Watch the alloc budget — the PC blob is 2× the +decompressed size. Also fix the pre-existing bug at `bg.c:2448`: +`texLoadFromGdl((Gfx *)scratch, (Gfx *)expanded_size, ...)` casts the +size arg to a pointer. + **Docs-to-commit reminder (session L).** The D88.1–D88.3 work (`tools_pc/d88_emit.py`, `port/src/pccg.c`, `src/bondtypes.h`, `src/game/bondview2.c`, `src/game/bondview_r.c`) plus the `GE_D88` probes