ba74bbd5aa
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>
36 lines
1.5 KiB
Python
36 lines
1.5 KiB
Python
#!/usr/bin/env python3
|
|
# Convert a linear PSMCT32 framebuffer dump ($fwrite "%08x") to a PNG for visual triage.
|
|
# Word layout = PS2 PSMCT32 0xAABBGGRR (low byte R). Usage:
|
|
# gs_fb_to_png.py <fb.mem> <out.png> [width] [height] [scale]
|
|
# Defaults to the SH3 real-draw FB (256x120). No-op (exit 0) if input missing or PIL absent,
|
|
# so it can be chained after a sim without ever breaking the build.
|
|
import sys
|
|
def main():
|
|
a = sys.argv
|
|
src = a[1] if len(a) > 1 else "sim/data/top_psmct32_raster_demo/sh3_real_fb_out.mem"
|
|
dst = a[2] if len(a) > 2 else "sim/data/top_psmct32_raster_demo/sh3_real_fb_rtl.png"
|
|
W = int(a[3]) if len(a) > 3 else 256
|
|
H = int(a[4]) if len(a) > 4 else 120
|
|
SC = int(a[5]) if len(a) > 5 else 3
|
|
try:
|
|
from PIL import Image
|
|
except Exception:
|
|
print("[fb_to_png] PIL not available; skipping PNG"); return 0
|
|
try:
|
|
words = []
|
|
with open(src) as f:
|
|
for ln in f:
|
|
s = ln.strip()
|
|
if not s or s.startswith("/"): continue
|
|
words.append(int(s, 16) & 0xFFFFFFFF)
|
|
except FileNotFoundError:
|
|
print(f"[fb_to_png] {src} not found; skipping"); return 0
|
|
img = Image.new("RGB", (W, H))
|
|
for i, w in enumerate(words[:W*H]):
|
|
img.putpixel((i % W, i // W), (w & 0xFF, (w >> 8) & 0xFF, (w >> 16) & 0xFF))
|
|
img.resize((W*SC, H*SC), Image.NEAREST).save(dst)
|
|
print(f"[fb_to_png] wrote {dst} ({W}x{H} x{SC})")
|
|
return 0
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|