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:
2026-07-20 19:56:46 -04:00
parent ec82764bef
commit ba74bbd5aa
476 changed files with 696247 additions and 130119 deletions
+25
View File
@@ -41,6 +41,31 @@ def build_localmem_to(dump, draw_idx):
replayed.append(u)
return mem, replayed, uploads, events, vram
def iter_localmem_at(dump, draw_idxs, collected=None):
"""Yield one mutable LocalMem at each ascending draw index in one replay.
Callers must consume/copy the texture and CLUT bytes before advancing the
iterator. This is equivalent to repeated build_localmem_to() calls but
parses the dump once and applies each upload once, which makes full-frame
fixture generation practical.
"""
targets=list(draw_idxs)
if targets != sorted(targets) or len(targets) != len(set(targets)):
raise ValueError("draw_idxs must be unique and ascending")
d, h, events, uploads, runs, vram = collected if collected is not None else R.collect(dump,0)
if vram is None:
return
mem=LM.LocalMem(vram); up=0
for draw_idx in targets:
while up < len(uploads) and uploads[up]["idx"] < draw_idx:
u=uploads[up]; up+=1
if u["dpsm"] != 0x00:
continue
off,end=u["blob_range"]; blob=d[off:end]
words=[int.from_bytes(blob[i:i+4],"little") for i in range(0,len(blob)//4*4,4)]
mem.write_image_ct32(u["dbp"],u["dbw"],u["dx"],u["dy"],u["w"],u["h"],words)
yield draw_idx,mem
def read_clut32(mem, cbp, order="grid"):
"""Read a 256-entry PSMCT32 CLUT from the modelled VRAM. 'grid' = read as a 16x16 CT32 surface based at
cbp (dbw=1) — the layout a CSM1 8-bit palette occupies; 'linear' = raw contiguous i*4 from cbp*256.