mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-24 00:02:45 +02:00
D306/D308: investigate z-fighting — depth precision == N64, real fighting confirmed; GE_ZF flicker probe in-tree
This commit is contained in:
1 parent
2efbbef964
commit
eaa137d6a9
5 files changed
+120
-8
No files matched your search
+19
-2
@@ -30,7 +30,7 @@ Sequencing follows M-139's R → Q → F order, split into four phases below.
|
||||
| D252 | Rainbow particles still intermittent on both platforms after the vertex-buffer fix | Second cause unrooted; prime suspect `import_texture_rgba16` fire-tile width/height from tile line size (32×7 vs 16×14). README known issue. |
|
||||
| D245 | Water seam between two patterns, moves with view (REOPENED) | M-142 probe: tc-shift k flips during ordinary rotation; opt-in `GE_D245_FIXEDSHIFT` candidate build-verified, needs A/B vs N64 reference before making it default. |
|
||||
| D303 | Wrong extra long muzzle flash (M16 + others) | **Investigated — pipeline + data ruled out.** Flash path (`gunUpdateAndFire` → `rwmtx[1]/[2]`, `dorottex` DLPRIMARY arms) is byte-identical game code; M16's `MuzzleFlashExtension`=6.0 is the legitimate max stat; Gm16Z flash-node data byte-faithful through d43. Headless runs can't fire weapons (guards don't shoot an idle player), so a TEMP `GE_D303=1` probe in `gfx_pc.cpp` logs every very-tall-thin emitted triangle with full RDP state — **blocked on a live firing capture** (playtest brief item 17). |
|
||||
| D306/D308 | Z-fighting: Dam intro/truck wheels + general/broader instances | Two reports, likely one family; investigate together. |
|
||||
| D306/D308 | Z-fighting: Dam intro/truck wheels + general/broader instances | **Investigated — real fighting confirmed, port-vs-faithful open.** Depth precision is equivalent to N64 (24-bit both sides; GE's RSP writes full 16.16 post-transform coords, not s16), so level-authored coincident geometry is the prime suspect and likely fights on N64 too. TEMP `GE_ZF=1` flicker probe in `gfx_pc.cpp` (recurrence-filtered; `GE_ZFBOX` region filter) shows sustained oscillation (counts ~1000) in the Dam-intro truck region. Closing it as faithful needs an N64 reference of the same spot; a PC-only mitigation (float depth) would diverge from N64 and needs a rule-2-style decision. |
|
||||
| D307 | In-level security camera props face backwards on some levels (Bunker) | **Investigated 2026-09-21 — no port-side bug found.** Full orientation path traced (`setupCctv` → per-frame `RotY(unkC8)×unk84`); every input verified N64-faithful against the ROM (PcctvZ switch data, boundpads incl. the legitimate load-time room-scale ×1.8542, record config words); all math helpers are byte-identical `src/game` code. Remaining suspect if it genuinely differs from N64: fast3d handling of the non-orthonormal lens matrix. **Blocked on user repro detail** (which camera/level + screenshot + ideally N64 compare). `GE_D307=1` diagnostic kept in-tree. |
|
||||
| D236 | Surface 1 billboard trees render as a solid wall of texture | **FIXED (M-198, pass 26, `425237f9`):** root cause was a texture-BINDING bug — `TEXTURETYPE_DETAIL` cards drawn from the detail tile (opaque IA8 noise) instead of the base image; `gfx_lod_tile_offset` now samples tile 1 when the pair differs (`Video.DetailBaseTile`, default on). Live-verified Surface 1/2 + Depot; other levels provably untouched. Awaiting user play-test sign-off; probes stripped (`0503d335`). |
|
||||
| D235 | Wrong textures after death/restart (level reload), multiple levels | State-leak on re-entry: texture pool / CI-cache not fully reset. Needs fresh-boot-vs-reload confirmation + surfaces + screenshot, then instrument `texInitPool`/CI-cache clear. |
|
||||
@@ -135,7 +135,11 @@ verification (headless where possible, human eyeball/ear as merge gate):
|
||||
6. **D303 + D306/D308 z-fighting family** — small visual parity items; batch
|
||||
per commit cadence. (~~D307 camera flip~~ investigated 2026-09-21: no
|
||||
port-side bug found, all inputs verified N64-faithful — blocked on user
|
||||
repro detail; see Bucket A row.)
|
||||
repro detail; see Bucket A row.) D303 + D306/D308 both investigated
|
||||
2026-07-19: no port-side bug found in either (pipeline/data/precision all
|
||||
verified N64-faithful); capture probes `GE_D303` and `GE_ZF` are in-tree —
|
||||
both now blocked on user-side captures (firing repro / N64 reference).
|
||||
Nothing further to do agent-side until those land.
|
||||
7. ~~**D236 tree wall**~~ — **done (M-198, pass 26):** `TEXTURETYPE_DETAIL`
|
||||
tile-binding fix in fast3d (`Video.DetailBaseTile`); live-verified,
|
||||
probes stripped. Only the user play-test sign-off remains.
|
||||
@@ -314,6 +318,19 @@ Order by user-visible value:
|
||||
Bunker1/Dam/Depot show only static scene geometry, so the artifact needs a
|
||||
live firing repro. Next: user fires the M16 under `GE_D303=1` and shares the
|
||||
log lines; the spurious quad's RDP state will identify its source.
|
||||
- **D306/D308 (z-fighting family) investigated — real fighting confirmed, cause
|
||||
framed.** Verified GE's RSP writes post-transform x/y/z/w as full 32-bit 16.16
|
||||
(not s16 8.8), so the port's float pipeline + `GL_DEPTH24_STENCIL8` matches N64
|
||||
depth precision — no port-side precision deficit exists. Built a TEMP
|
||||
`GE_ZF=1` flicker probe in `gfx_pc.cpp` (96×54 screen-cell grid, per-cell depth
|
||||
history, requires non-monotonic a-b-a oscillation within GE_ZFTOL recurring ≥5×
|
||||
at the same cell; `GE_ZFBOX` region filter) — earlier center-pair and simple
|
||||
flicker variants saturated on tessellation noise. Dam (`-level_33`) unattended:
|
||||
sustained hits in the lower-left truck region with per-cell oscillation counts to
|
||||
~970 → D306's "transparent areas" are real depth-test alternation. Prime suspect
|
||||
is level-authored coincident geometry (fights on N64 too); confirming port-only
|
||||
needs an N64 reference of the same spot, and a mitigation (e.g. float depth)
|
||||
would diverge from N64 — parked pending that.
|
||||
- **Plan/doc refresh:** D75 (M-197) and D236 (M-198) marked fixed throughout
|
||||
(Bucket A rows, Phase 1 items 6/7/11, playtest brief); findings index
|
||||
regenerated; README Known Issues to match.
|
||||
|
||||
@@ -183,9 +183,9 @@ D302,FIXED,"Render FPS regression to ~40-45fps on release/v0.3.0 (user QA on the
|
||||
D303,OPEN,"Some muzzle flashes (M16 named specifically, ""and some others"") draw wrong —","OPEN — investigated: pipeline + weapon stats + model conversion ruled out; GE_D303 capture probe in-tree (port/fast3d/gfx_pc.cpp), blocked on a live firing repro."
|
||||
D304,FIXED,"Mouse sensitivity menu overhaul (user request, 2026-09-18):","FIXED — see full entry for both the range/parity pass and the same-day follow-up (collapsed to a single Input.MouseSensitivity menu row + fixed overlayUpdateScroll()'s unconditional bottom-anchor, th…"
|
||||
D305,FIXED,"Steam Deck SIGSEGV on the v0.3.0 pre-release build (Cavern, early in the level, Game.AllUnlocked previously enabled on the session/save) —",FIXED (defensive guard) —
|
||||
D306,OPEN,"Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).","OPEN — reported only, not investigated."
|
||||
D306,OPEN,"Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).",OPEN — confirmed real depth-fighting by the GE_ZF probe (sustained oscillation in the truck region); port-vs-faithful blocked on an N64 reference.
|
||||
D307,OPEN,"In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g.",OPEN (investigated 2026-09-21) —
|
||||
D308,OPEN,"Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).","OPEN — reported/confirmed by the user, not investigated."
|
||||
D308,OPEN,"Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).","OPEN — investigated: PC depth precision == N64 (24-bit both sides; RSP writes full 16.16), so level-authored coincident geometry is the prime suspect; GE_ZF flicker probe in-tree."
|
||||
D309,FIXED,Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen —,FIXED via D310 — user-playtest-confirmed 2026-09-18 (Caverns→intro clean; the spin record itself observed resuming correctly in the post-fix probe log).
|
||||
D310,FIXED,"RULE-2-SIGNOFF: chraiitemsize() mis-sizes 1-byte AI_PRINT records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT —",FIXED — user-playtest-confirmed 2026-09-18 (v2:
|
||||
D311,PARTIAL,Complete freeze in modelSetAnimFrame2WithChrStuff root-motion loop —,"GUARDED (#ifdef PORT, D156-guard extension in the same file) —"
|
||||
|
||||
|
+14
-4
@@ -591,9 +591,9 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D303 | **Some muzzle flashes (M16 named specifically, "and some others") draw wrong — the flash renders very long, extending straight up from the gun (user QA on the v0.3.0 pre-release build, 2026-09-18).** — full `## D303` entry at file tail | OPEN — investigated: pipeline + weapon stats + model conversion ruled out; GE_D303 capture probe in-tree (`port/fast3d/gfx_pc.cpp`), blocked on a live firing repro. |
|
||||
| D304 | **Mouse sensitivity menu overhaul (user request, 2026-09-18): aim speed/turn speed sliders weren't "1:1", had too little range, and (follow-up) risked decoupling into a bad state; F10 menu also had a click-jump bug.** — full `## D304` entry at file tail | FIXED — see full entry for both the range/parity pass and the same-day follow-up (collapsed to a single `Input.MouseSensitivity` menu row + fixed `overlayUpdateScroll()`'s unconditional bottom-anchor, the actual cause of the reported "menu jumps to the setting below on click"). Build-verified (Windows) both passes; headless overlay smoke test clean after each. **Live F10 playtest done (2026-09-18): user confirmed the collapsed single-sensitivity menu works, the click-jump is gone, and the D251 bottom-row duplication no longer occurs.** |
|
||||
| D305 | **Steam Deck SIGSEGV on the v0.3.0 pre-release build (Cavern, early in the level, `Game.AllUnlocked` previously enabled on the session/save) — same exact FAULT ADDR 0x62 / `sndHandleEvent` signature as D285, reproduced AFTER D285's own lock fix was already live-verified crash-free on real hardware.** — full `## D305` entry at file tail | FIXED (defensive guard) — `sndHandleEvent`'s preempt-scan (`src/snd.c`) dereferenced its list-walk pointer before ever checking it for NULL (a do-while always runs its body once); D285's `osSetIntMask` lock only prevents another thread from emptying the list mid-scan, not a scan that starts with an already-empty list, so the crash could still happen even with that fix in place. Added the missing `iterState != NULL` guard before the loop, matching D255's established skip-instead-of-dereference precedent. Root desync mechanism (why pool-exhaustion accounting and the list can disagree) still not identified; `Game.AllUnlocked` correlation not proven, only reported. **Live-verified on the Deck (2026-09-18):** user ran two test sessions on Cavern with the updated build, plus toggled `Game.AllUnlocked` off then back on and relaunched — no crash in any of them. |
|
||||
| D306 | **Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).** — full `## D306` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0. |
|
||||
| D306 | **Dam intro/truck wheels render with odd transparent-looking areas, possibly z-fighting (user QA, 2026-09-18).** — full `## D306` entry at file tail | OPEN — confirmed real depth-fighting by the GE_ZF probe (sustained oscillation in the truck region); port-vs-faithful blocked on an N64 reference. |
|
||||
| D307 | **In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g. Bunker (user QA, 2026-09-18) — NOT the player's view camera.** — full `## D307` entry at file tail | OPEN (investigated 2026-09-21) — no port-side bug found: orientation path traced, every input verified N64-faithful vs ROM (`PcctvZ` switch data, room-scaled boundpads, config words), all math byte-identical `src/game`. Blocked on user repro detail; `GE_D307=1` diagnostic in-tree. |
|
||||
| D308 | **Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).** — full `## D308` entry at file tail | OPEN — reported/confirmed by the user, not investigated. Explicitly not for v0.3.0; D306 may be one instance of this. |
|
||||
| D308 | **Occasional z-fighting confirmed on some levels' geometry, general/broader than the D306 truck-wheel instance (user QA, 2026-09-18).** — full `## D308` entry at file tail | OPEN — investigated: PC depth precision == N64 (24-bit both sides; RSP writes full 16.16), so level-authored coincident geometry is the prime suspect; GE_ZF flicker probe in-tree. |
|
||||
| D309 | **Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen — boss thread spins forever in `ai()` on `m_RunToBondPersistent` via a phantom `GotoNext(lblZero)` created by `chraiitemsize`'s `AI_PRINT` NUL-scan mis-sizing a stringless PRINT record (user report + live GDB diagnosis, 2026-09-18).** — full `## D309` entry at file tail | **FIXED via D310 — user-playtest-confirmed 2026-09-18** (Caverns→intro clean; the spin record itself observed resuming correctly in the post-fix probe log). The teardown-ordering open question (why PC presents the unreachable-Bond state) remains documented but is now harmless. |
|
||||
| D310 | **RULE-2-SIGNOFF: `chraiitemsize()` mis-sizes 1-byte `AI_PRINT` records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT — fixes D309's freeze mechanism and the Caverns standing-still guards (`Stop`+`PRINT("wait")` mis-lands on EndList, re-executed every tick; user report 2026-09-18).** — full `## D310` entry at file tail | **FIXED — user-playtest-confirmed 2026-09-18** (v2: global-list-only sizing via `d310ItemSize`; guards resume, Trevelyan pathing intact, Caverns→intro clean; probe log verified both list classes). PD precedent: PRINT removed, slot 0xAD reassigned. |
|
||||
| D311 | **Complete freeze in `modelSetAnimFrame2WithChrStuff` root-motion loop — D156 guard hole: poisoned `framea` (`model->animframe1`) passes the frameb-only clamp and saturates to a ~3.1e9-iteration spin (Caverns, live GDB diagnosis, 2026-09-18).** — full `## D311` entry at file tail | GUARDED (`#ifdef PORT`, D156-guard extension in the same file) — freeze class neutralized; upstream speed/frame poison source OPEN (level reload clears displaced model state). No AI involvement — distinct from D309/D310. |
|
||||
@@ -12228,7 +12228,9 @@ do {
|
||||
|
||||
**Reported only, not investigated, explicitly not for v0.3.0.** User playtest: the truck's wheels on Dam (seen during the level intro) render oddly, showing what look like transparent areas where they shouldn't be — user's own suspicion is z-fighting. No code read done. May be an instance of the broader z-fighting issue logged separately as D308, or a distinct texture/alpha bug specific to this prop — not distinguished yet.
|
||||
|
||||
**Status:** OPEN — logged, no investigation started. Deferred past v0.3.0 by user instruction.
|
||||
**Investigation (2026-07-19, with D308):** see §D308's investigation block — the two were worked together. The `GE_ZF` flicker probe confirms **real, persistent depth-fighting in the Dam intro's lower-left screen region** (the truck area) — cells there accrue oscillation counts to ~1000 over a 40 s unattended run, i.e. near-equal depths genuinely alternating frame-to-frame, not tessellation noise. The "transparent-looking areas" are consistent with the wheel geometry losing the depth test against coincident surfaces in alternating frames.
|
||||
|
||||
**Status:** OPEN — confirmed as real z-fighting by probe; port-vs-faithful question open (see D308).
|
||||
|
||||
## D307 — In-level security camera entities can be flipped facing the wrong direction (backwards) on some levels, e.g. Bunker (user QA, 2026-09-18).
|
||||
|
||||
@@ -12248,7 +12250,15 @@ do {
|
||||
|
||||
**Reported/confirmed by the user, not investigated, explicitly not for v0.3.0.** User: "Confirmed occasional z-fighting in some levels due to the level geometry and current state of code" — framed as a general, known-class issue (overlapping/coincident geometry at the current renderer's precision) rather than a single specific bug site. D306 (Dam truck wheels) may be one visible instance of this broader class, not confirmed as the same mechanism.
|
||||
|
||||
**Status:** OPEN — logged, no investigation started. Deferred past v0.3.0 by user instruction.
|
||||
**Investigation (2026-07-19, with D306):**
|
||||
|
||||
- **Depth pipeline precision compared against N64 — equivalent.** GE's RSP (`rsp/graphics/gmain.s` vertex transform) writes post-transform x/y/z/w back to the vertex buffer as **full 32-bit 16.16 fixed-point** (`sdv` stores at +0/+8/+18), NOT s16 8.8 — so the RDP receives full-precision NDC on N64. The port's `gfx_sp_vertex` keeps float (≥ as precise). Both sides write into a **24-bit integer depth buffer** (port: `GL_DEPTH24_STENCIL8`; N64 RDP: 24-bit z-image) with the same near/far from the game's projection matrix. Net: the PC has *no less* depth precision than the N64 — coincident-geometry fighting that exists in the level data fights on both platforms.
|
||||
- **Probe.** TEMP env-gated `GE_ZF=1` flicker detector in `port/fast3d/gfx_pc.cpp`: a 96×54 screen-cell grid remembers recent per-cell 24-bit depth values; a hit requires non-monotonic oscillation (a-b-a within `GE_ZFTOL`, default 2 units) that **recurs ≥5 times at the same cell** — filters out tessellation gradients and one-off camera-motion coincidences. Optional region filter `GE_ZFBOX="x0 y0 x1 y1"`.
|
||||
- **Result (Dam, `-level_33`, 40 s unattended, intro plays automatically):** sustained hits in the lower-left screen region (ndc ≈ x∈[-0.1,+0.1], y≈-0.57 — the truck) with per-cell oscillation counts reaching ~970: genuine near-equal depths alternating across hundreds of frames.
|
||||
- **Open question — port bug or faithful?** Given equivalent precision on both sides, the most likely explanation is **level-authored coincident geometry** (the user's own framing: "due to the level geometry") that fights on N64 too. Proving/disproving requires an N64 reference of the same spot (footage or side-by-side), which is not available in this environment. Secondary suspects if it turns out PC-only: exact `glDepthFunc`/z-range edge cases, or MSAA depth behavior — none evidenced so far.
|
||||
- **Fix posture if confirmed PC-only:** no game-code lever exists (depth values are the game's); a port-side mitigation would be a precision change (e.g. 32-bit float depth) which would *reduce* fighting but diverge from N64 behavior — needs a rule-2-style decision, not a silent fix.
|
||||
|
||||
**Status:** OPEN — real z-fighting confirmed by probe; port-vs-faithful blocked on an N64 reference of the same spot.
|
||||
|
||||
## D309 — Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen — boss thread spins forever in `ai()` on `m_RunToBondPersistent` via a phantom `GotoNext(lblZero)` (user report + live GDB diagnosis, 2026-09-18).
|
||||
|
||||
|
||||
@@ -1201,6 +1201,12 @@ produce the same visual symptom but need opposite fixes.
|
||||
|
||||
**Update 2 (same investigation, immediately after): freezing a *value* and freezing a *pointer target* are different operations — treating them the same crashed twice.** Extending the same freeze technique to `render_pos` (a `Model*` field, unlike `field_488.pos` a plain value) by skipping the call that reassigns it (`subcalcmatrices`) seemed equivalent to M-167's "skip the write" but wasn't: `render_pos` is a pointer into a per-tick dynamically-reallocated arena, and skipping its reassignment only works if the pointer it's left holding is still valid — which depends on model lifecycle, not just on this tick's logic. Two fixes in a row tried to detect "is it safe to skip" by inspecting either the pointer's *value* (a sentinel check, `!= NULL && != -1`) or a *cached identity* (comparing the pointer against a remembered "already validated" pointer) — both crashed, because **the allocator reuses model-pointer addresses across genuinely different logical model instances**: a freshly-`CREATE`d model can land at the exact address a previously-removed model occupied, so both the sentinel check and the identity check wrongly conclude "this is already valid" for an instance whose `render_pos` is still an uninitialized tombstone. This is the same "don't guess validity from a value that can coincidentally look right" trap as the paragraph above, encountered a second time from a different angle (a *pointer's* target identity, not a *field's* content). **The robust fix:** never skip the call that establishes the pointer's validity — let it always run — and apply the freeze as a *contents* copy afterward, on top of a buffer that's now unconditionally guaranteed valid. If you must "hold something steady" and that something is reached through a pointer that some other code reassigns, freeze the *pointee's bytes*, not the *act of assignment* — the assignment is usually also the thing keeping the pointer sane.
|
||||
|
||||
## D12. Depth precision: the port matches N64 exactly — z-fighting seen on PC is probably faithful (D306/D308)
|
||||
|
||||
When a user reports z-fighting, do NOT assume the software renderer has less depth precision than the RDP. Verified for GE: the RSP's vertex transform (`rsp/graphics/gmain.s`) writes post-transform x/y/z/w back to the vertex buffer as **full 32-bit 16.16 fixed-point** (`sdv` stores), not s16 8.8 — the RDP interpolates from full-precision NDC and quantizes once, into its 24-bit z-image. The port keeps floats through `gfx_sp_vertex` and writes a `GL_DEPTH24_STENCIL8` buffer: same or better precision at every stage, same near/far. So coincident geometry authored into the level fights on both platforms; a PC-only explanation needs positive evidence (an N64 reference of the same spot), not just the existence of the symptom. A mitigation like switching to 32-bit float depth would *reduce* fighting but diverge from N64 behavior — that's a rule-2-style decision, not a silent fix.
|
||||
|
||||
**Probe technique that worked (vs. three variants that didn't):** detecting z-fighting from emitted triangles requires filtering out (a) tessellation gradients — adjacent tris of one surface have near-equal depths by construction — and (b) camera-motion coincidences — as the camera moves, unrelated world points pass through the same screen cell and their depths happen to sit close. What survives both: a coarse screen-cell grid keeping a short per-cell depth history, flagging only **non-monotonic** (a-b-a) oscillation within a small tolerance that **recurs many times at the same cell**. Monotonic drift = gradient; one-off close pairs = motion artifact; sustained recurrence = a real fight. `GE_ZF` in `port/fast3d/gfx_pc.cpp` implements this (`GE_ZFTOL` tolerance, `GE_ZFBOX` region filter).
|
||||
|
||||
## E. Process / method notes
|
||||
|
||||
- Investigation loop is: reproduce → env-gated capped probe → root-cause
|
||||
|
||||
@@ -1571,6 +1571,84 @@ static void d75d_note_vtx(uint32_t f, uint32_t count, uint32_t dest) {
|
||||
if (dest + count > d75d_batchhi) d75d_batchhi = dest + count;
|
||||
if (d75d_seqlen < 4096) d75d_seq[d75d_seqlen++] = 'V';
|
||||
}
|
||||
/* TEMP D306/D308: env-gated z-fighting FLICKER detector (docs/dev/findings.md
|
||||
* §D306/§D308). A coarse grid of screen cells remembers the depth values seen
|
||||
* recently at each cell; when a new value arrives that is close to a
|
||||
* recently-seen-but-different one (within GE_ZFTOL, default 2 units of 24-bit
|
||||
* quantized NDC z), that is the screen-space signature of genuine z-fighting
|
||||
* (the winner alternates between two near-equal depths as the camera moves).
|
||||
* Tessellation noise (adjacent tris of one surface) does not alternate. Gated
|
||||
* on GE_ZF; optional NDC box filter GE_ZFBOX="x0 y0 x1 y1"; caps output per
|
||||
* run. Remove once D306/D308 are resolved. */
|
||||
static int zf_on = -1;
|
||||
static int zf_tol = 2;
|
||||
static float zfbox[4] = { -1.05f, -1.05f, 1.05f, 1.05f };
|
||||
static int zfbox_on = 0;
|
||||
#define ZF_GRIDX 96
|
||||
#define ZF_GRIDY 54
|
||||
#define ZF_HIST 6
|
||||
struct ZfCell { uint32_t hist[ZF_HIST]; uint8_t n; uint16_t osc; };
|
||||
static ZfCell zf_grid[ZF_GRIDX * ZF_GRIDY];
|
||||
static uint32_t zf_hits = 0;
|
||||
#define ZF_MIN_OSC 5 // a fight must recur this many times at the same cell
|
||||
static void zf_note_emit(uint32_t f, struct LoadedVertex* const* v_arr) {
|
||||
if (zf_on < 0) {
|
||||
const char* e = getenv("GE_ZF");
|
||||
zf_on = (e && e[0]) ? 1 : 0;
|
||||
const char* t = getenv("GE_ZFTOL");
|
||||
if (t) zf_tol = atoi(t);
|
||||
const char* b = getenv("GE_ZFBOX");
|
||||
if (b && sscanf(b, "%f %f %f %f", &zfbox[0], &zfbox[1], &zfbox[2], &zfbox[3]) == 4)
|
||||
zfbox_on = 1;
|
||||
}
|
||||
if (!zf_on || zf_hits >= 600) return;
|
||||
float cx=0.f, cy=0.f, czw=0.f, wsum=0.f; int ok=0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float w = v_arr[i]->w;
|
||||
if (w <= 0.f) continue;
|
||||
cx += (v_arr[i]->x / w) * w; cy += (v_arr[i]->y / w) * w; czw += (v_arr[i]->z / w) * w; wsum += w;
|
||||
ok = 1;
|
||||
}
|
||||
if (!ok || wsum <= 0.f) return;
|
||||
cx /= wsum; cy /= wsum; czw /= wsum;
|
||||
if (cx < -1.0f || cx > 1.0f || cy < -1.0f || cy > 1.0f) return; // on-screen only
|
||||
if (zfbox_on && (cx < zfbox[0] || cx > zfbox[2] || cy < zfbox[1] || cy > zfbox[3])) return;
|
||||
uint32_t z24 = (uint32_t)(czw * 255.f); // NDC z in [-1,1] -> 24-bit [0,65535]
|
||||
int gx = (int)((cx + 1.0f) * 0.5f * ZF_GRIDX); if (gx >= ZF_GRIDX) gx = ZF_GRIDX - 1;
|
||||
int gy = (int)((cy + 1.0f) * 0.5f * ZF_GRIDY); if (gy >= ZF_GRIDY) gy = ZF_GRIDY - 1;
|
||||
ZfCell* c = &zf_grid[gy * ZF_GRIDX + gx];
|
||||
int dup = 0;
|
||||
for (uint8_t k = 0; k < c->n; k++) if (c->hist[k] == z24) { dup = 1; break; }
|
||||
if (!dup) {
|
||||
// TRUE oscillation: new value close to an OLDER history entry while a
|
||||
// different value sat between them (a b a), AND the cell's history is
|
||||
// not a monotonic drift (tessellation gradient of one surface).
|
||||
int anyup = 0, anydn = 0;
|
||||
for (uint8_t k = 1; k < c->n; k++) {
|
||||
if (c->hist[k] > c->hist[k - 1]) anyup = 1;
|
||||
else if (c->hist[k] < c->hist[k - 1]) anydn = 1;
|
||||
}
|
||||
if (!(anyup && anydn)) goto zf_push; // monotonic drift = gradient, not a fight
|
||||
for (uint8_t k = 0; k + 1 < c->n; k++) {
|
||||
long dz = (long)z24 - (long)c->hist[k];
|
||||
if (dz < 0) dz = -dz;
|
||||
if (dz > 0 && dz <= (long)zf_tol) {
|
||||
uint16_t o = ++c->osc;
|
||||
if (o < ZF_MIN_OSC || (o % 10) != 0 && o != ZF_MIN_OSC) goto zf_push;
|
||||
zf_hits++;
|
||||
fprintf(stderr,
|
||||
"ZF: f=%u z24=%u dprev=%ld osc=%u ndc=(%.3f,%.3f) oml=0x%08x comb=0x%016llx wavg=%.1f\n",
|
||||
f, z24, dz, (unsigned)o, cx, cy, rdp.other_mode_l,
|
||||
(unsigned long long)rdp.combine_mode, wsum / 3.0f);
|
||||
if (zf_hits >= 600) return;
|
||||
}
|
||||
}
|
||||
zf_push:
|
||||
if (c->n < ZF_HIST) c->hist[c->n++] = z24;
|
||||
else { memmove(c->hist, c->hist + 1, sizeof(uint32_t) * (ZF_HIST - 1)); c->hist[ZF_HIST - 1] = z24; }
|
||||
}
|
||||
}
|
||||
|
||||
/* TEMP D303: env-gated detector for the "extra long flash straight up" quad
|
||||
* (M-?? / docs/dev/findings.md §D303). Logs any emitted triangle whose NDC bbox
|
||||
* is tall + thin (aspect > 3, height > 25% of frame) and mostly on-screen — the
|
||||
@@ -2533,6 +2611,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
|
||||
d75d_note_emit(videoGetFrameCount(), v_arr); // survived all rejection gates -> reaches GL
|
||||
d303_note_emit(videoGetFrameCount(), v_arr); // TEMP D303
|
||||
zf_note_emit(videoGetFrameCount(), v_arr); // TEMP D306/D308
|
||||
d75d_note_emit_z(videoGetFrameCount(), v_arr, (used_textures[0] || used_textures[1]) ? 1 : 0, comb->used_textures[0] ? 1 : 0);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float z = v_arr[i]->z, w = v_arr[i]->w;
|
||||
|
||||
Reference in new issue
Block a user