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>
This commit is contained in:
@@ -0,0 +1,522 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Render the SH3 ZSCHED fixture with the RTL's fixed-point perspective path.
|
||||
|
||||
The existing dump-derived reference is intentionally float-ish: it uses clipped
|
||||
float vertices and computes S/Q at a reference sample point. This tool answers a
|
||||
different question: if we mirror the RTL's rounded XYZ2 vertices, Q16.16
|
||||
gradient setup, top-left edge rule, gs_persp_uv reciprocal, and GEQUAL Z RMW,
|
||||
does the framebuffer line up with the board/zint dump?
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
|
||||
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")
|
||||
sys.path.insert(0, HERE)
|
||||
|
||||
import gs_make_sh3_multidraw_fixture as MD
|
||||
|
||||
FBW = 256
|
||||
FBH = 210
|
||||
TW = 512
|
||||
TH = 512
|
||||
PERSP_FRAC = 12
|
||||
PSCALE = 4096
|
||||
S24_MAX = (1 << 23) - 1
|
||||
|
||||
|
||||
def load_mem(path):
|
||||
out = []
|
||||
with open(path) as f:
|
||||
for ln in f:
|
||||
s = ln.strip()
|
||||
if s and not s.startswith("//"):
|
||||
out.append(int(s, 16) & 0xFFFFFFFF)
|
||||
return out
|
||||
|
||||
|
||||
def load_mem64(path):
|
||||
out = []
|
||||
with open(path) as f:
|
||||
for ln in f:
|
||||
s = ln.strip()
|
||||
if s and not s.startswith("//"):
|
||||
out.append(int(s, 16) & 0xFFFFFFFFFFFFFFFF)
|
||||
return out
|
||||
|
||||
|
||||
def load_epochs(tag="zsched"):
|
||||
out = []
|
||||
with open(os.path.join(DATA, f"sh3_{tag}_epochs.txt")) as f:
|
||||
for ln in f:
|
||||
s = ln.strip()
|
||||
if s and not s.startswith("#") and not s.startswith("META"):
|
||||
out.append(int(s.split()[1]))
|
||||
return out
|
||||
|
||||
|
||||
def find_dump():
|
||||
c = glob.glob(os.path.join(ROOT, "captures", "gs", "silenthill3", "*224139*.gs.zst"))
|
||||
if not c:
|
||||
raise SystemExit("[persp] no SH3 224139 dump found")
|
||||
return c[0]
|
||||
|
||||
|
||||
def clip_rect_z(tri, w, h):
|
||||
def lerp(a, b, t):
|
||||
return {k: (a[k] + t * (b[k] - a[k])) for k in ("x", "y", "z", "s", "t", "q")}
|
||||
|
||||
def clip(poly, inside, cross):
|
||||
out = []
|
||||
for i, a in enumerate(poly):
|
||||
b = poly[(i + 1) % len(poly)]
|
||||
ina, inb = inside(a), inside(b)
|
||||
if ina:
|
||||
out.append(a)
|
||||
if ina != inb:
|
||||
out.append(cross(a, b))
|
||||
return out
|
||||
|
||||
poly = [dict(x=v["x"], y=v["y"], z=v["z"], s=v["s"], t=v["t"], q=v["q"]) for v in tri]
|
||||
poly = clip(poly, lambda p: p["x"] >= 0.0, lambda a, b: lerp(a, b, (0.0 - a["x"]) / (b["x"] - a["x"])))
|
||||
if not poly:
|
||||
return []
|
||||
poly = clip(poly, lambda p: p["x"] <= w, lambda a, b: lerp(a, b, (w - a["x"]) / (b["x"] - a["x"])))
|
||||
if not poly:
|
||||
return []
|
||||
poly = clip(poly, lambda p: p["y"] >= 0.0, lambda a, b: lerp(a, b, (0.0 - a["y"]) / (b["y"] - a["y"])))
|
||||
if not poly:
|
||||
return []
|
||||
poly = clip(poly, lambda p: p["y"] <= h, lambda a, b: lerp(a, b, (h - a["y"]) / (b["y"] - a["y"])))
|
||||
if len(poly) < 3:
|
||||
return []
|
||||
return [(poly[0], poly[i], poly[i + 1]) for i in range(1, len(poly) - 1)]
|
||||
|
||||
|
||||
def pack_vertex(v):
|
||||
s = round(v["s"] * TW * (1 << PERSP_FRAC) * PSCALE)
|
||||
t = round(v["t"] * TH * (1 << PERSP_FRAC) * PSCALE)
|
||||
q = round(v["q"] * (1 << PERSP_FRAC) * PSCALE)
|
||||
if abs(s) > S24_MAX or abs(t) > S24_MAX:
|
||||
raise SystemExit(f"[persp] ST overflow s={s} t={t}")
|
||||
if q < 0 or q > 0xFFFFFF:
|
||||
raise SystemExit(f"[persp] Q out of RTL 24-bit range q={q}")
|
||||
return {
|
||||
"x": max(0, min(FBW - 1, int(round(v["x"])))),
|
||||
"y": max(0, min(FBH - 1, int(round(v["y"])))),
|
||||
"z": max(0, min(0xFFFFFF, int(round(v["z"])))),
|
||||
"s": s & 0xFFFFFF,
|
||||
"t": t & 0xFFFFFF,
|
||||
"q": q & 0xFFFFFF,
|
||||
}
|
||||
|
||||
|
||||
def edge(px, py, ax, ay, bx, by):
|
||||
return (px - ax) * (by - ay) - (py - ay) * (bx - ax)
|
||||
|
||||
|
||||
def top_or_left(ax, ay, bx, by):
|
||||
dx = bx - ax
|
||||
dy = by - ay
|
||||
return (dy > 0) or (dy == 0 and dx > 0)
|
||||
|
||||
|
||||
def trunc_div(num, den):
|
||||
if den == 0:
|
||||
return 0
|
||||
sign = -1 if (num < 0) ^ (den < 0) else 1
|
||||
return sign * (abs(num) // abs(den))
|
||||
|
||||
|
||||
def grad_num_dadx(a0, a1, a2, x0, y0, x1, y1, x2, y2):
|
||||
return ((a1 - a0) * (y2 - y0) - (a2 - a0) * (y1 - y0)) << 16
|
||||
|
||||
|
||||
def grad_num_dady(a0, a1, a2, x0, y0, x1, y1, x2, y2):
|
||||
return ((a2 - a0) * (x1 - x0) - (a1 - a0) * (x2 - x0)) << 16
|
||||
|
||||
|
||||
def interp_wide(base, dadx, dady, x, y, x0, y0):
|
||||
step = dadx * (x - x0) + dady * (y - y0)
|
||||
return (base + (step >> 16)) & 0xFFFFFF
|
||||
|
||||
|
||||
def interp_z(base, dadx, dady, x, y, x0, y0):
|
||||
step = dadx * (x - x0) + dady * (y - y0)
|
||||
return max(0, min(0xFFFFFFFF, base + (step >> 16)))
|
||||
|
||||
|
||||
def recip_lut(q, idx_bits=11, scale=24):
|
||||
out_max = (1 << (scale + 1)) - 1
|
||||
if q <= 0:
|
||||
return out_max
|
||||
top = idx_bits - 1
|
||||
e = q.bit_length() - 1
|
||||
m = (q >> (e - top)) if e >= top else (q << (top - e))
|
||||
m &= (1 << idx_bits) - 1
|
||||
if m == 0:
|
||||
return out_max
|
||||
r = ((1 << (scale + top)) // m) >> e
|
||||
return min(r, out_max)
|
||||
|
||||
|
||||
def persp_uv(s, t, q):
|
||||
r = recip_lut(q)
|
||||
u = (s * r) >> 24
|
||||
v = (t * r) >> 24
|
||||
if u > 2047:
|
||||
u = 2047
|
||||
if v > 2047:
|
||||
v = 2047
|
||||
return u, v
|
||||
|
||||
|
||||
def texel(idx_words, pal, u, v):
|
||||
lin = v * TW + u
|
||||
if lin < 0 or lin >= len(idx_words) * 4:
|
||||
return 0
|
||||
ci = (idx_words[lin // 4] >> (8 * (lin % 4))) & 0xFF
|
||||
return pal[ci] & 0xFFFFFF
|
||||
|
||||
|
||||
def prep_tri(tri):
|
||||
verts = [pack_vertex(v) for v in tri]
|
||||
x0, y0 = verts[0]["x"], verts[0]["y"]
|
||||
x1, y1 = verts[1]["x"], verts[1]["y"]
|
||||
x2, y2 = verts[2]["x"], verts[2]["y"]
|
||||
det = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)
|
||||
if det == 0:
|
||||
return None
|
||||
if det < 0:
|
||||
verts = [verts[0], verts[2], verts[1]]
|
||||
det = -det
|
||||
v0, v1, v2 = verts
|
||||
x0, y0 = v0["x"], v0["y"]
|
||||
x1, y1 = v1["x"], v1["y"]
|
||||
x2, y2 = v2["x"], v2["y"]
|
||||
bias = [
|
||||
0 if top_or_left(x0, y0, x1, y1) else 1,
|
||||
0 if top_or_left(x1, y1, x2, y2) else 1,
|
||||
0 if top_or_left(x2, y2, x0, y0) else 1,
|
||||
]
|
||||
|
||||
def grad(attr):
|
||||
a0, a1, a2 = v0[attr], v1[attr], v2[attr]
|
||||
return (
|
||||
trunc_div(grad_num_dadx(a0, a1, a2, x0, y0, x1, y1, x2, y2), det),
|
||||
trunc_div(grad_num_dady(a0, a1, a2, x0, y0, x1, y1, x2, y2), det),
|
||||
)
|
||||
|
||||
return {
|
||||
"v": verts,
|
||||
"det": det,
|
||||
"bias": bias,
|
||||
"ds": grad("s"),
|
||||
"dt": grad("t"),
|
||||
"dq": grad("q"),
|
||||
"dz": grad("z"),
|
||||
}
|
||||
|
||||
|
||||
def prep_tri_packed(verts):
|
||||
verts = [dict(v) for v in verts]
|
||||
x0, y0 = verts[0]["x"], verts[0]["y"]
|
||||
x1, y1 = verts[1]["x"], verts[1]["y"]
|
||||
x2, y2 = verts[2]["x"], verts[2]["y"]
|
||||
det = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)
|
||||
if det == 0:
|
||||
return None
|
||||
if det < 0:
|
||||
verts = [verts[0], verts[2], verts[1]]
|
||||
det = -det
|
||||
v0, v1, v2 = verts
|
||||
x0, y0 = v0["x"], v0["y"]
|
||||
x1, y1 = v1["x"], v1["y"]
|
||||
x2, y2 = v2["x"], v2["y"]
|
||||
bias = [
|
||||
0 if top_or_left(x0, y0, x1, y1) else 1,
|
||||
0 if top_or_left(x1, y1, x2, y2) else 1,
|
||||
0 if top_or_left(x2, y2, x0, y0) else 1,
|
||||
]
|
||||
|
||||
def grad(attr):
|
||||
a0, a1, a2 = v0[attr], v1[attr], v2[attr]
|
||||
return (
|
||||
trunc_div(grad_num_dadx(a0, a1, a2, x0, y0, x1, y1, x2, y2), det),
|
||||
trunc_div(grad_num_dady(a0, a1, a2, x0, y0, x1, y1, x2, y2), det),
|
||||
)
|
||||
|
||||
return {
|
||||
"v": verts,
|
||||
"det": det,
|
||||
"bias": bias,
|
||||
"ds": grad("s"),
|
||||
"dt": grad("t"),
|
||||
"dq": grad("q"),
|
||||
"dz": grad("z"),
|
||||
}
|
||||
|
||||
|
||||
def build_tris(draw_idxs):
|
||||
got, _ = MD.load_draws(find_dump(), draw_idxs)
|
||||
eps = [got[i] for i in draw_idxs]
|
||||
ox = int(min(min(v["x"] for v in e["verts"]) for e in eps))
|
||||
oy = int(min(min(v["y"] for v in e["verts"]) for e in eps))
|
||||
out = []
|
||||
for e in eps:
|
||||
rawv = [dict(x=v["x"] - ox, y=v["y"] - oy, z=v["z"], s=v["s"], t=v["t"], q=v["q"]) for v in e["verts"]]
|
||||
raw = [(rawv[i - 2], rawv[i - 1], rawv[i]) for i in range(2, len(rawv))]
|
||||
tris = []
|
||||
for tri in raw:
|
||||
for ct in clip_rect_z(tri, FBW, FBH):
|
||||
qs = [v["q"] for v in ct]
|
||||
if all(q < 0 for q in qs):
|
||||
ct = tuple(dict(x=v["x"], y=v["y"], z=v["z"], s=-v["s"], t=-v["t"], q=-v["q"]) for v in ct)
|
||||
elif not all(q > 0 for q in qs):
|
||||
raise SystemExit(f"[persp] mixed/zero Q in idx{e['first_idx']}: {qs}")
|
||||
pt = prep_tri(ct)
|
||||
if pt is not None:
|
||||
tris.append(pt)
|
||||
out.append(tris)
|
||||
return out
|
||||
|
||||
|
||||
def build_tris_from_feeder(tag="zsched"):
|
||||
out = []
|
||||
ep = 0
|
||||
while True:
|
||||
path = os.path.join(DATA, f"feeder_sh3_{tag}{ep}.mem")
|
||||
if not os.path.exists(path):
|
||||
break
|
||||
words = load_mem64(path)
|
||||
ntris = words[0] & 0xFFFF
|
||||
tris = []
|
||||
off = 7
|
||||
for _ in range(ntris):
|
||||
verts = []
|
||||
for _v in range(3):
|
||||
rgbaq = words[off]
|
||||
st = words[off + 1]
|
||||
xyz = words[off + 2]
|
||||
verts.append({
|
||||
"x": (xyz >> 4) & 0xFFF,
|
||||
"y": (xyz >> 20) & 0xFFF,
|
||||
"z": (xyz >> 32) & 0xFFFFFFFF,
|
||||
"s": st & 0xFFFFFF,
|
||||
"t": (st >> 32) & 0xFFFFFF,
|
||||
"q": (rgbaq >> 32) & 0xFFFFFF,
|
||||
})
|
||||
off += 3
|
||||
pt = prep_tri_packed(verts)
|
||||
if pt is not None:
|
||||
tris.append(pt)
|
||||
out.append(tris)
|
||||
ep += 1
|
||||
return out
|
||||
|
||||
|
||||
def render(tag="zsched"):
|
||||
draw_idxs = load_epochs(tag)
|
||||
idx = [load_mem(os.path.join(DATA, f"sh3_{tag}{e}_idx.mem")) for e in range(len(draw_idxs))]
|
||||
pal = [load_mem(os.path.join(DATA, f"sh3_{tag}{e}_pal.mem")) for e in range(len(draw_idxs))]
|
||||
tris_by_ep = build_tris_from_feeder(tag)
|
||||
if len(tris_by_ep) != len(draw_idxs):
|
||||
tris_by_ep = build_tris(draw_idxs)
|
||||
|
||||
fb = [0] * (FBW * FBH)
|
||||
zbuf = [-1] * (FBW * FBH)
|
||||
owner = [-1] * (FBW * FBH)
|
||||
emitted = [0] * len(draw_idxs)
|
||||
accepted = [0] * len(draw_idxs)
|
||||
frags = []
|
||||
for ep, tris in enumerate(tris_by_ep):
|
||||
for tri in tris:
|
||||
v0, v1, v2 = tri["v"]
|
||||
minx = max(0, min(v0["x"], v1["x"], v2["x"]))
|
||||
maxx = min(FBW - 1, max(v0["x"], v1["x"], v2["x"]))
|
||||
miny = max(0, min(v0["y"], v1["y"], v2["y"]))
|
||||
maxy = min(FBH - 1, max(v0["y"], v1["y"], v2["y"]))
|
||||
for y in range(miny, maxy + 1):
|
||||
for x in range(minx, maxx + 1):
|
||||
e0 = edge(x, y, v0["x"], v0["y"], v1["x"], v1["y"]) + tri["bias"][0]
|
||||
e1 = edge(x, y, v1["x"], v1["y"], v2["x"], v2["y"]) + tri["bias"][1]
|
||||
e2 = edge(x, y, v2["x"], v2["y"], v0["x"], v0["y"]) + tri["bias"][2]
|
||||
if e0 > 0 or e1 > 0 or e2 > 0:
|
||||
continue
|
||||
s = interp_wide(v0["s"], tri["ds"][0], tri["ds"][1], x, y, v0["x"], v0["y"])
|
||||
t = interp_wide(v0["t"], tri["dt"][0], tri["dt"][1], x, y, v0["x"], v0["y"])
|
||||
q = interp_wide(v0["q"], tri["dq"][0], tri["dq"][1], x, y, v0["x"], v0["y"])
|
||||
z = interp_z(v0["z"], tri["dz"][0], tri["dz"][1], x, y, v0["x"], v0["y"])
|
||||
u, v = persp_uv(s, t, q)
|
||||
col = texel(idx[ep], pal[ep], u, v)
|
||||
o = y * FBW + x
|
||||
emitted[ep] += 1
|
||||
frags.append((ep, x, y, z, col, u, v, s, t, q))
|
||||
zq = min(z, 0xFFFF)
|
||||
if zq >= zbuf[o]:
|
||||
zbuf[o] = zq
|
||||
fb[o] = col
|
||||
owner[o] = ep
|
||||
accepted[ep] += 1
|
||||
return draw_idxs, tris_by_ep, fb, owner, emitted, accepted, frags
|
||||
|
||||
|
||||
def nearest_color(idx_words, pal, u, v, color, max_radius=64):
|
||||
for rad in range(max_radius + 1):
|
||||
for dv in range(-rad, rad + 1):
|
||||
for du in range(-rad, rad + 1):
|
||||
if max(abs(du), abs(dv)) != rad:
|
||||
continue
|
||||
uu = u + du
|
||||
vv = v + dv
|
||||
if 0 <= uu < TW and 0 <= vv < TH and texel(idx_words, pal, uu, vv) == color:
|
||||
return rad, du, dv
|
||||
return None
|
||||
|
||||
|
||||
def compare_trace(frags, path, idx, pal):
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
got = []
|
||||
with open(path) as f:
|
||||
for ln in f:
|
||||
p = ln.split()
|
||||
if len(p) >= 5:
|
||||
got.append((int(p[0]), int(p[1]), int(p[2]), int(p[3]), int(p[4], 16) & 0xFFFFFF))
|
||||
n = min(len(frags), len(got))
|
||||
coord_miss = color_miss = z_miss256 = 0
|
||||
near_bins = {"r1": 0, "r8": 0, "r32": 0, "r64": 0, "miss": 0}
|
||||
by_ep = {}
|
||||
examples = []
|
||||
for i in range(n):
|
||||
me = frags[i]
|
||||
hw = got[i]
|
||||
ep = hw[0]
|
||||
st = by_ep.setdefault(ep, {"n": 0, "coord": 0, "color": 0, "z256": 0})
|
||||
st["n"] += 1
|
||||
if me[:3] != hw[:3]:
|
||||
coord_miss += 1
|
||||
st["coord"] += 1
|
||||
if (me[4] & 0xFFFFFF) != hw[4]:
|
||||
color_miss += 1
|
||||
st["color"] += 1
|
||||
near = nearest_color(idx[ep], pal[ep], me[5], me[6], hw[4])
|
||||
if near is None:
|
||||
near_bins["miss"] += 1
|
||||
else:
|
||||
rad, _du, _dv = near
|
||||
if rad <= 1:
|
||||
near_bins["r1"] += 1
|
||||
if rad <= 8:
|
||||
near_bins["r8"] += 1
|
||||
if rad <= 32:
|
||||
near_bins["r32"] += 1
|
||||
if rad <= 64:
|
||||
near_bins["r64"] += 1
|
||||
if abs(me[3] - hw[3]) > 256:
|
||||
z_miss256 += 1
|
||||
st["z256"] += 1
|
||||
if len(examples) < 12 and (me[:3] != hw[:3] or (me[4] & 0xFFFFFF) != hw[4] or abs(me[3] - hw[3]) > 256):
|
||||
near = nearest_color(idx[ep], pal[ep], me[5], me[6], hw[4]) if (me[4] & 0xFFFFFF) != hw[4] else None
|
||||
examples.append((i, me, hw, near))
|
||||
print(f"[persp] trace={path} model_frags={len(frags)} trace_frags={len(got)} compared={n}")
|
||||
print(f"[persp] trace_miss coord={coord_miss} color={color_miss} z_gt256={z_miss256}")
|
||||
print(f"[persp] trace color-near model_uv: <=1 {near_bins['r1']} <=8 {near_bins['r8']} <=32 {near_bins['r32']} <=64 {near_bins['r64']} >64/notfound {near_bins['miss']}")
|
||||
for ep in sorted(by_ep):
|
||||
st = by_ep[ep]
|
||||
print(f"[persp] trace e{ep}: n={st['n']} coord={st['coord']} color={st['color']} z_gt256={st['z256']}")
|
||||
for i, me, hw, near in examples:
|
||||
ns = "near=none" if near is None else f"near r={near[0]} du={near[1]} dv={near[2]}"
|
||||
print(f"[persp] trace miss#{i}: model ep{me[0]} ({me[1]},{me[2]}) z={me[3]} uv=({me[5]},{me[6]}) col={me[4]&0xFFFFFF:06x} "
|
||||
f"trace ep{hw[0]} ({hw[1]},{hw[2]}) z={hw[3]} col={hw[4]:06x} {ns}")
|
||||
|
||||
|
||||
def compare_issue(frags, path):
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
got = []
|
||||
with open(path) as f:
|
||||
for ln in f:
|
||||
p = ln.split()
|
||||
if len(p) >= 7:
|
||||
got.append((int(p[0]), int(p[1]), int(p[2]), int(p[3]), int(p[4]), int(p[5]), int(p[6])))
|
||||
n = min(len(frags), len(got))
|
||||
by_ep = {}
|
||||
s_miss = t_miss = u_miss = v_miss = recip_miss = 0
|
||||
examples = []
|
||||
for i in range(n):
|
||||
me = frags[i]
|
||||
hw = got[i]
|
||||
ep = hw[0]
|
||||
st = by_ep.setdefault(ep, {"n": 0, "s": 0, "t": 0, "u": 0, "v": 0, "recip": 0})
|
||||
st["n"] += 1
|
||||
mr = recip_lut(me[9])
|
||||
if me[7] != hw[1]:
|
||||
s_miss += 1
|
||||
st["s"] += 1
|
||||
if me[8] != hw[2]:
|
||||
t_miss += 1
|
||||
st["t"] += 1
|
||||
if mr != hw[3]:
|
||||
recip_miss += 1
|
||||
st["recip"] += 1
|
||||
if me[5] != hw[4]:
|
||||
u_miss += 1
|
||||
st["u"] += 1
|
||||
if me[6] != hw[5]:
|
||||
v_miss += 1
|
||||
st["v"] += 1
|
||||
if len(examples) < 12 and (me[7] != hw[1] or me[8] != hw[2] or mr != hw[3] or me[5] != hw[4] or me[6] != hw[5]):
|
||||
examples.append((i, me, hw, mr))
|
||||
print(f"[persp] issue={path} model_frags={len(frags)} issue_rows={len(got)} compared={n}")
|
||||
print(f"[persp] issue_miss s={s_miss} t={t_miss} recip={recip_miss} u={u_miss} v={v_miss}")
|
||||
for ep in sorted(by_ep):
|
||||
st = by_ep[ep]
|
||||
print(f"[persp] issue e{ep}: n={st['n']} s={st['s']} t={st['t']} recip={st['recip']} u={st['u']} v={st['v']}")
|
||||
for i, me, hw, mr in examples:
|
||||
print(f"[persp] issue miss#{i}: model ep{me[0]} ({me[1]},{me[2]}) s={me[7]} t={me[8]} q={me[9]} recip={mr} uv=({me[5]},{me[6]}) "
|
||||
f"rtl ep{hw[0]} s={hw[1]} t={hw[2]} recip={hw[3]} uv=({hw[4]},{hw[5]}) valid={hw[6]}")
|
||||
|
||||
|
||||
def main(argv):
|
||||
args = argv[1:]
|
||||
fb_path = args[0] if args and not args[0].startswith("--") else os.path.join(DATA, "sh3_zsched_board_fb.mem")
|
||||
board = load_mem(fb_path)
|
||||
trace_path = args[args.index("--trace") + 1] if "--trace" in args else os.path.join(ROOT, "sim", "traces", "rtl", "zsched_frags.txt")
|
||||
draw_idxs, tris_by_ep, fb, owner, emitted, accepted, frags = render()
|
||||
if len(board) != len(fb):
|
||||
raise SystemExit(f"[persp] {fb_path}: {len(board)} words != expected {len(fb)}")
|
||||
mism = []
|
||||
cov = sum(1 for x in owner if x >= 0)
|
||||
for i, (a, b) in enumerate(zip(board, fb)):
|
||||
if (a & 0xFFFFFF) != (b & 0xFFFFFF):
|
||||
mism.append(i)
|
||||
by_owner = [0] * len(draw_idxs)
|
||||
by_miss = [0] * len(draw_idxs)
|
||||
for o in range(len(fb)):
|
||||
ep = owner[o]
|
||||
if ep >= 0:
|
||||
by_owner[ep] += 1
|
||||
miss_set = set(mism)
|
||||
for o in miss_set:
|
||||
ep = owner[o]
|
||||
if ep >= 0:
|
||||
by_miss[ep] += 1
|
||||
|
||||
print(f"[persp] fb={fb_path}")
|
||||
print(f"[persp] draw_idxs={draw_idxs} FB={FBW}x{FBH} covered={cov} mismatches={len(mism)}/{len(fb)}")
|
||||
for ep, idx in enumerate(draw_idxs):
|
||||
print(f"[persp] e{ep} idx{idx}: tris={len(tris_by_ep[ep])} emitted={emitted[ep]} accepted={accepted[ep]} final_owner={by_owner[ep]} miss={by_miss[ep]}")
|
||||
for o in mism[:12]:
|
||||
print(f"[persp] miss x={o % FBW} y={o // FBW} owner=e{owner[o]} model={fb[o] & 0xFFFFFF:06x} board={board[o] & 0xFFFFFF:06x}")
|
||||
trace_idxs = [load_mem(os.path.join(DATA, f"sh3_zsched{e}_idx.mem")) for e in range(len(draw_idxs))]
|
||||
trace_pals = [load_mem(os.path.join(DATA, f"sh3_zsched{e}_pal.mem")) for e in range(len(draw_idxs))]
|
||||
compare_trace(frags, trace_path, trace_idxs, trace_pals)
|
||||
compare_issue(frags, os.path.join(ROOT, "sim", "traces", "rtl", "zsched_issue.txt"))
|
||||
return 0 if not mism else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main(sys.argv))
|
||||
Reference in New Issue
Block a user