"""Diagnostic: is the CPU/GPU 18% divergence float32-vs-float64 in the plane eval, and does the authentic int-truncation (golden model stores int(Ax+By+C)) reconcile them? Renders frame 11's prims three ways and compares. A = float64 planes, no truncation (== current render_faithful / CPU ref) B = float64 planes, int-truncated (authentic: int(Ax+By+C) fields) C = float32 planes, int-truncated (authentic + GPU precision) If B ~= C, int-truncation removes the float32/64 sensitivity -> the fix. """ import sys, os, struct HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE); sys.path.insert(0, os.path.dirname(HERE)) sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha') import emu860, emu_main, emu860c import numpy as np from driver import boot, CpuShim from vrboard import A from texstore import build_texstore from dpl_sampler import mode_to_texflags, wrap_index, composite ANAME = {int(a): a.name for a in A} emu860.Mem.log = lambda self, *a, **k: None SRC = r'C:/VWE/TeslaRel410/emulator/render-bridge/captures/netdeath-20260708.fifodump' PROG_LO, PROG_HI = 0x08158000, 0x08170000 W, H = 832, 512 EDGE = {0x42, 0x0d, 0x2c} TARGET = 11 data = open(SRC, 'rb').read() recs = []; off = 0 while True: i = data.find(b'VPXM', off) if i < 0: break ln = struct.unpack_from('= 4 and struct.unpack_from('> 8) & 0xff) in EDGE and len(edges) < 6: edges.append((f32(rd(p+4)), f32(rd(p+8)), f32(rd(p+12)))); p += 16 if len(edges) < 3: continue zp = tzp = up = vp = None; tid = None; q = p for _ in range(70): w = rd(q); op = (w >> 8) & 0xff; ad = w & 0xff if op == 0x21 and zp is None: zp = (f32(rd(q+4)), f32(rd(q+8)), f32(rd(q+12))) if op == 0x43 and ad == 32 and tzp is None: tzp = (f32(rd(q+4)), f32(rd(q+8)), f32(rd(q+12))) if op == 0x43 and ad == 58 and up is None: up = (f32(rd(q+4)), f32(rd(q+8)), f32(rd(q+12))) if op == 0x43 and ad == 78 and vp is None: vp = (f32(rd(q+4)), f32(rd(q+8)), f32(rd(q+12))) if op == 0xf7 and ad in (141, 142) and tid is None: tid = (rd(q+4) >> 2) & 0x3f q += 4 if zp is None: continue polys.append((edges, zp, tzp, up, vp, tid)) return polys def render(polys, xx, yy, trunc): zbuf = np.full((H, W), -1e30) img = np.zeros((H, W, 3), np.uint8) for edges, zp, tzp, up, vp, tid in polys: ep = np.ones((H, W), bool); en = np.ones((H, W), bool) for Ae, Be, Ce in edges: v = Ae*xx + Be*yy + Ce; ep &= v >= 0; en &= v < 0 inside = ep | en if not inside.any(): continue z = zp[0]*xx + zp[1]*yy + zp[2] if trunc: z = np.trunc(z) inside &= z > zbuf if not inside.any(): continue if up and vp and tzp: h, (tu, tv, mode, arr) = texlist[(tid or 0) % len(texlist)] wu, wv, cm = mode_to_texflags(mode) tzv = tzp[0]*xx + tzp[1]*yy + tzp[2] uu = up[0]*xx + up[1]*yy + up[2] vv = vp[0]*xx + vp[1]*yy + vp[2] if trunc: tzv = np.trunc(tzv); uu = np.trunc(uu); vv = np.trunc(vv) tzv = np.where(np.abs(tzv) < 1.0, np.sign(tzv) + (tzv == 0), tzv) uc = (uu.astype(np.float64)/tzv*2048).astype(np.int64) vc = (vv.astype(np.float64)/tzv*2048).astype(np.int64) ui = wrap_index((uc*tu) >> 8, tu, wu); vi = wrap_index((vc*tv) >> 8, tv, wv) dm = composite(img, inside, arr[vi, ui], cm) else: img[inside] = (60, 60, 70); dm = inside zbuf[dm] = np.asarray(z, np.float64)[dm] return img frames = 0; prev = False while r.qi < len(r.queue): reason, _ = emu860c.run(500_000_000) if reason == 3: continue if reason != 0: break pc = emu860c.getstate()['pc'] h = r.hooks.get(pc) if h is None: break if pc == RECV: if prev: if frames == TARGET: polys = capture_polys() print("frame %d: %d polys" % (frames, len(polys)), flush=True) A_ = render(polys, xx64, yy64, False) B_ = render(polys, xx64, yy64, True) C_ = render(polys, xx32, yy32, True) def cmp(p, q, na, nb): d = np.abs(p.astype(int) - q.astype(int)).sum(2) print(" %s vs %s: differ>24 %.2f%% mean|d| %.2f" % (na, nb, 100*(d > 24).mean(), d.mean()), flush=True) cmp(A_, B_, "float64-raw(A)", "float64-trunc(B)") cmp(B_, C_, "float64-trunc(B)", "float32-trunc(C)") cmp(A_, C_, "float64-raw(A)", "float32-trunc(C)") break frames += 1 prev = False if r.qi < len(r.queue) and ANAME.get(r.queue[r.qi][0]) == 'draw_scene': prev = True if h(shim) == 'done': break