mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
D75 (M-195): GE_D75V per-batch vertex probe + findings/probes doc updates
- gfx_sp_vertex probe (env GE_D75V=lo-hi): logs per G_VTX batch the transformed x/y/z/w min/max, raw first-vertex ob, dest_index, and the MP translation row. Proves the logo transform is correct and that every batch encodes v0=0 (slot-overwrite hypothesis). - videoGetFrameCount() accessor for frame-gated probes. - findings.md: M-195 entry in the D75 section (emission + transform eliminated; G_VTX v0=0 overwrite is the leading suspect). - GE-ENV-PROBES.md: register GE_D75V, bump reconciled line.
This commit is contained in:
1 parent
bb508e5ce4
commit
aebcf178e6
5 files changed
+50
-1
No files matched your search
@@ -3,7 +3,7 @@
|
||||
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-21 (GE_D235 added, D235 fix wired; GE_D288 refined per M-155 follow-up). All are **env-gated**: unset = zero behavior
|
||||
File:line cells. Last reconciled 2026-09-21 (GE_D235 added, D235 fix wired; GE_D288 refined per M-155 follow-up; GE_D75V added for the Nintendo-logo vertex-slot investigation, M-195). 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
|
||||
@@ -72,6 +72,7 @@ Two classes:
|
||||
| `GE_D245_FIXEDSHIFT` | `src/game/sky.c:946` (`#ifdef PORT`) | D245 test override: pins the water tc shift `k` to the given integer (0..SKY_TC_MAX_SHIFT) instead of the computed per-vertex value, to A/B the allowShift=TRUE behavior. Off by default (unset = current behavior). | **live, test-only** (D245 OPEN) |
|
||||
| `GE_D252` | `port/fast3d/gfx_pc.cpp:733` (`import_texture`, cached `s_d252`) | D252 rainbow-particle diag: one-shot per (address,size) import log of the tile state (tmem/fmt/siz/addr/size/line) for small textures so a suspect particle tile can be checked against its source bytes by hand. Remove once D252 is resolved. | **live** (D252 OPEN — non-reproducible) |
|
||||
| `GE_D235` | `src/boss.c` (per-stage `while (!done)` block, after `memaReset`; `#ifdef PORT`) | D235 evidence probe: logs how many GL-texture-cache entries the per-stage `videoResetTextureCache()` call purges at each level load. A cold boot into a level should log 0; a death/restart (or any transition from a level that uploaded textures) logs >0 — direct evidence of the stale-entry mechanism. The clear itself is **not** gated on this var (it's the fix, see below); the var only controls the log line. | **live** (D235) |
|
||||
| `GE_D75V` | `port/fast3d/gfx_pc.cpp` (`gfx_sp_vertex`, end of the copy/transform loop; cached env check) | D75 (Nintendo logo) per-batch vertex probe: for each `G_VTX` batch in frames `lo..hi`, logs frame#, source pointer, n_vertices, original dest_index, raw ob[0..2] of the first vertex, min/max of the transformed x/y/z/w across the batch, and the MP translation row. Used to prove the transform is correct (M-195) and that every batch encodes v0=0 (slot-overwrite hypothesis). Value form `"lo-hi"` (e.g. `300-900` = the logo screen); unset = off. | **live** (D75) |
|
||||
|
||||
## Dxx diagnostic probes — finding closed unless noted
|
||||
|
||||
|
||||
@@ -2426,6 +2426,8 @@ Confidence overall: **medium** (triage solid, no runtime confirmation).
|
||||
> renders as degenerate white blobs" plus the unverified cast roll; the
|
||||
> gun-barrel half is retired. The M-32b probe text below is left for history.
|
||||
|
||||
> **M-195 UPDATE (v0.4.0 Phase 1, 2026-09-21) — Nintendo logo: vertex transform proven CORRECT; leading hypothesis now = G_VTX slot overwrite.** Three-pass investigation this session: **(1) Emission is fine.** Fresh `GE_D63=1` bare-front-end run (log `/c/tmp/d75_d63.log`, 32k lines): all 23 nintendologo Primary GDLs are emitted **every frame** of the logo screen (~1002 hits each, BaseAddr=0x70157a98), and the log contains **zero** `D146: unknown GBI opcode` lines — the software RSP consumes every DL to completion. PC-side GDLs verified byte-faithful to the N64 source via the d43 toolchain (same custom GE opcode sequences, same vertex counts). **(2) Transform is fine.** New `GE_D75V="lo-hi"` probe in `gfx_sp_vertex` (per-batch transformed-vertex min/max + MP translation row; uses new `videoGetFrameCount()` accessor) shows the logo's vertices land exactly where the wordmark geometry says they should: x∈[−2500,+2500], y∈[±644], w≈3.9k–5k, MP translation (0,0,3878.7) matching `lookat(0,0,4000)` — this eliminates basematrix, the f32→s32 conversion loop, and the matrix-list suspects. **(3) Leading hypothesis: vertex-slot overwrite.** Every `G_VTX` batch in these GDLs encodes **v0=0** (fast3d decodes `n=C0(0,16)/sizeof(Vtx)`, `dest_index=C0(16,4)`; probe confirms di=0 for every batch), so a node whose vertices span multiple 16-vertex batches writes all of them to slots 0..n−1 of the shared buffer — each later batch **overwrites** the earlier ones and only the last batch survives. Triangles referencing indices beyond the last batch's count read stale slots from prior nodes (likely clipped, not visible as junk — consistent with the observed single ~25×6px orbiting fragment matching the smallest node's 4-vert quad at x≈1020 → ~155px orbit radius vs observed ~200px). The N64 RSP must handle multi-batch nodes differently (per-batch ring or relative indexing) — GE's own ucode is not in this repo, so the next step is empirical: dump one full node's GDL stream from the ROM and cross-reference its `G_TRI4`/`G_TRI1` index ranges against per-batch vertex counts. If confirmed, the fix is port-layer only (fast3d vertex-slot management) — no rule-2 sign-off needed. Probe registered in `GE-ENV-PROBES.md` as `GE_D75V`.
|
||||
|
||||
**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
|
||||
|
||||
@@ -1442,7 +1442,10 @@ static inline bool fast3d_ptr_ok(const void *p) {
|
||||
return v >= 0x10000 && v < 0x0000800000000000ULL;
|
||||
}
|
||||
|
||||
extern "C" u32 videoGetFrameCount(void); /* port/src/video.c (D75 probe) */
|
||||
|
||||
static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx* vertices) {
|
||||
const size_t d75_di0 = dest_index; /* D75 probe: loop below mutates dest_index */
|
||||
SUPPORT_CHECK(n_vertices <= MAX_VERTICES);
|
||||
|
||||
if (!fast3d_ptr_ok(vertices) || dest_index + n_vertices > MAX_VERTICES) {
|
||||
@@ -1699,6 +1702,47 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx* verti
|
||||
|
||||
d->color.a = vcn->a; // can be required for SHADE_ALPHA even if fog is enabled
|
||||
}
|
||||
|
||||
#ifdef PORT
|
||||
/* TEMP D75 (M-19x): per-batch transformed-vertex range probe. Static
|
||||
* analysis of the nintendologo path exhausted itself clean (all 23 op=4
|
||||
* nodes visited every frame, GDLs byte-faithful to N64, every opcode
|
||||
* handled, G_VTX counts sum exactly to nv, G_TRI4 decode matches the
|
||||
* gSP4Triangles macro) -- so log what the pipeline actually computes:
|
||||
* for frames in [lo,hi] (env GE_D75V="lo-hi"), one line per G_VTX batch
|
||||
* with the resolved vertex ptr, raw first-vertex ob[], transformed
|
||||
* x/y/z/w ranges and the MP translation row. The logo's batches are
|
||||
* identifiable offline by vtx ptr == BaseAddr(0x70157a98)+file offset.
|
||||
* Remove once D75 is root-caused. */
|
||||
{
|
||||
static int d75v_lo = -1, d75v_hi = 0;
|
||||
if (d75v_lo < 0) {
|
||||
const char* v = getenv("GE_D75V");
|
||||
d75v_lo = 1; d75v_hi = 0x7fffffff;
|
||||
if (!v || sscanf(v, "%d-%d", &d75v_lo, &d75v_hi) != 2)
|
||||
d75v_lo = -1;
|
||||
}
|
||||
if (d75v_lo >= 0 && (int)videoGetFrameCount() >= d75v_lo &&
|
||||
(int)videoGetFrameCount() <= d75v_hi) {
|
||||
float mnx = 1e30f, mxx = -1e30f, mny = 1e30f, mxy = -1e30f,
|
||||
mnz = 1e30f, mxz = -1e30f, mnw = 1e30f, mxw = -1e30f;
|
||||
for (size_t i = 0; i < n_vertices; i++) {
|
||||
const struct LoadedVertex* d2 = &rsp.loaded_vertices[d75_di0 + i];
|
||||
if (d2->x < mnx) mnx = d2->x; if (d2->x > mxx) mxx = d2->x;
|
||||
if (d2->y < mny) mny = d2->y; if (d2->y > mxy) mxy = d2->y;
|
||||
if (d2->z < mnz) mnz = d2->z; if (d2->z > mxz) mxz = d2->z;
|
||||
if (d2->w < mnw) mnw = d2->w; if (d2->w > mxw) mxw = d2->w;
|
||||
}
|
||||
const Vtx* v0 = &vertices[0];
|
||||
sysLogPrintf(LOG_NOTE,
|
||||
"D75V: f=%u vtx=%p n=%zu di=%zu raw0=(%d,%d,%d) x[%.0f,%.0f] y[%.0f,%.0f] z[%.0f,%.0f] w[%.0f,%.0f] MPt=(%.1f,%.1f,%.1f)",
|
||||
videoGetFrameCount(), (const void*)vertices, n_vertices, d75_di0,
|
||||
(int)v0->v.ob[0], (int)v0->v.ob[1], (int)v0->v.ob[2],
|
||||
mnx, mxx, mny, mxy, mnz, mxz, mnw, mxw,
|
||||
rsp.MP_matrix[3][0], rsp.MP_matrix[3][1], rsp.MP_matrix[3][2]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gfx_sp_modify_vertex(uint16_t vtx_idx, uint8_t where, uint32_t val) {
|
||||
|
||||
@@ -40,6 +40,7 @@ void videoPumpEvents(void);
|
||||
/* The game's native video mode (NTSC 640x480, PAL 640x400). fast3d scales
|
||||
* N64 screen coordinates into window pixels using this. */
|
||||
void videoUpdateNativeResolution(s32 w, s32 h);
|
||||
u32 videoGetFrameCount(void);
|
||||
s32 videoGetNativeWidth(void);
|
||||
s32 videoGetNativeHeight(void);
|
||||
|
||||
|
||||
@@ -732,6 +732,7 @@ void videoUpdateNativeResolution(s32 w, s32 h)
|
||||
gfx_current_native_aspect = (float)w / (float)h;
|
||||
}
|
||||
|
||||
u32 videoGetFrameCount(void) { return frames; }
|
||||
s32 videoGetNativeWidth(void) { return gfx_current_native_viewport.width; }
|
||||
s32 videoGetNativeHeight(void) { return gfx_current_native_viewport.height; }
|
||||
|
||||
|
||||
Reference in new issue
Block a user