From 0503d335646b98153570c05b3b1d535f13e61d06 Mon Sep 17 00:00:00 2001 From: James Dansereau <106631954+jkdansereau@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:53:04 -0400 Subject: [PATCH] D236: strip the investigation probes now that the finding is closed D236 was root-caused and fixed in the previous commit, so its diagnostic scaffolding comes out: GE_D236RM / GE_D236ORDER / GE_D236ALPHA / GE_D236ZFIX gfx_sp_tri1 GE_D236RAW bg.c room load GE_D236BT chr.c + model.c port_d236bt_dump() host stack backtrace g_d236_last_vtx_seg / _raw G_VTX trackers Also drops the include that only the backtrace dumper needed, and rewords the one D288 comment that cross-referenced GE_D236RM. src/game/bg.c, chr.c and model.c are back to their pre-probe state -- no game-code diff from D236 remains. The pass-26 fix in gfx_lod_tile_offset is untouched. Doc rows removed from GE-ENV-PROBES.md; gen_env_probes.py --check and gen_findings_index.py --check both pass. Build clean. The Surface 1 spawn capture is unchanged across the strip (settled frame 560 within threshold; the intro-pan frames never match run-to-run, D117). --- docs/dev/GE-ENV-PROBES.md | 6 - docs/dev/findings.md | 10 +- port/fast3d/gfx_pc.cpp | 267 +------------------------------------- src/game/bg.c | 42 ------ src/game/chr.c | 29 ----- src/game/model.c | 37 ------ 6 files changed, 10 insertions(+), 381 deletions(-) diff --git a/docs/dev/GE-ENV-PROBES.md b/docs/dev/GE-ENV-PROBES.md index 0db006db..a0a852bc 100644 --- a/docs/dev/GE-ENV-PROBES.md +++ b/docs/dev/GE-ENV-PROBES.md @@ -64,12 +64,6 @@ Two classes: | `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) | | `GE_D288` | `port/fast3d/gfx_pc.cpp` (`gfx_sp_tri1`, right after the D233 trivial-reject guard; cached `ge_d288`) | M-152 diag for the Silo intro stray triangle: frame-gated to `num_dls` 550–755 (M-155), now **skips `any_behind_camera==1` triangles** (M-155 follow-up — the x/w divide is meaningless for w≤0; that subset was pure false-lead noise) and logs the render-mode word (`oml`) so a live capture can ID the culprit asset against level tables. Logs any triangle whose clip-space NDC bbox covers >50% of the screen or goes non-finite, with each vertex's `w`. Bare `-level_20` re-run: 1965 sane hits in the window, still zero for the target color RGB(83,62,44) — consistent with M-155's working theory that the bare boot's scripted camera never reaches the bug state; **headless probing is at its limit, live capture is next**. | **live** (D288) | -| `GE_D236RM` | `port/fast3d/gfx_pc.cpp` (`gfx_sp_tri1`, unconditional getenv, no state kept when unset) | M-155/pass-10 diag for D236: per-frame (`num_dls`) triangle count of the `0x0c184b50` render-mode class (`other_mode_l` exact match), heartbeat-logged every 300 frames even at zero. **REFRAMED D280's "run-to-run dependent instantiation" as ordinary room-based occlusion**, not a CPU-side gating bug — see `## D236` pass-10 writeup. | **live** (D236 OPEN, kept for future passes) | -| `GE_D236ORDER` | `port/fast3d/gfx_pc.cpp:1844` (`gfx_sp_tri1`, cached `s_d236order`) | D236 pass-12 diag: per-DL sequence log of the tree-class triangles (DL index, screen-space depth, noise min/max census) to test the draw-order hypothesis. Zero cost unset; remove once D236 concludes. | **live** (D236 OPEN) | -| `GE_D236ALPHA` | `port/fast3d/gfx_pc.cpp:1896` (`gfx_sp_tri1`, cached `s_d236alpha`) | D236 pass-14 diag: for the `0x0c184b50` tree-class render mode, logs the combine/alpha state of up to 4000 matching triangles (deduped on combine change) so the captured draw can be cross-checked against the source. Zero cost unset; remove once D236 concludes. | **live** (D236 OPEN) | -| `GE_D236ZFIX` | `port/fast3d/gfx_pc.cpp:1970` (`gfx_sp_tri1`, cached `s_d236zfix`) | D236 pass-12 test override: forces `depth_update=true` for the `0x0c184b50` tree-class render mode — a cheap mechanism test before deciding what a real fix looks like. Off by default; remove once D236 concludes. | **live, test-only** (D236 OPEN) | -| `GE_D236RAW` | `src/game/bg.c:2437` (`#ifdef PORT`) | D236 pass-16 diag: one-shot census of the raw vertex table's alpha-byte distribution (5 buckets + min/max), camera-independent, to check whether any vertex in the whole table exceeds the low ceiling. Zero cost unset; remove once D236 concludes. | **live** (D236 OPEN) | -| `GE_D236BT` | `src/game/chr.c` (`get_ptr_allocated_block_for_vertices`, `#ifdef PORT`) + `src/game/model.c` (`doshadow`) + `port/fast3d/gfx_pc.cpp` (`port_d236bt_dump()`) | D236 pass-17 diag: host stack backtrace at vertex-arena allocation time (pinpoints the CPU-side quad builder — proved it's `doshadow`) plus a one-shot live ShadowRecord/tconfig dump in `doshadow` (writes `d236sh.bin` to CWD on first hit). Zero cost unset; remove once D236 concludes. | **live, TEMP** (D236 OPEN) | | `GE_D245V` | `src/game/sky.c:962` (`skyPortRenderPoly`-adjacent, `#ifdef PORT`) | D245 water-seam diag: per-call min/max of the recomputed S/T texture-coordinate ranges for the water fan vertices (rate-limited), to check whether the seam tracks a tc-shift boundary. Inert unset. | **live** (D245 OPEN) | | `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) | diff --git a/docs/dev/findings.md b/docs/dev/findings.md index e55c313e..6a1edfd5 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -11298,8 +11298,14 @@ stale entry from an earlier type-1 draw satisfies it. **Generalised to `docs/porting-notes.md` §D12.** -**Housekeeping:** the pass-25 `GE_D236P25` probe and the pass-26 cut-out -experiment are both removed from the tree (the mip question is closed). +**Housekeeping:** with D236 closed, every D236 diagnostic is out of the tree +-- the pass-25 `GE_D236P25` probe and the pass-26 cut-out experiment, plus +`GE_D236RM`/`ORDER`/`ALPHA`/`ZFIX` (`gfx_pc.cpp` `gfx_sp_tri1`), `GE_D236RAW` +(`bg.c`), `GE_D236BT` (`chr.c` + `model.c`), the `port_d236bt_dump()` host +backtrace dumper and the `windows.h` include it needed, and the +`g_d236_last_vtx_seg`/`_raw` G_VTX trackers. Their rows are gone from +`GE-ENV-PROBES.md`; `gen_env_probes.py --check` is in sync. Build clean and +the Surface 1 spawn capture is unchanged across the strip. ## D237 — QoL ask (M-106, user QA): F10 options overlay — make it scrollable with the mouse wheel, expose more settings into it (e.g. screen-flash / no-hit-flash… diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 234b37e6..fb6dd17f 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -4,10 +4,6 @@ #include #include #include -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include /* D236 pass 17 GE_D236BT backtrace probe */ -#endif #include #include @@ -143,80 +139,6 @@ static struct RSP { const struct NormalColor *vertex_colors; //[MAX_VERTEX_COLORS]; } rsp; -/* D236 pass 16 (TEMP): segment byte (top byte of the raw segmented address) - * of the most recent G_VTX load, so a later triangle-time probe can report - * which segment the tree class's vertices actually came from. See the - * G_VTX case comment below for why. Remove once D236 pass 16 concludes. */ -static uint8_t g_d236_last_vtx_seg = 0xFF; -/* D236 pass 17 (TEMP): full raw w1 of the most recent G_VTX, so the - * GE_D236BT backtrace probe can report WHICH buffer the tree class's - * triangles read from alongside the C call site that submitted them. - * Remove once D236 pass 17 concludes. */ -static uint32_t g_d236_last_vtx_raw = 0; - -/* D236 pass 17b (TEMP): host stack backtrace dumper, C-linkage so the - * allocator-side probe in src/game/chr.c can call it too. Windows-only: - * RtlCaptureContext + RtlVirtualUnwind over the exe's own .pdata table - * (this box's dbghelp.dll is stripped: no CaptureStackBackTrace, - * StackWalk64 fails immediately; RtlCaptureContext must be called - * directly -- GetProcAddress indirection zero-filled the context; - * mingw-ld leaves DataDirectory[10] zero even when .pdata is present, - * so find it by section name and trim the trailing zeroed entry; NULL - * out-params crash RtlVirtualUnwind). Frames print as RVAs -- resolve - * offline with addr2line against this exact exe. Remove once D236 - * pass 17 concludes. */ -#ifdef _WIN32 -extern "C" void port_d236bt_dump(const char* tag) { - CONTEXT ctx; - RtlCaptureContext(&ctx); - const HMODULE imgbase_h = GetModuleHandleA(NULL); - const ULONG64 imgbase = (ULONG64)(uintptr_t)imgbase_h; - PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)imgbase_h; - PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)((BYTE*)imgbase_h + dos->e_lfanew); - PIMAGE_SECTION_HEADER shs = (PIMAGE_SECTION_HEADER) - ((BYTE*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); - typedef struct { DWORD BeginAddress; DWORD EndAddress; DWORD UnwindDataAddress; } D236_RF; - D236_RF* rfs = NULL; - int nvalid = 0; - for (WORD si = 0; si < nth->FileHeader.NumberOfSections; si++) { - if (_stricmp((const char*)shs[si].Name, ".pdata") == 0) { - rfs = (D236_RF*)((BYTE*)imgbase_h + shs[si].VirtualAddress); - nvalid = (int)(shs[si].SizeOfRawData / sizeof(D236_RF)); - while (nvalid > 0 && (rfs[nvalid - 1].BeginAddress == 0 || - rfs[nvalid - 1].EndAddress == 0)) - nvalid--; - break; - } - } - ULONG64 rip = (ULONG64)(uintptr_t)ctx.Rip; - fprintf(stderr, "D236BT %s rip_rva=0x%llx nvalid=%d\n", - tag ? tag : "?", (unsigned long long)(rip - imgbase), nvalid); - for (int depth = 0; depth < 32 && rfs != NULL; depth++) { - const ULONG64 rva = rip - imgbase; - int lo = 0, hi = nvalid - 1; - D236_RF* rf = NULL; - while (lo <= hi) { - const int mid = (lo + hi) / 2; - if (rva < rfs[mid].BeginAddress) hi = mid - 1; - else if (rva >= rfs[mid].EndAddress) lo = mid + 1; - else { rf = &rfs[mid]; break; } - } - if (!rf) { - fprintf(stderr, "D236BT %s [%d] rva=0x%llx (outside exe .pdata)\n", tag, depth, - (unsigned long long)rva); - break; - } - PVOID hd = NULL; - DWORD64 ef = 0; - RtlVirtualUnwind(0, imgbase, rip, (PRUNTIME_FUNCTION)rf, &ctx, - &hd, &ef, NULL); - rip = (ULONG64)(uintptr_t)ctx.Rip; - fprintf(stderr, "D236BT %s [%d] rva=0x%llx\n", tag, depth, - (unsigned long long)(rip - imgbase)); - } -} -#endif - struct RawTexMetadata { uint16_t width, height; float h_byte_scale = 1, v_pixel_scale = 1; @@ -2145,7 +2067,8 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo * run fired 116k times in ~1500-2000 frames -- bbox_frac >0.15 * alone is a common occurrence for ordinary near-camera geometry, * not a distinguishing signature. Gated to the reported frame - * window (num_dls, same pattern as GE_D236RM below) and the + * window (num_dls, the pattern the since-removed GE_D236RM + * probe also used) and the * threshold raised well above the ~0.15 "normal" baseline M-155 * established, so a hit here is actually rare. M-155 follow-up: * for any_behind_camera==1 triangles the x/w perspective divide is @@ -2178,160 +2101,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo } } - /* D236 pass 10 (M-155, TEMP): does the 0x0c184b50 render-mode class's - * per-frame triangle count actually vary frame-to-frame WITHIN one - * deterministic -level_36 boot, or is D280's "run-to-run dependent" - * observation only visible ACROSS separate process launches (which - * would point at room-streaming state that isn't reset/seeded the - * same way twice, not at true per-frame nondeterminism)? Log the - * count once per display list (frame) while it's nonzero. Remove - * once D236 pass 10 concludes. */ - static int s_d236rm = -1; - if (s_d236rm < 0) s_d236rm = getenv("GE_D236RM") != NULL; - if (s_d236rm) { - static uint32_t d236rm_last_dl = 0xFFFFFFFFu; - static uint32_t d236rm_count = 0; - extern uint32_t num_dls; - if (num_dls != d236rm_last_dl) { - if (d236rm_count != 0 || (num_dls % 300) == 0) { - fprintf(stderr, "D236RM dl=%u count=%u\n", d236rm_last_dl, d236rm_count); - } - d236rm_last_dl = num_dls; - d236rm_count = 0; - } - if (rdp.other_mode_l == 0x0c184b50u) { - d236rm_count++; - } - } - - /* D236 pass 12 (M-191, TEMP): new angle, not tried by passes 1-11 (all of - * which focused on the tree-card class's z/w and instantiation counts). - * Both the noise "wall" (oml=0xc81049d8) and the discrete tree-card class - * (oml=0x0c184b50) decode to Z_CMP=1/Z_UPD=0/ZMODE=DEC (checked offline - * against both full oml words) -- NEITHER writes the depth buffer. Two - * no-z-write decals drawn against the same static (z-writing) background - * never actually depth-test against EACH OTHER: each is tested only - * against the background's z, so on-screen precedence between the two - * decals is decided purely by which one is submitted LAST in the frame's - * draw list, not by which one's own z/w is smaller (the z/w comparisons - * all 11 prior passes made are therefore not conclusive either way about - * visual winner). This probe tests that directly: track a per-frame - * submission-order counter (reset whenever num_dls changes, i.e. once - * per frame) and log the min/max order index seen for each of the two - * classes whenever num_dls changes and at least one of them appeared - * that frame -- if the noise class's order index is consistently HIGHER - * (drawn later) than the tree class's in frames where both appear, that - * directly explains "wall painted over trees" regardless of geometric - * depth, and points at a draw-order (not depth) bug. Remove once D236 - * pass 12 concludes. */ - static int s_d236order = -1; - if (s_d236order < 0) s_d236order = getenv("GE_D236ORDER") != NULL; - if (s_d236order) { - static uint32_t d236o_last_dl = 0xFFFFFFFFu; - static uint32_t d236o_seq = 0; - static uint32_t d236o_noise_min = 0, d236o_noise_max = 0, d236o_noise_n = 0; - static uint32_t d236o_tree_min = 0, d236o_tree_max = 0, d236o_tree_n = 0; - extern uint32_t num_dls; - if (num_dls != d236o_last_dl) { - if (d236o_noise_n != 0 || d236o_tree_n != 0) { - fprintf(stderr, - "D236ORDER dl=%u noise_n=%u noise_order=[%u,%u] tree_n=%u tree_order=[%u,%u] " - "tree_last_after_noise_last=%d\n", - d236o_last_dl, d236o_noise_n, d236o_noise_min, d236o_noise_max, - d236o_tree_n, d236o_tree_min, d236o_tree_max, - (d236o_tree_n != 0 && d236o_noise_n != 0) ? (int) (d236o_tree_max > d236o_noise_max) : -1); - } - d236o_last_dl = num_dls; - d236o_seq = 0; - d236o_noise_min = d236o_noise_max = d236o_noise_n = 0; - d236o_tree_min = d236o_tree_max = d236o_tree_n = 0; - } - if (rdp.other_mode_l == 0xc81049d8u) { - if (d236o_noise_n == 0) d236o_noise_min = d236o_seq; - d236o_noise_max = d236o_seq; - d236o_noise_n++; - } else if (rdp.other_mode_l == 0x0c184b50u) { - if (d236o_tree_n == 0) d236o_tree_min = d236o_seq; - d236o_tree_max = d236o_seq; - d236o_tree_n++; - } - d236o_seq++; - } - - /* D236 pass 14 (M-19x, TEMP): pass 13's live capture ruled out draw - * order as the dominant cause even in the favorable (tree-after-noise, - * high tri count) zone -- redirecting to whether the tree class's own - * per-vertex alpha (D280's "gfog=0, CPU-baked bimodal 25/255" census) - * is actually LOW (near-transparent) for the close/high-count trees the - * live capture walked through. This render mode's blend equation is a - * standard alpha-blend decal (FORCE_BL, GBL c1/c2 = CLR_IN,A_IN -> - * CLR_MEM,1-A_IN -- see include/PR/gbi.h RM_AA_ZB_XLU_DECAL), so if the - * combiner's alpha output tracks vertex/SHADE alpha directly, a card - * baked near 25/255 (~10%) would blend almost invisibly over whatever - * was drawn under it -- looking exactly like "the noise wall shows - * through" even with correct geometry and correct draw order. Logs, - * once per triangle of this class: each vertex's raw color.a, the - * combine_mode word (to see which alpha slot actually feeds the - * blend), and 1/w (a cheap camera-distance proxy) so alpha can be - * correlated against "close" vs "far" the same way pass 13's live - * capture was read. Zero cost unset. Remove once D236 pass 14 - * concludes. */ - /* D236 pass 17 (TEMP): six passes of signature-matching (11-16) failed - * to identify the CPU-side writer of the tree class's raw-pointer vertex - * batches. Stop guessing: on the first triangle(s) of this class whose - * vertices came from a raw (unsegmented, seg 0x70) G_VTX load, capture a - * host stack backtrace -- the C call chain that submitted this display - * list IS the writer's caller, no inference needed. Windows-only (this - * build): RtlCaptureContext + RtlVirtualUnwind over the exe's own .pdata - * table -- this box's dbghelp.dll is stripped (no CaptureStackBackTrace; - * StackWalk64 fails immediately), so ntdll does the unwind and there is - * no dbghelp dependency at all. Frames print as RVAs, resolved offline - * with addr2line against this exact exe. Env-gated, fires at most once - * per distinct raw pointer (cap 5), zero cost unset. Remove once D236 - * pass 17 concludes. */ -#ifdef _WIN32 - static int s_d236bt = -1; - if (s_d236bt < 0) s_d236bt = getenv("GE_D236BT") != NULL; - if (s_d236bt && rdp.other_mode_l == 0x0c184b50u && g_d236_last_vtx_seg == 0x70) { - static uint32_t d236bt_seen[5] = {0, 0, 0, 0, 0}; - static int d236bt_n = 0; - int dup = 0; - for (int i = 0; i < d236bt_n; i++) { - if (d236bt_seen[i] == g_d236_last_vtx_raw) { dup = 1; break; } - } - if (!dup && d236bt_n < 5) { - d236bt_seen[d236bt_n++] = g_d236_last_vtx_raw; - fprintf(stderr, - "D236BT rawvtx=0x%08x a=(%u,%u,%u) invw1=%.4f\n", g_d236_last_vtx_raw, - v1->color.a, v2->color.a, v3->color.a, - (v1->w != 0.f) ? 1.f / v1->w : 0.f); - port_d236bt_dump("rsp"); - } - } -#endif - - static int s_d236alpha = -1; - if (s_d236alpha < 0) s_d236alpha = getenv("GE_D236ALPHA") != NULL; - if (s_d236alpha && rdp.other_mode_l == 0x0c184b50u) { - static uint32_t d236a_hits = 0; - static uint64_t d236a_last_combine = 0xFFFFFFFFFFFFFFFFull; - if (d236a_hits < 4000) { - if (rdp.combine_mode != d236a_last_combine) { - fprintf(stderr, "D236ALPHA combine_mode=0x%016llx\n", - (unsigned long long)rdp.combine_mode); - d236a_last_combine = rdp.combine_mode; - } - fprintf(stderr, - "D236ALPHA a=(%u,%u,%u) invw=(%.4f,%.4f,%.4f) vtxseg=0x%02x\n", - v1->color.a, v2->color.a, v3->color.a, - (v1->w != 0.f) ? 1.f / v1->w : 0.f, - (v2->w != 0.f) ? 1.f / v2->w : 0.f, - (v3->w != 0.f) ? 1.f / v3->w : 0.f, - g_d236_last_vtx_seg); - d236a_hits++; - } - } - if ((rsp.geometry_mode & G_CULL_BOTH) != 0) { float dx1 = v1->x / (v1->w) - v2->x / (v2->w); float dy1 = v1->y / (v1->w) - v2->y / (v2->w); @@ -2373,25 +2142,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo bool depth_test = ((rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER || (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM) && ((rdp.other_mode_h & G_CYC_1CYCLE) == G_CYC_1CYCLE || (rdp.other_mode_h & G_CYC_2CYCLE) == G_CYC_2CYCLE); bool depth_update = (rdp.other_mode_l & Z_UPD) == Z_UPD; - /* D236 pass 12 (M-191, TEMP, diagnostic-only): both the noise "wall" - * (oml=0xc81049d8) and the discrete tree-card class (oml=0x0c184b50) are - * Z_CMP=1/Z_UPD=0 decals, and GE_D236ORDER above shows the noise class is - * ALWAYS submitted after the tree class in every sampled frame -- with - * neither writing depth, later-submitted always wins the color buffer - * regardless of which is geometrically closer. This experiment forces - * depth_update=true for the tree-card class ONLY, so it writes real - * depth; if the noise class (submitted later, same depth_compare=LEQUAL) - * now correctly fails its depth test against the tree cards' nearer z - * instead of overwriting them, that confirms draw-order+no-z-write is - * the actual visual-precedence mechanism. NOT a proposed fix (forcing - * z-write for a decal-mode class is not decomp-faithful either) -- purely - * to test the mechanism cheaply before deciding what a real fix looks - * like. Remove once D236 pass 12 concludes. */ - static int s_d236zfix = -1; - if (s_d236zfix < 0) s_d236zfix = getenv("GE_D236ZFIX") != NULL; - if (s_d236zfix && rdp.other_mode_l == 0x0c184b50u) { - depth_update = true; - } bool depth_compare = (rdp.other_mode_l & Z_CMP) == Z_CMP; bool depth_source_prim = (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM /* && gDP.primDepth.z == 1.0f */; uint16_t zmode = rdp.other_mode_l & ZMODE_DEC; @@ -3802,19 +3552,6 @@ static void gfx_run_dl(Gfx* cmd) { gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(0, 8)); break; case G_VTX: - /* D236 pass 16 (TEMP): pass 15's GE_D236RAW dump proved every - * room-background Vtx (g_BgRoomInfo[].vertices) is alpha=255 - * on load -- so the tree class's <=36/255 alpha measured at - * draw time (GE_D236ALPHA) can't be coming from that static - * table. Record which segment (top byte of the raw segmented - * address) the most recent G_VTX load came from, so the next - * triangle-time probe can report it -- distinguishes "still - * room background, something else touches it after load" from - * "not room background at all" (a different segment, e.g. a - * model/CPU-built-quad source) without guessing from source - * review alone. Remove once D236 pass 16 concludes. */ - g_d236_last_vtx_seg = (uint8_t)(cmd->words.w1 >> 24); - g_d236_last_vtx_raw = cmd->words.w1; gfx_sp_vertex(C0(0, 16) / sizeof(Vtx), C0(16, 4), (const Vtx*)seg_addr(cmd->words.w1)); d75d_note_vtx(videoGetFrameCount(), C0(0, 16) / sizeof(Vtx), C0(16, 4)); break; diff --git a/src/game/bg.c b/src/game/bg.c index 3476f08d..886638b5 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -2415,48 +2415,6 @@ s32 bgLoadRoomVtxData(s32 roomnum, u8 *dst, s32 len) #ifdef PORT /* D85: byte-swap the raw N64 Vtx table (16-byte struct, no widening). */ bgSwapRoomVtx((Vtx *)dst, result); - - /* D236 pass 16 (TEMP): pass 15's live GE_D236ALPHA capture found the - * Surface1 tree-card render class's vertex alpha capped at <=36/255 - * (<=14% opacity) across a full far->close walk to the tree line, and - * confirmed (via the combine_mode decode) that this vertex alpha - * directly multiplies the texture's own alpha in the blend equation -- - * so a capped-low vertex alpha caps every tree pixel's final opacity - * outright. bgSwapRoomVtx (just above) explicitly leaves colour bytes - * untouched, so whatever is in cn[] here is exactly what bgDecompress - * produced -- this is the earliest point after decompression the raw - * per-room vertex colour data can be inspected, independent of which - * camera path a live player happens to walk. Unlike GE_D236ALPHA (which - * only sees whatever triangles are actually drawn from wherever the - * player is standing), this dumps a histogram of EVERY vertex's alpha - * byte (cn[3]) for the WHOLE room's table the moment it loads -- - * settling whether the low ceiling pass 15 measured is a sampling - * artifact (the walked path just never reached a vertex with a high - * baked alpha) or a genuine property of this room's authored data (no - * vertex in the whole table goes above the low ceiling, regardless of - * where the camera is). Zero cost unset. Remove once D236 pass 16 - * concludes. */ - if (getenv("GE_D236RAW")) { - s32 vtxCount = result / (s32)sizeof(Vtx); - s32 vi; - u32 buckets[5] = {0, 0, 0, 0, 0}; /* 0 / 1-36 / 37-100 / 101-200 / 201-255 */ - u8 amin = 255, amax = 0; - Vtx *vtxArr = (Vtx *)dst; - for (vi = 0; vi < vtxCount; vi++) { - u8 a = vtxArr[vi].v.cn[3]; - if (a < amin) amin = a; - if (a > amax) amax = a; - if (a == 0) buckets[0]++; - else if (a <= 36) buckets[1]++; - else if (a <= 100) buckets[2]++; - else if (a <= 200) buckets[3]++; - else buckets[4]++; - } - osSyncPrintf( - "D236RAW room=%d n=%d amin=%u amax=%u buckets[0,1-36,37-100,101-200,201-255]=%u,%u,%u,%u,%u\n", - (int)roomnum, (int)vtxCount, amin, amax, - buckets[0], buckets[1], buckets[2], buckets[3], buckets[4]); - } #endif room->vertices = (Vtx *)dst; diff --git a/src/game/chr.c b/src/game/chr.c index 855085ee..f0c6f819 100644 --- a/src/game/chr.c +++ b/src/game/chr.c @@ -1266,37 +1266,8 @@ s32 get_numguards(void) } -/* D236 pass 17b (TEMP): env-gated backtrace at the vertex allocator -- - * every dynamic-quad builder in model.c (dotube/doshadow/dorottex/ - * dogfnegx) funnels through here, so a stack capture on this call names - * the actual writer of a raw-pointer G_VTX batch. Correlate the printed - * physical address with the RSP-side GE_D236BT rawvtx captures. Port-side - * dumper: port/fast3d/gfx_pc.cpp (port_d236bt_dump). Zero cost unset. - * Remove once D236 pass 17 concludes. */ void get_ptr_allocated_block_for_vertices(int param_1) { -#ifdef PORT - static int s_d236bt = -1; - if (s_d236bt < 0) s_d236bt = getenv("GE_D236BT") != NULL; - if (s_d236bt) { - extern void port_d236bt_dump(const char* tag); - static int d236bt_allocs = 0; - if (d236bt_allocs < 8) { - d236bt_allocs++; - Vtx* p = (Vtx*)dynAllocate(param_1 << 4); - fprintf(stderr, "D236BT alloc n=%d bytes=0x%x phys=0x%08x\n", - param_1, param_1 << 4, (unsigned)osVirtualToPhysical(p)); - port_d236bt_dump("alloc"); - /* CRITICAL: callers do `vtx = (Vtx*)vtxallocator(n)` on this - * void function and read RAX (works on the unprobed path only - * because nothing clobbers it between dynAllocate and ret). - * Pin p in RAX so the probe's fprintf/unwind calls don't - * hand the caller garbage. */ - __asm__ volatile("" : "+a" (p)); - return; - } - } -#endif dynAllocate(param_1 << 4); } diff --git a/src/game/model.c b/src/game/model.c index 65a2c772..b34f726d 100644 --- a/src/game/model.c +++ b/src/game/model.c @@ -5470,43 +5470,6 @@ void doshadow(ModelRenderData *renderdata, Model *model, ModelNode *node) } #endif -#ifdef PORT - /* D236 pass 17c (TEMP): env-gated runtime dump of the live ShadowRecord + - * tconfig, to settle which fields the PC loader actually populated (the - * d43_emit.py op-13 emit and modelPromoteNodeOffsetsToPointers disagree - * on paper; this shows ground truth). Zero cost unset. Remove once D236 - * pass 17 concludes. */ - { - static int s_d236bt = -1; - if (s_d236bt < 0) s_d236bt = getenv("GE_D236BT") != NULL; - if (s_d236bt) { - static int d236sh_n = 0; - if (d236sh_n < 6) { - d236sh_n++; - if (d236sh_n == 1) { - FILE *f = fopen("d236sh.bin", "wb"); - if (f) { - fwrite(shadow, 1, 0x24, f); /* live ShadowRecord */ - fwrite(&node->Opcode, 1, 8, f); /* node opcode+pad */ - fwrite(node->Data, 1, 0x24, f); /* record via Data ptr */ - fwrite(shadow->BaseAddr, 1, 0x60, f); /* file header */ - fclose(f); - } - } - sImageTableEntry *tc = (sImageTableEntry *)shadow->image; - fprintf(stderr, - "D236SH node=%p img=%p hdr=%p base=%p height=%.1f size=(%.1f,%.1f) a=%u\n" - " tc: idx=0x%08x %ux%u lvl=%u fmt=%u depth=%u fs=%u ft=%u\n", - (void*)node, (void*)shadow->image, (void*)shadow->HeaderNode, - (void*)shadow->BaseAddr, height, sizex, sizey, - (unsigned)vtxtemplate.v.cn[3], - (unsigned)tc->index, tc->width, tc->height, tc->level, - tc->format, tc->depth, tc->flagsS, tc->flagsT); - } - } - } -#endif - vtx = (Vtx *) vtxallocator(4); vtx[0] = vtxtemplate;