Files
retroDE_ps2/tools/verify_persp_z.py
thejayman77 ba74bbd5aa Snapshot: fog implementation + fidelity tooling baseline (pre bilinear-clamp fix)
Per-vertex GS fog end-to-end (gs_stub emit incl. persp_emit5, gs_prim_list_feeder
XYZ2->XYZF2 on PRIM.FGE, gs_make_sh3_scheduler_fixture.py F/FGE packing), new fog
TBs, fidelity attribution tooling. Functional baseline before removing the dead
bilinear lerp8 clamps (Codex: 161-node comb loop -> -0.042ns setup fail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 19:56:46 -04:00

78 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""retroDE_ps2 — Ch357: verify the RASTER's emitted per-fragment Z (persp_z5) end-to-end.
Replays the captured raster fragment stream {epoch, x, y, persp_z, color} (from tb_top_psmct32_sh3_zsched -> zsched_frags.txt)
through the SAME clamp16 persistent-Z model the RTL ROP (gs_lpddr_zc_emit) implements, and compares the resulting per-pixel
OWNER + reject-vs-paint-order to the software oracle (gs_sh3_z_oracle emits sh3_zsched_zowner.mem / _reject.mem).
If persp_z5 is the authentic screen-linear Z (right value, right pixel), the replay reproduces the oracle: covered=21692,
reject=3971 for the primary [8634,12757,145742]. A wrong Z value or a pipeline-stage misalignment shows up as a reject/owner
mismatch — so this is the decisive check on the new gs_stub RTL, independent of the (separately unit-proven) ROP.
Usage: verify_persp_z.py [frags.txt] [--tag zsched] [--fbpxw 256]
"""
import sys, os
HERE=os.path.dirname(os.path.abspath(__file__)); ROOT=os.path.normpath(os.path.join(HERE,".."))
DATA=os.path.join(ROOT,"sim","data","top_psmct32_raster_demo")
def clamp16(z): z=int(z); return 0xFFFF if z>0xFFFF else (0 if z<0 else z)
def main(argv):
a=argv[1:]
frags = a[0] if a and not a[0].startswith("--") else os.path.join(ROOT,"sim","traces","rtl","zsched_frags.txt")
tag = a[a.index("--tag")+1] if "--tag" in a else "zsched"
if not os.path.exists(frags): sys.exit(f"[perspZ] no fragment capture at {frags} (run make tb_top_psmct32_sh3_zsched)")
# load the oracle owner map: [31]cov [30]reject [27:24]z_owner(+1) [23:8]zq16 [3:0]paint_owner(+1)
owner_fn=os.path.join(DATA,f"sh3_{tag}_zowner.mem")
if not os.path.exists(owner_fn): sys.exit(f"[perspZ] no oracle map {owner_fn} (run gs_sh3_z_oracle.py --draw-list ... --emit)")
orc=[int(l,16)&0xFFFFFFFF for l in open(owner_fn) if l.strip() and not l.startswith("//")]
NPX=len(orc)
# infer FB width: prefer param, else from the oracle geometry note isn't stored — require --fbpxw or default 256
FBPXW = int(a[a.index("--fbpxw")+1]) if "--fbpxw" in a else 256
# replay the captured fragments (in emit order == dump/paint order across epochs) through persistent clamp16 GEQUAL
zbuf=[-1]*NPX; z_owner=[-1]*NPX; paint_owner=[-1]*NPX; cov=[0]*NPX
nfr=0; oob=0
for ln in open(frags):
p=ln.split()
if len(p)<5: continue
ep=int(p[0]); x=int(p[1]); y=int(p[2]); z=int(p[3])
o=y*FBPXW+x
if o<0 or o>=NPX: oob+=1; continue
nfr+=1; cov[o]=1
zq=clamp16(z)
paint_owner[o]=ep
if zq>=zbuf[o]: zbuf[o]=zq; z_owner[o]=ep # GEQUAL, persistent across epochs, ZMSK=0
# compare to the oracle
covered=sum(cov); reject=sum(1 for o in range(NPX) if cov[o] and z_owner[o]!=paint_owner[o])
# oracle covered/reject
orc_cov=sum(1 for w in orc if w>>31); orc_rej=sum(1 for w in orc if (w>>30)&1)
# per-pixel owner agreement (where both cover)
owner_mismatch=0; both=0
for o in range(NPX):
if cov[o] and (orc[o]>>31):
both+=1
orc_owner=((orc[o]>>24)&0xF)-1
if z_owner[o]!=orc_owner: owner_mismatch+=1
print(f"[perspZ] replayed {nfr} captured fragments (oob={oob}); FBPXW={FBPXW}, NPX={NPX}")
print(f"[perspZ] REPLAY : covered={covered} reject-vs-paint={reject}")
print(f"[perspZ] ORACLE : covered={orc_cov} reject={orc_rej}")
agree = 100.0*(both-owner_mismatch)/max(both,1)
rej_ratio = reject/max(orc_rej,1)
print(f"[perspZ] per-pixel z-owner agreement (both-covered {both}): {agree:.2f}% ({owner_mismatch} mismatch)")
print(f"[perspZ] reject ratio replay/oracle = {rej_ratio:.3f} (1.0 = persp_z5 authentic; ~0 or >>1 = broken/misaligned)")
# tolerate RTL-vs-float edge/coverage + fixed-point-Z noise; catch a GROSS persp_z5 error (wrong stage/value).
ok = (agree >= 95.0) and (0.80 <= rej_ratio <= 1.20)
if ok:
print(f"[perspZ] PASS — the raster's persp_z5 reproduces the clamp16 oracle owner/reject within edge tolerance. "
f"persp_z5 is the authentic screen-linear Z, correctly aligned to the emit.")
return 0
print(f"[perspZ] FAIL — persp_z5 diverges from the oracle (wrong Z value or pipeline-stage misalignment). Numbers above.")
return 1
if __name__=="__main__":
raise SystemExit(main(sys.argv))