mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
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 <windows.h> 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).
This commit is contained in:
1 parent
425237f93f
commit
0503d33564
6 files changed
+10
-381
No files matched your search
@@ -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) |
|
||||
|
||||
@@ -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…
|
||||
|
||||
|
||||
+2
-265
@@ -4,10 +4,6 @@
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h> /* D236 pass 17 GE_D236BT backtrace probe */
|
||||
#endif
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user