forked from Ports/goldeneye-pc-port
* D250: fix sysSleep unit-conversion bug in frame-pacing; add GE_D250 lvlRender probe port/fast3d/gfx_sdl2.cpp sync_framerate_with_timer() computed the remaining frame budget in 100ns units (qpc_to_100ns) and passed it straight into sysSleep(), which takes microseconds -- a real 10x oversleep whenever that branch fires. Genuine bug, but only active when target_fps is nonzero (tied to Input/Video FpsCap); confirmed via live testing that it is NOT the active cause of the user's reported ~45-50fps with FpsCap=0/VSync=0, where this pacing path never runs. Added GE_D250 (src/boss.c, #ifdef PORT) to isolate lvlRender()'s DL-building cost (culling/animation/scene traversal) from gfx_run's already-measured software-RSP interpretation cost. Live test on Dam shows lvlRender averaging ~0.5-1.5ms -- also not the bottleneck. Documented in docs/dev/GE-ENV-PROBES.md (GE_D250 row). findings.md D250 update to follow after rebase. Claude-Session: https://claude.ai/code/session_016DQUKGLZxFtPy52MkKXXog * docs(D250): live A/B session -- MSAA/aniso/FOV/resolution/vsync all ruled out Live session with the user driving the game directly, confirmed the sim-healthy/render-sagging pattern from earlier idle testing reproduces under real play on Dam. One-at-a-time A/B via the F10 overlay ruled out MSAA, anisotropy, FOV, resolution (1280x960 fullscreen vs 640x480 windowed), and VSync (render never exceeds ~60 even uncapped) as the cause -- the cost is resolution/GPU-setting-independent. gfx_run (~6-10ms) + lvlRender (~0.5-1.5ms, via the new GE_D250 probe) together don't account for the real ~20-22ms/frame. Leading remaining suspect: the emulated N64 thread-handoff/scheduler round-trip (gesched.c/sched.c) -- real OS context-switch/wake latency standing in for what was free hardware handoff on N64. Needs a real profiler (Visual Studio / WPR) attached during a live bad-fps moment to confirm; ad-hoc per-call timers have now ruled out the two most obvious CPU call sites without finding the cost. Claude-Session: https://claude.ai/code/session_016DQUKGLZxFtPy52MkKXXog * D250: fix uncached getenv() in fast3d hot paths -- root cause of the fps drop A live WPR/xperf CPU trace (tools_pc/perf.ps1, new sister script to debug.ps1) with Microsoft public symbols resolved found the dominant render thread spending only 5.2% of its CPU time in the game's own code -- 43% was in msvcrt.dll, and getenv()/_getenv_helper_nolock alone accounted for ~50% of the thread's total CPU time. Root cause: port/fast3d/gfx_pc.cpp's import_texture() (runs on every texture bind) and several per-triangle/per-G_SETCOMBINE debug-probe checks (GE_DTEX, GE_TEXDUMP, GE_TEXRAW, GE_D229 x2, GE_D172 x2, plus GE_TEXDUMP/GE_PCDUMP in gfx_opengl.cpp) called getenv() uncached on every call, unlike the safe static-cached pattern already used elsewhere in this codebase. On a texture-heavy scene that's tens of thousands of locked, locale-aware Windows CRT environment lookups per second -- invisible to both of the timers added earlier this session (gfx_run's own cost measurement and the new GE_D250 lvlRender probe), since neither isolates CRT/library time from the game's own code. Fix: cache every getenv() site in gfx_pc.cpp/gfx_opengl.cpp with the established static-int pattern. Narrow, mechanical, no logic change. Verified: the exact idle-Dam test that was pinned at 45-50fps before the fix now holds a rock-steady 60-61fps, zero dips. Also explains why the earlier MSAA/aniso/FOV/resolution/vsync A/B pass all showed "no change" -- the getenv() cost was a large per-call constant that swamped any real, smaller resolution-dependent GPU cost at every setting tried. Residual, separate issue found once this was fixed: still runs badly at 1440p+ (640x480 now holds a clean 60fps) -- likely the real GPU fill-rate cost the getenv() bug was masking, now exposed on its own. Not yet investigated. docs/dev/findings.md D250 updated with the full root-cause writeup. docs/porting-notes.md gets a new lesson under section E (cache getenv() in any hot-path probe). tools_pc/perf.ps1 automates the trace-and-analyze workflow for next time. Claude-Session: https://claude.ai/code/session_016DQUKGLZxFtPy52MkKXXog * docs(D250): correct the 1440p+ follow-up -- it was a stale-build false alarm User re-tested 1440p/4K on the actual getenv-fix build and confirmed it holds up fine too. The "still runs badly at 1440p+" report was from before the fix was live, same stale-build class as the DLL-load false alarm earlier in the session. D250 is fully resolved across all resolutions tested, not just 640x480. Claude-Session: https://claude.ai/code/session_016DQUKGLZxFtPy52MkKXXog * docs: add missing GE_D219RAW row to GE-ENV-PROBES.md (CI validate fix) Pre-existing gap unrelated to this branch's own changes -- gen_env_probes.py --check caught it now since it runs on every PR. GE_D219RAW has had live getenv() sites in src/game/image.c since the D219 investigation but was never added to the probe doc.
102 lines
22 KiB
Markdown
102 lines
22 KiB
Markdown
# GE_* environment probes — consolidated list
|
||
|
||
Every `getenv("GE_…")` in the tree. The table prose is hand-curated;
|
||
**`tools_pc/gen_env_probes.py`** re-greps the live sites and reports drift
|
||
(NEW / GONE vars + a fresh file:line map) — run it before trusting the
|
||
File:line cells. Last reconciled 2026-09-04 (M-51). All are **env-gated**: unset = zero behavior
|
||
change, so they are safe to leave in a release build (they only cost a
|
||
`getenv` on the guarded path). "Dead" below means *the finding it was built
|
||
for is closed* — the probe is strip-candidate scaffolding, not that it does
|
||
anything harmful.
|
||
|
||
Two classes:
|
||
- **Infra / live tooling** — deliberately kept, used by the playtest harness
|
||
(`tools_pc/debug.ps1`, `playtest.sh`, `level_sweep.sh`) or by an
|
||
investigation still in progress.
|
||
- **Dxx diagnostic** — added to chase one finding; most are now closed.
|
||
|
||
## Infra / live tooling
|
||
|
||
| Env var | File:line | What it does | Status |
|
||
|---|---|---|---|
|
||
| `GE_PCDUMP` | `port/fast3d/gfx_opengl.cpp:1079` (`is_pcdump`), `gfx_opengl.cpp:700`, `port/src/video.c:188`, `port/src/config.c:46` (`configGetFrameDump`) | Per-frame framebuffer PPM dump to `$PCDUMP` dir (verification-ritual golden captures, `tools_pc/framediff.py`/`pixcount.py`). Also settable via `[Debug] FrameDump` ini (env wins). **M-33/D168: the writer now emits rows top-to-bottom — captures before that fix are vertically flipped.** | **live** |
|
||
| `GE_INPUTSCRIPT` | `port/src/input.c:306` | Headless scripted controller-0 input: `"<frame>:<tok>,…;…"` (`SUP/SDOWN/SLEFT/SRIGHT/SNONE` sustain, buttons pulse). Sole input source when set. | **live** |
|
||
| `GE_INPUTLOG` | `port/src/input.c:329`, `port/src/config.c:53` (`configGetInputLog`) | Logs computed pad state (buttons + stick) each poll when non-zero. Also `[Debug] InputLog` ini. Also traces D165 `menuptr est/tgt/eff/stick`. | **live** |
|
||
| `GE_STARTMENU` (+ `GE_STARTMENU_PAGE`, `GE_STARTMENU_DIFF`) | `src/game/lv.c:398-402` (`#ifdef PORT`) | Boot straight into a front-end menu id (13=MISSION_COMPLETE, 10=BRIEFING, 7=MISSION_SELECT, 12=MISSION_FAILED, 6=MODE_SELECT); `_PAGE`=folder row (def 1=Dam), `_DIFF`=0..3. Crash-test a screen fast. | **live** |
|
||
| `GE_UNLOCK_ALL` | `src/game/debugmenu_handler.c:1098` (`get_debug_enable_all_levels_flag`, `#ifdef PORT`) | Mission-select shows every solo level (playtest jump-to-any-level aid). Cached in a `static int c`. | **live** |
|
||
| `GE_OPTIONSOVERLAY` | `port/src/optionsoverlay.c:231` | Force-enable the F10 port-layer options overlay (D184 / PR #10) regardless of ini. `atoi != 0`. | **live** |
|
||
| `GE_D204` | `port/src/audio.c` (`audioSetNextBuffer`) | **Audio-health monitor (D204).** One line per 5 s of wall clock: `rt=` produced-audio/wall ratio (1.000 healthy; below 1 = the 30 Hz audio retrace is starving and the device is padding with silence), `q=` SDL queue depth / `queueLimit` (pinning at the limit with `drop=` climbing = overproduction, the "eventually no audio" state), `drop=` blocks discarded, `max=` largest block vs its `g_MaxFrameSize*4` allocation. **Deliberately cheap (~30 clock reads/s) — safe to leave on for a full playtest, unlike `GE_MIXERTRACE`.** The instrument of record for D202. | **live** |
|
||
| `GE_D204_OLD` | `port/src/audio.c` (`d204OldMode`) | Restores pre-D204 behaviour (`osAiGetLength()` reports the whole SDL queue depth; `queueLimit` back to 8192) so before/after can be A/B'd in **one binary**, without build-to-build variance. Temporary — remove when D204 closes. | **live** (D204 A/B) |
|
||
| `GE_AUDIOTRACE` | `src/snd.c` (`sndPlaySfx`, `sndDeactivate`), `src/game/propobj.c` (door sounds), `src/libultra/audio/load.c` (`alLoadParam`) | Per-`sndPlaySfx` resolution trace to `audiotrace.log`: `soundIndex` → `ALSound*`/keyMap/wavetable/base/len/book, the returned `ALSoundState*`, every `sndDeactivate`, and wavetable bind events. M-65 additions: `[VOICE+]`/`[VOICE-]` pairing every voice acquire/release with sound/state/flags (NB: written from two threads to one unbuffered FILE* — occasional torn lines, parse defensively), `[SLOTWRITE]` door slot ownership, `[RETRIGGER-POST]`, `[WAVELOOP]` (per-sound `ALADPCMloop` presence), `[DOORSND]` every door sound state change incl. an `ORPHAN-both-slots-busy` verdict. M-66b addition: `[EXPIRE]` — posted whenever the port-side ownerless-infinite-loop expiration is scheduled (sound/state/delay/fade); this line is **permanent** (part of the D202 option-C fix), unlike the rest of the probe set which is removable on close. M-67/M-69 additions: `[WIRE] t=µs filter=… <- table=…` (`src/libultra/audio/load.c`, every wavetable→decoder bind, µs-timestamped) and `[VOICEMAP]` (`src/libultra/audio/synthesizer.c`, full PVoice→decoder/resampler/env-state address map at synth init — this is how offline voicedump slot addresses tie to WIRE filter addresses). M-68 additions: `[EVT] t=µs type=N state=P` + `[STOP-EVT] … deltaUs=N` (event types per `src/snd.h`: 1=PLAY, 2=STOP, 8=VOL, 64=DECAY, 128=END). M-71 additions: `[VOL] t=µs state=… rawVol=… playing=…` (`src/snd.c`, per-VOL-event value before the slot-volume law) and `[DISTVOL] pos=(…) player=(…) dist=… vol=…` (`src/game/propobj.c`, the distance-attenuation funnel `sub_GAME_7F053894` — this is how an SFX's final volume is computed from hit position). NB: lines from the multiple file handles interleave — occasional torn/corrupt lines, parse defensively. `dumppos=` gives the exact byte offset into `audiodump.raw` (quantised to the 2880-byte audio block). Low cost. | **live** (D202/D205) |
|
||
| `GE_PULLTRACE` | `src/libultra/audio/load.c` (`alAdpcmPull`) | `[PASTEND]` assertion: fires if a voice's `f->sample` exceeds its wave's total samples while `nOver == 0` (i.e. an unstopped voice keeps decoding past the end instead of zero-filling). Rate-limited to 40 lines. M-65: 0 hits — exhausted voices go silent correctly. | **live** (D202) |
|
||
| `GE_DMEMWIPE` | `port/src/mixer.c` (`aClearBufferImpl`) | Zeroes the whole software DMEM at the frame boundary (detected as `alMainBusPull`'s clear of `AL_MAIN_L_OUT`, addr 1088). Tests whether audio state survives across frames in DMEM. M-65: no-op on output — ruled out. | **live** (D202) |
|
||
| `GE_NOWET` | `port/src/mixer.c` (`aSetVolumeImpl`) | Mutes the reverb send (`wetamt = 0`), isolating the reverb delay lines as a possible source of persistent signal. M-65: drone unchanged — ruled out (NB `aPoleFilterImpl` is still an unimplemented no-op, D199). | **live** (D202) |
|
||
| `GE_BANKDUMP` | `port/src/romdata.c` | `BANKSRC` lines: the source ROM-layout bank tree per `soundIndex` (instrument → sound → envelope pointers + `decayTime`). Used to prove sound 203's `decay=-1` is genuine ROM data, not a conversion bug. One-shot at load. | **live** (D202) |
|
||
| `GE_FORCEALARM` | `src/game/propobj.c` (`handle_alarm_gas_timer_calldamage`, `#ifdef PORT`) | **D207 diag (temporary).** Forces the in-game alarm klaxon (`alarmActivate`) on a frame counter — on ~2–10 s, off, on again — and emits a per-frame `[D207] f=… active=… ptr_alarm_sfx=… playstate=… locked=…` line to `audiotrace.log`. Repro harness for the "alarm SFX overrides other audio" report when a level's own alarm can't be triggered headlessly. Remove when D207 closes. | **live** (D207) — temporary |
|
||
| `GE_KEYMAPDUMP` | `port/src/romdata.c` | `KEYMAP` + `ENVSRC` lines: raw source bytes of every `ALKeyMap` / `ALEnvelope` in the ROM-layout blob, for byte-wise comparison against runtime values. One-shot at load. | **live** (D202) |
|
||
| `GE_AUDIODUMP` | `port/src/audio.c` (`audioSetNextBuffer`) | Raw-dumps every mixed s16/stereo/22050 Hz buffer to `audiodump.raw` in the CWD for offline waveform inspection. Length ÷ 88200 = seconds of audio produced. | **live** (D202) |
|
||
| `GE_VOICEDUMP` | `port/src/mixer.c` (`aEnvMixerImpl`) | Dumps each voice's resampled mono stream (post-resample/pre-envelope, i.e. the env-mixer input) to `voicedump.raw` as records of `[u32 stateAddr][u32 nSamples][u64 us][s16 × n]`. **The µs stamp is when the block was MIXED — records are rendered ahead, so a record's samples END at its stamp** (M-69: treating stamps as start offsets misplaces content by up to one ~33 ms block). `stateAddr` = the env-mixer state address from `[VOICEMAP]`. Used with `scratchpad/exact_match.py` for full-corpus per-voice sample verification. | **live** (D202) |
|
||
| `GE_MIXERTRACE` | `port/src/mixer.c`, `src/audi.c` (`amDmaCallback`), `src/libultra/audio/load.c` (`_decodeChunk`, `alLoadParam`) | Per-opcode mixer trace to `mixertrace.log` (DMEM addresses, ADPCM books, decoded frames, `[DMAREQ]`/`[DMAHIT]`/`[DMAMISS]`/`[BINDTABLE]`). **WARNING: unbuffered per-opcode `fprintf`, ~25 MB/min. It slows the process enough to starve the audio thread — M-63 measured "audio at 13 % of real time" that was entirely this probe's own artifact. NEVER use it for timing-sensitive measurement; use `GE_D204`.** Grep it, never read it whole. | **live** (D202) — timing-unsafe |
|
||
| `GE_TEXPITCH` | `port/fast3d/gfx_pc.cpp:924` (`gfx_tex_pitch_fix`, cached) | `=0` disables the D183 defensive de-stride in `import_texture` (default on). RC2/RC3 texture-shear A/B knob. | **live** (RC3 not finished) |
|
||
| `GE_TEXRAW` | `port/fast3d/gfx_pc.cpp:1079` | With `GE_TEXDUMP`, also dumps the raw pre-import source bytes (`texdump/rNNN_f…_s…_WxH.bin`) so a decode bug can be told from a source-data bug offline (D183). | **live** (RC3 not finished) |
|
||
| `GE_D219RAW` | `src/game/image.c` (`texReadUncompressed`/`texChannelsToPixels`, `#ifdef PORT`) | Diagnostic-only, print-only (no behavior change): logs the runtime texture decompressor's bitstream header (texnum/format/width/height/compmethod) for every non-zlib wide-pixel image, plus a dump of the first row of decoded texels exactly as stored in the pool (post-`PORT_PIXEL16`, i.e. byte-swapped for the 16-bit family) for RGBA16/RGB15/IA16. No texnum filter — lets any suspect texture be cross-referenced against the offline ROM census (`scratch/d219_census.txt`) without narrowing by hand. | **live** (D219, closed — kept for future runtime-decoder triage) |
|
||
| `GE_WRAPFIX` | `port/fast3d/gfx_pc.cpp:3166` (`gfx_set_wrap_fix`) | RC3 test override for the `Video.WrapFix` D74/D167 wrap-block path (`atoi != 0` wins over the ini). | **live** (RC3 not finished) |
|
||
| `GE_SAVELOG` | `src/game/file.c:46`, `src/game/file2.c:16` (`SAVELOG` macro), `src/boss.c:749`, `src/game/objective_status.c:297,343` | Traces the campaign save/unlock chain (objective completion → `end_of_mission_briefing` → `fileWriteSave` → EEPROM). Used to confirm D157. `g_savelogObjOnce` gates the per-criterion dump to the `bossReturnTitleStage` call. | **live** (strip once a few more level boundaries are playtested) |
|
||
| `GE_D160` | `src/boss.c:744`, `src/game/bondview2.c:791`, `src/aicommands.def:10055,10181,10236,10242,10247` (all `#ifdef PORT`) | Dam exit-cutscene (D148/D160) diagnostic: trace points in `bossReturnTitleStage`, `bondviewSetCameraMode`, and AI cmds `EndLevel`/`exit_level`/`CameraLookAtBondFromPad`/`CameraSwitch`. **Investigation in progress** — user owes a `GE_D160=1` Dam run. | **live** |
|
||
| `GE_D193` | `src/game/frametiming.c` (`waitForNextFrame`, `#ifdef PORT`) | Per-wall-second line: `render=` rendered frames, `sim=` sim ticks delivered (Σ of the `deltaFrames`/`g_ClockTimer` fed downstream), `clamped=` frames whose catch-up hit `FRAMETIMING_PORT_MAX_CATCHUP`, `maxraw=` largest pre-clamp delta. Healthy steady state = `render=30 sim=60 clamped=0 maxraw=2` (measured M-80, all levels idle). Use to check whether the wall-clock timer under-advances under real AI load (D193). Cheap; safe for a full playtest. | **live** (D193) |
|
||
| `GE_D193A` | `src/game/chr.c` (`chrTick` → `d193aSample`, plus `d193aMoved` in `chrUpdateAnim`; `#ifdef PORT`) | Per-wall-second per-ticked-chr locomotion telemetry (D193/D209): `chr=` chrnum, `act=` ACT_TYPE, `speed=` world-units travelled/s, `gtd=` g_GlobalTimerDelta, `tier=` `act_gopos.unk59` SPEED tier (0 walk / 1 run / 2 sprint; `-1` when not ACT_GOPOS), `gspd=` `act_gopos.speed` (**a turn rate, not a travel rate** — 0 means running straight), `typ=` PROP_TYPE (3=CHR, 6=VIEWER), `tick=`/`move=`/`frz=` chrTick entries vs `chrUpdateAnim` calls vs freeze-gated (move « tick = the chr is being visibility-culled out of its own locomotion; `move=0` at high `speed` = WAYMODE_MAGIC), `hid=` CHRFLAG_HIDDEN, then the root-motion scalars `scale` / `xlscale` / `animrate` / `playspeed` / `mspeed` (model->speed) / `endframe` / `anim` ptr / `aidx=` that pointer reverse-resolved to its `animation_table_ptrs1` index (40 walking, 41 sprinting, 42 running, 107 walking_unarmed — map via `src/game/initanitable.c`). `GE_D193A_CHR=<n>` restricts to one chrnum. **This probe found D209**: Cradle showed `tier=1` (RUN) with `aidx=40/107` (walk anims) on every sample. | **live** (D193/D209) |
|
||
| `GE_D193B` | `src/game/model.c` (`sub_GAME_7F06D3F4`, `#ifdef PORT`) | Rate-limited (1/97) raw anim root-motion decode trace (D193): `joint=` / `flip=` / `base=` mtx channel index / `frame=` / `tmp=` decoded s16 translation triple from the anim bitstream / `angle=` / `anim` ptr / `bd=`+`bs=` the D32 u32 bitDescriptors/bitStream addresses / `njoints`. M-80 Facility: `base=0`, `angle=0` **always** (root-motion facing delta never non-zero — top lead), `tmp` ≈ (±small, ~1086 hip-height, ±small). Compare `tmp`/`angle` magnitudes against a clean N64 decomp build of the same anim+frame. | **live** (D193) |
|
||
| `GE_D250` | `src/boss.c` (`bossMainloop`, wraps `lvlRender()`, `#ifdef PORT`) | Per-wall-second line: `[D250] lvlRender avg=Nus n=M` — average + count of `lvlRender()` (DL-building: culling/animation/scene traversal) calls that wall-second, isolated from `gfx_run()`'s software-RSP interpretation cost (already covered by the existing "frame rendered in Nus" line). Added M-120 to chase D250 (fps stuck ~45-50 on Dam, ruled resolution/MSAA/vsync/build-flags out already) — found `lvlRender` itself is cheap (~0.5-1.5ms avg), so it is NOT the missing ~10-15ms/frame either; the still-unexplained cost must be elsewhere in the per-retrace-message loop (scheduler/thread round-trip, audio, or something not yet isolated by a targeted timer). Cheap; safe for a full playtest. | **live** (D250) |
|
||
| `GE_D172` | `port/fast3d/gfx_pc.cpp` (`gfx_sp_tri1` — SETCOMBINE dedup log + non-LOD multitex tri dump; `#ifdef PORT`) | Particle magenta/cyan colour (D172). Logs each distinct SETCOMBINE + active cycletype, and — for a 2-cycle tri that consumes TEXEL1 with `tex_lod=0` and a distinct 2nd tile — the tile fast3d *samples* for each texunit vs what the DL *configured*. **Found D172**: 40/40 particle tris configured tile 1 @ tmem 392 (fire) but sampled tile 0 (smoke) → `smoke*smoke`. FIXED (`gfx_lod_tile_offset` `return rdp.tex_lod ? 0 : i`). Probe kept inert. | **live** (D172 FIXED, probe kept) |
|
||
| `GE_DVM` | `src/game/gunfire.c` (`gunUpdateAndFire` gate dump + `gunRenderFirstPersonGunModels` render dump; `#ifdef PORT`) | 1P weapon viewmodel (D215). `[DVM]` line: the `field_87F` show/hide gate terms + `Gun_hand_without_item` sub-terms + `copy_of_body_obj_header` RootNode/Switches/numRecords. `[DVMr]` line: `87F` + `cmds_emitted` = gfx commands the weapon `subdraw()` produced (healthy ≈ 150; the D215 bug showed **1**). Rate-limited ~1/s per hand. **Found + verified D215** (`renderdata.flags` read 0 → all weapon DL nodes gated off). Probe kept inert. | **live** (D215 FIXED, probe kept) |
|
||
| `GE_DTEX` | `port/fast3d/gfx_pc.cpp:1001` | Per-`import_texture` param log (dims / line / size / lod / gen_mipmaps). Used to root-cause RC2 and D159. Kept as an inert diagnostic. | **live** (RC2/RC3 not finished) |
|
||
| `GE_TEXDUMP` | `port/fast3d/gfx_pc.cpp:1020`, `port/fast3d/gfx_opengl.cpp:700` | PPM dump of every uploaded texture + a `fmt/siz/palfmt/palidx/pal[0..3]` line. Root-caused D161 (Depot ceiling). Kept as an inert diagnostic. | **live** (RC3 not finished) |
|
||
| `GE_D116` | `port/fast3d/gfx_pc.cpp:1710,2362`, `src/game/textrelated.c:265,541` (cached `ge_d116`) | HUD/text "X-mirror" (D114/D116) vbo/uv trace. **D114/D116 CLOSED — NOT A BUG (M-33/D168): the captures were upside-down, not mirrored.** Probe is now dead scaffolding — strip on the next cleanup pass. | dead (D114/D116 closed) |
|
||
|
||
## Dxx diagnostic probes — finding closed unless noted
|
||
|
||
| 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` | — (all blocks stripped M-32, commit `49ce620a`) | music seq-table ABI / endianness (`ALMidiHdr`) | dead (D54 closed) — fully removed (kept here as a tombstone; the generator flags it GONE) |
|
||
| `GE_D154` | `src/game/bg.c:3418,3447,3632` (capped 64 calls) | bg room-GDL call trace (room / gdlidx / vtxoff / op / raw hdr words) | dead (D154 closed) |
|
||
| `GE_D227V` | `src/game/sky.c` (`skyPortRenderPoly`, `#ifdef PORT`) | Sky/water per-vertex dump: `S`/`T`/`w`/`1/w`, screen xy, the chosen tc shift `k`, the baked `tc`, and whether the tile capture succeeded. **Found D227**: one sky quad spans ~30,000 texels in S and T but `Vtx.tc` is S10.5 in an `s16` (+/-1024 texels), so 7 of its 8 texture coordinates overflowed and wrapped -- the starburst/"two sky processes" seam. Root cause was a unit error (`unk20`/`unk24` are already S10.5, not texels; M-82's `*32` was spurious). FIXED M-100b. Probe kept inert. | **live** (D227 FIXED, probe kept; useful for D229 water) |
|
||
| `GE_D176` | `src/game/bgfog.c:459,471`, `src/game/sky.c:325,381` (all `#ifdef PORT`) | D176 sky/fog env-match + sky-vert trace (Path B, PR #18) | **live** (D176(a)/(b) OPEN) |
|
||
| `GE_D178` | `src/game/front.c:6586,6594` (`#ifdef PORT`) | briefing-data u16 decode trace (blank-objectives, D143/D178) | dead (D178 closed) |
|
||
| `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` | 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 |
|
||
| `GE_D85DUMP` | `src/game/bg.c:2510` | D85 `bgWidenRoomGdl` 8→16B dump | dead (D85 closed) |
|
||
| `GE_D85TEX` | `src/game/image.c:2479`, `src/game/tex.c:859,1050` | D85 texpool-full events (Depot analysis) | dead (D85 closed) — was useful for §3 |
|
||
| `GE_D217TEX` | `src/game/image.c:234` (`texInflateZlib`) | D217: logs `texnum`/`format`/`numcolours`/`palette[0..1]` straight off the decode bitstream (before any arena/pointer math) — the decode-correctness check that proved the affected texture (grip, `texnum=1608`) decodes byte-identically across levels, ruling out a decode/ROM-data bug. | **live** (D217 open — investigation instrument) |
|
||
| `GE_D229` | `port/fast3d/gfx_pc.cpp` (`gfx_sp_tri` dual-texunit probe + `import_texture`) | D229: per-draw dump of both texunits' tile/tmem/fmt/siz/UV state for 2-cycle draws, plus a one-shot confirm line when the RGBA16-over-CI8 import remap fires (the fix path). Inert by default. | **live** (D229 fixed — probe kept for the Surface 2 / sweep verification) |
|
||
| `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` | 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
|
||
|
||
- 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`.
|
||
- Not GE_-prefixed but same category: `GE_DETERM` is **implemented but
|
||
experimental — not yet achieving its determinism goal** (fixed-tick
|
||
mode, §F D117, M-52 four-pass writeup); `GE_DETERM_TRACE` (M-52 4th
|
||
pass) adds instrumented clock-event logging when used alongside it, for
|
||
diffing two runs to localize remaining divergence. Both env-gated,
|
||
default off, zero cost when unset.
|