Files
retroDE_ps2/tools/gs_merge_scheduler_bootlets.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

85 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""Build one scheduler bootlet that preloads the distinct CLUTs required by several fixture tags.
Usage: gs_merge_scheduler_bootlets.py <output-tag> <input-tag> [<input-tag> ...]
"""
import os
import re
import sys
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, DATA)
import bake
RAM_QWORDS = 512
HEADER_QWORDS = 16
FBW = 10
FBPXW = 640
FBH = 480
def read_payload(tag):
path = os.path.join(DATA, f"payload_sh3_{tag}.mem")
with open(path) as f:
lines = f.readlines()
header = next((line for line in lines if line.startswith("//")), "")
match = re.search(r"QWC=(\d+)", header)
if not match:
raise ValueError(f"{path}: missing QWC metadata")
cbp_match = re.search(r"CBPs \[([^]]*)\]", header)
if not cbp_match:
raise ValueError(f"{path}: missing CBP metadata")
cbps = [int(x.strip()) for x in cbp_match.group(1).split(",") if x.strip()]
words = [int(line.strip(), 16) for line in lines if line.strip() and not line.startswith("//")]
if len(words) != RAM_QWORDS:
raise ValueError(f"{path}: expected {RAM_QWORDS} qwords, got {len(words)}")
qwc = int(match.group(1))
if qwc > RAM_QWORDS - HEADER_QWORDS:
raise ValueError(f"{path}: QWC {qwc} exceeds payload capacity")
return qwc, cbps, words[HEADER_QWORDS:HEADER_QWORDS + qwc]
def main(argv):
if len(argv) < 4:
print(__doc__.strip())
return 2
output_tag, input_tags = argv[1], argv[2:]
active = []
seen_cbps = set()
for tag in input_tags:
qwc, cbps, words = read_payload(tag)
for cbp in set(cbps):
if cbp in seen_cbps:
raise ValueError(f"duplicate relocated CBP {cbp}: fixture {tag} aliases an earlier input")
seen_cbps.add(cbp)
if len(words) != qwc:
raise ValueError(f"payload word count mismatch for {tag}")
active.extend(words)
if len(active) > RAM_QWORDS - HEADER_QWORDS:
raise ValueError(f"combined QWC {len(active)} exceeds {RAM_QWORDS - HEADER_QWORDS}")
payload_name = f"payload_sh3_{output_tag}.mem"
bios_name = f"bios_sh3_{output_tag}.mem"
with open(os.path.join(DATA, payload_name), "w") as f:
f.write(f"// combined scheduler CLUT preload tags={input_tags} CBPs={sorted(seen_cbps)} QWC={len(active)}. gitignored.\n")
for _ in range(HEADER_QWORDS):
f.write("00000000000000000000000000000000\n")
for word in active:
f.write(f"{word:032x}\n")
for _ in range(RAM_QWORDS - HEADER_QWORDS - len(active)):
f.write("00000000000000000000000000000000\n")
display1_hi = ((FBH - 1) << 12) | (FBPXW - 1)
bake.write_bios_mem(
bios_name,
bake.build_textured_demo_bootlet_disp(len(active), display1_hi, FBW),
f"combined scheduler CLUT preload tags={input_tags} QWC={len(active)} DISPLAY1={FBPXW}x{FBH}. gitignored.",
)
print(f"[bootlet] emitted {bios_name} + {payload_name}: QWC={len(active)} CBPs={sorted(seen_cbps)}")
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv))