mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-24 00:02:45 +02:00
* fix(D176a): sky scroll/tiling too fast -- perspective-correct tc interpolation skyPortRenderPoly (Path B, D176(a) black-sky fix) placed sky quad verts under a plain w=1 ortho projection, so fast3d's GPU pipeline interpolated texture coords linearly in screen space across the primitive. The source S/T data (unk20/unk24) is computed upstream from a world-space projection without a perspective divide -- exactly like the real N64 RDP's G_TRI_SHADE_TXTR coefficient block, which relies on real perspective- correct interpolation to divide it back out per pixel. A single sky quad's near (top) and horizon-grazing (bottom) vertices can differ up to ~38x in camera-space w. Under linear interpolation that smears the entire S/T delta evenly across every pixel instead of concentrating it near the horizon, producing a uniformly dense aliased 'hatching' over the whole sky -- reported as 'scrolls too fast / tiles too visibly'. Fix: build a custom projection matrix that gives each vertex its real camera-space w (already computed upstream, SkyRelated38.unk0c) while keeping the same screen-space x,y, so the GPU's normal perspective divide recovers the intended position but interpolates tc (and colour) with real 1/w weighting -- the same pipeline every other textured draw in the game already depends on. No port/fast3d changes; #ifdef PORT only, N64 path untouched. Verified: tools_pc/verify.sh bunker1 PASS (no regression on a non-sky level); -level_22 (Statue) and -level_41 (Cradle) GE_PCDUMP captures show the expected before/after change (uniform parallel aliasing -> a proper perspective-converging fan), and Cradle's sky is no longer black at default FOV. Defect 2 (horizon-band tessellation) and the FOV-coupled black-sky-past-frustum symptom are unchanged / still open. docs/dev/findings.md: new D176(a) subsection + summary-row update. docs/porting-notes.md: generalized the screen-space-overlay quirk to call out the w=1-vs-real-w interpolation pitfall. * chore(D176a): regen findings index * docs(D176a/D227): M-93 - human playtest of PR #43 confirms Cradle black-sky fix + partial Statue scroll improvement; new split-sky residual filed as D227 * docs(D227): M-94 - visual evidence + a concrete mechanistic hypothesis for the sky seam (per-primitive wScale quantization), not yet fixed Headless -level_22 capture (this shell can do offscreen GE_PCDUMP capture via the game binary directly, run from the repo root with the MSYS2 mingw64 PATH set -- the earlier GUI-launch flakiness in this session was specific to a live window, not this path) shows a real, static-frame crease in the sky's cloud texture. Screenshot committed: docs/img/bugs/d227-sky-seam-statue.png. Hypothesis: skyPortRenderPoly (D176(a)'s fix) computes wScale per call, and skyRenderTri/skyRenderFull issue up to 5 separate calls per frame (one per triangle in the sky fan). The position math is exact for any wScale (re-verified algebraically), but Vtx.ob[] is s16, so two triangles sharing an edge can quantize a logically-shared vertex to two slightly different values depending on which triangle's independently- chosen wScale computed it -- crack at the shared edge, reads as "two regions with a different pattern." Not yet confirmed (didn't isolate camera motion from sky-scroll motion to test the "moves at a different rate" half of the report) and not fixed -- documented the fix direction (one wScale shared across the whole fan, not recomputed per triangle) for whoever picks this up next. Cleaned up capture scratch files after pulling the one evidence shot. * docs(D227): M-94 addendum - static-camera test confirms the sky genuinely animates over time, independent of camera motion * fix(D227): M-95 - one shared wScale across the whole sky fan instead of one per triangle, closes the visible seam skyRenderTri/skyRenderFull draw up to 5 triangles per frame from a shared pool of up to 5 vertices (built once, then fan-triangulated across 1-3 calls). D176(a)'s fix had each call compute its own wScale from only its own 2-4 verts; two triangles sharing a vertex could each pick a different wScale, and since Vtx.ob[] is s16, quantize that logically-shared vertex to two different values depending on which triangle's call computed it -- a crack at the shared edge (D227, the "two sky halves" report). Fix: skyPortBeginFan()/skyPortEndFan() (new, #ifdef PORT) compute one wScale across the whole fan and skyPortRenderPoly uses it when set, falling back to the old per-call computation otherwise. N64 path unchanged (these are PORT-only additions around existing #ifdef PORT code, no #else branch touched). Verified: - Clean build, no new/duplicate symbols. - Full verify.sh sweep: 21/21 PASS, both with and without this change. - Same-frame before/after screenshots at -level_22 frame 345 (docs/img/bugs/d227-sky-seam-statue{,-fixed}.png): visible kink in the cloud streaks in the before shot, gone in the after shot, same exact frame. - bunker1's nonzero framediff worst_cell is unaffected by this change (reproduced identically pre-fix) -- confirmed pre-existing stale golden-baseline issue, unrelated to sky.c. - Cradle's black-rectangle artifact is also confirmed pre-existing (reproduced identically pre-fix) -- the separate, already-documented FOV-coupled black-sky-past-frustum-edge symptom (D218/D222 family), not touched by this fix. Not re-verified: whether the "moves at a different rate" half of the original report is also resolved, and the aspect-ratio-artifact alternate theory was never independently ruled out. Human eyeball still owed before merge, same as every other rendering fix landed this session without interactive display access. Also generalized the quirk (per-call vs per-shared-vertex-group scale quantization) to docs/porting-notes.md alongside the existing D176(a) entry. * docs(D227): M-96 - human playtest on Statue: seam/crack STILL PRESENT despite M-95 fix The M-95 wScale-sharing fix only verified the static per-primitive quantization theory (single-frame screenshot diff); it explicitly left the 'two halves move at different rates' temporal theory from the original report unverified. This playtest is that missing verification, and it says the seam is still visible in live play. D227 NOT resolved. PR #43 stays in draft pending investigation of the temporal/rate theory -- do not merge on the M-95 fix alone. * docs(D227): M-96 addendum - N64 sky should be near-static, this build scrolls extremely fast New data point from the same Statue playtest session, separate from the seam/crack: the user reports the intended N64 scroll rate is near-static, stronger than M-93's 'still reads too fast'. Bears on D176(a)'s fix magnitude itself, not just the D227 seam -- flagged as a possible shared root cause (wrong per-frame tc delta could drive both symptoms), not yet investigated. * fix(D227): M-98 - share sky S/T fold across whole fan, not per-triangle skyPortBeginFan() (M-95) shared wScale across a whole sky fan so shared vertices quantize position consistently, but skyPortRenderPoly's S/T fold (foldS/foldT -- floorf(minS/64)*64, keeps texel coords in s16 range) was still computed per-call, from only that triangle's own 2-4 verts. Same bug class as the wScale fix, one field over, never fixed -- which is why M-96's human playtest still saw the seam after M-95. Two triangles in one fan can floor a shared vertex's S/T to different multiples of 64 texels; nominally invisible (GL_REPEAT period 64), but each triangle bakes (S-fold)*32 into its own s16 Vtx buffer, so two folds 64 texels apart produce tc values 2048 apart -- a real crack at the shared edge. Fix: extend skyPortBeginFan()/skyPortEndFan() to also compute one shared fold across the whole fan, threaded into skyPortRenderPoly the same way as wScale. #ifdef PORT only, no game-logic change. Also measured (per M-96/M-97's ask): cross-correlated 11 consecutive frames at a static camera -> ~7 px/tick horizontal scroll at 640px capture width, a full screen-width sweep every ~1.5s. Confirms "extremely fast" quantitatively; root cause of that magnitude is not yet found (accumulator + vertex geometry are unmodified N64 logic, so if it's genuinely wrong the bug is in how the Path B substitution maps texel-ticks to screen pixels, not the tick rate itself -- next step spec'd in findings.md). Verified: build clean; -level_22 frame 345 (same frame M-95's before/after used) shows no visible crease vs. the pre-M-95 reference screenshot; verify.sh bunker1 PASS, worst_cell unchanged (known stale golden baseline, not a regression). Human eyeball still owed on both the seam-close and the scroll-speed question before PR #43 leaves draft. * docs(D176a): M-98 - Cradle side of PR #43 checked; tower starburst is Defect 2 Checked the Cradle side of the D227 fold-sharing fix (M-97 left this outstanding). No regression -- verify.sh cradle PASS -- but found a much more visible pre-existing artifact while there: looking up the suspension tower near spawn, roughly half the sky renders as a sharp radiating starburst instead of clouds. Confirmed pre-existing (pixel-identical with sky.c reverted to pre-M-98) and confirmed static, not the D227 "moves at different rates" symptom (pixel-identical 30 ticks apart at a fixed camera). This is the already-known, already-open D176(a) Defect 2 (horizon-band tessellation) -- the code's own fold-logic comment already predicts exactly this failure shape for a triangle spanning >1000 texels near the horizon, which looking straight up the tower produces. Not fixed (tessellation is separate, bigger work); logged with a concrete repro + screenshot so it's no longer "inconclusive." * docs(D227): M-99 - human playtest negative (seam persists, view-angle-dependent); headless repro blocked Human playtest after M-98's fold-sharing fix: the seam is still present on Statue and now confirmed to move/change with mouse/view position -- also reported still bad on Cradle and present on Surface. M-98's fix was real but is not the dominant mechanism live play is hitting, same pattern as M-95 before it. Ruled out this pass: the cross-quad water/cloud texture-scale mismatch theory, on the two IsWater==0 levels actually tested (Statue, Cradle) -- untested on any IsWater==1 level, which is now the top ranked candidate for next session. Blocked on: headless camera-pan repro via GE_INPUTSCRIPT does not work -- confirmed neither analog-stick nor C-button tokens rotate the camera, so this needs either a human playtest or a debug hook into the real mouselook path before it can be chased further headlessly. Full ranked candidate list + environment notes for next session in findings.md and (session-local) docs/HANDOFF.md. * docs(D227): M-100 - root cause PROVEN: s16 texture-coordinate overflow The sky seam is not a crack, not a quantization mismatch, and not view-dependence. 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 overflow and wrap to arbitrary values. The fold cannot help against a span 29x the representable range. Unblocked by a user-supplied emulator-vs-ours screenshot pair on Surface: the real symptom is a radial starburst, not a crack, which is a different mechanism from what M-94..M-98 were chasing. M-95 (shared wScale) and M-98 (shared S/T fold) each fixed a real second-order bug; neither could touch this one. Both stay - per-fan consistency is exactly what will make subdivision seamless. Measured with a new env-gated GE_D227V probe (GE_D176 style) on the Cradle frame-350 camera. All four w are positive, so no projective pole. The quad is split gSP2Triangles(0,1,3, 0,3,2) on the 0-3 diagonal, and vertices 0 and 3 are exactly the two that keep one coordinate in range - hence "two halves with different patterns, split by a line", the original D227 report verbatim. Apparent view-dependence needs no view-dependent mechanism: S/T depend on view, so the wrap point moves. Confirmed by a diagnostic build: baking tc at 1-texel instead of 1/32-texel granularity (32x range, deliberately wrong scale) makes the starburst and the split completely disappear. No second defect behind it. D227 == D176(a) "Defect 2" == M-98's "Cradle tower starburst". M-98 misfiled that capture as unrelated, which is what made D227 look headlessly-unreproducible in M-99 - it reproduces statically. Fix not implemented: subdivide until span < ~960 texels/primitive. The subdivision math and cut placement are worked out in the finding (S is linear in w, so cut uniformly in w), but the vertex budget is an open decision - dynAllocateVertices is an unchecked 50 KB/frame pool and pure tessellation wants ~40% of it. * docs(D227): M-100 addendum - RDP tile shift (option D) dominates; fast3d already implements it shifts/shiftt is the RDP's native precision-vs-range knob and gfx_pc.cpp implements it fully including the left-shift case. Emitting tc at 32/2^k units with shifts = 16-k buys 2^k range with no tessellation, no fast3d change and no vertex-budget cost. k=5 covers the measured 29,830-texel span outright. * fix(D227): M-100b - sky texcoords are S10.5, not texels; drop M-82's stray *32 Fixes the sky seam/starburst, the over-tiling, and the "scrolls too fast" complaint - all three were the same bug. M-82 ("D176(a) Defect 1") read unk20/unk24 as texel counts and baked tc as (S - fold) * 32 to convert texels into tc's S10.5 units. They are not texel counts. skyRender sets them as worldpos * 0.1f and the N64 path hands them to the RDP coefficient block unscaled (skyRenderTri: S * unk34 * sp368), so they are already in the RDP's native S10.5 1/32-texel units. That stray *32 made every sky texture coordinate 32x too large, producing three symptoms previously tracked as separate bugs: 1. D227 - spans of ~30,000 texels against an s16 tc holding +/-1024, so 7 of a quad's 8 coordinates overflowed and wrapped to arbitrary values. The quad splits on the 0-3 diagonal and verts 0 and 3 are exactly the two that keep one coordinate in range, hence "two halves with different patterns" - the original D227 report verbatim. 2. Over-tiling - ~466 repeats of the 64-texel cloud per quad, not ~15. 3. M-96's "the N64 sky is nearly static, ours races", measured at ~7 px/tick in M-98. g_SkyCloudOffset advances 1 unit/tick = 1/32 texel, not 1 texel. This is why M-98's re-derivation of the tick path kept coming back clean: the accumulator was never wrong, its unit was. Fix: tc = (S - fold) 1:1, with the fold rebased to a whole tile period (SKY_TC_WRAP = 64 texels * 32 = 2048 units). The ~30,000-unit span then fits an s16 unaided - which is also why the original N64 code needs no tessellation here: it never had a range problem to solve. Kept: M-95's shared wScale and M-98's shared fold (both real bugs; per-fan consistency keeps a fan's shared vertices bit-identical). Also kept as a safety valve, since only ~4% of s16 headroom remains on the observed span: skyPortPickShift/skyPortCaptureTile/skyPortEmitTileShift, which trade tc precision for range via the RDP's own tile shifts/shiftt (port/fast3d already implements it, so no fast3d change). skyPortCaptureTile replays the exact G_SETTILE texSelect emitted with only the shift fields patched, so it cannot drift from texSelect's format/line/mask derivation. Also adds the env-gated GE_D227V per-vertex probe (GE_D176 style) that measured all of this. Verified: -level_41 Cradle frame 350 (the M-98 starburst repro) now shows soft cloud bands at the correct scale with no starburst, diagonal split or moire; GE_D227V confirms kS=kT=0 and max tc 31,513 of 32,767. -level_22 Statue frame 345 clean. verify.sh bunker1 PASS (worst_cell 10.32, the known stale-golden-baseline number). Human play-test still owed. * D229: file green/pulsating water; decouple D227's tc safety valve from it New finding D229: on IsWater levels (Frigate, Surface 2) the water renders green and pulses blue<->green on an interval. Pre-existing, proven by A/B: built plain main with none of the D227 work and captured -level_26 frame 340 - same green, only the tiling density differs. D229 is independent of D227. The gun half of the same report was NOT a bug: the branch was 2 commits behind main and those 2 commits were exactly the D217 fixes (#47 texpool alignment, #49 CI cache palette-content key). After merging main the user confirms the gun is good on Frigate. Mechanism so far: the water quad is sky.c's IsWater block1 (Frigate confirmed IsWater=1 via GE_D176, which also settles M-99's ranked item 1). sub_GAME_7F09343C binds tile 0 and tile 1 to the SAME tmem, offsets tile 1 via gDPSetTileSize(1, 90, 150, 0, 0), and cross-fades TEXEL0/TEXEL1 with a PRIM_LOD_FRAC driven by sinf(). That sine is the reported pulsing, so one texunit resolves blue and the other green. Ruled out the shade path by measurement (it spans dark blue to pale yellow, never green; sampled pixels have R and B crushed). Not yet root-caused. Code change here is only the decoupling: skyPortBeginFan takes allowShift and the water quad passes FALSE, leaving that path byte-identical to its pre-D227 behaviour. The water quad is a two-texunit draw sharing one set of vertex tc, so a tc rescale needs a matching shift on both tiles - and shifting both makes them sample identically, which flattens the cross-fade. An intermediate build that did so turned the water from pulsating into constantly green, observed live. Also fixes skyPortCaptureTile to capture after all tile setup (not just after texSelect) and to handle both tiles, so a future shift cannot clobber a later re-declaration. Cradle sky re-verified unaffected (frame 350 still correct). bunker1 golden framediff reports REGRESSION at 55.02, but plain main scores WORSE at 73.24 - the baseline is stale relative to main's D217 texture fixes, the re-baseline owed since M-83/M-84. Not caused by this branch. * docs(D227/D229): regenerate findings index; mark D227 FIXED The generated findings-index.csv was hand-edited during the main merge and when D229 was filed, so CI's 'Check generated dev indexes are current' failed on PR #43. Regenerated with tools_pc/gen_findings_index.py. Also updates the D227 row's status to lead with FIXED (M-100b) rather than the M-94 'not yet fixed' text, so the index reflects the user-confirmed fix. * docs: register GE_D227V in the env-probe index CI's 'Check generated dev indexes are current' also runs gen_env_probes.py --check, which flags any GE_* probe with live sites that has no row in docs/dev/GE-ENV-PROBES.md. GE_D227V (added in M-100 to measure the sky texcoord overflow) had none.
20 KiB
20 KiB
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_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_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_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 PORTGE_D63block inbgRenderRoomPrimary(d63bgprimarycountstatic + entry log, was ~bg.c:2876/2880) was removed M-32 (49ce620a). Every remainingGE_D63block is#ifdef PORT/#if defined(PORT)wrapped and inert. [Debug]ini keys (Debug.FrameDump,Debug.InputLog) mirrorGE_PCDUMP/GE_INPUTLOGas a fallback (env var wins) — M-26,port/src/config.c.- Not GE_-prefixed but same category:
GE_DETERMis 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.