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>
73 lines
3.4 KiB
Python
73 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
# Ch352 diagnostic (Codex's test): replace the SH3 texture indices with a LARGE, UNMISTAKABLE
|
|
# 16x16-cell pattern using strongly-contrasting indices from the REAL SH3 CSM1 palette, and emit it
|
|
# through the EXACT same linear LPDDR texture file the uploader streams. Geometry / CLUT / feeder are
|
|
# untouched. If the cells render as clean flat colors -> the board photo is authentic high-frequency
|
|
# SH3 texture, NOT timing corruption. If the flat cells speckle -> real corruption.
|
|
#
|
|
# LOCAL/gitignored (palette is dump-derived). Backs up the real texture to *.REAL.bak first.
|
|
import sys, os
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
from gs_localmem import ct32_addr # CT32 grid de-swizzle (CSM1 palette layout)
|
|
|
|
DATA = os.path.join(os.path.dirname(__file__), "..", "sim", "data", "top_psmct32_raster_demo")
|
|
TEX = os.path.join(DATA, "sh3_real_tex_lpddr.mem")
|
|
CLUT = os.path.join(DATA, "sh3_real_clut.mem")
|
|
TW = TH = 512
|
|
CELL = 16
|
|
NCHOSEN = 8
|
|
|
|
def load_words(path):
|
|
out = []
|
|
with open(path) as f:
|
|
for ln in f:
|
|
s = ln.strip()
|
|
if not s or s.startswith("/"):
|
|
continue
|
|
out.append(int(s, 16) & 0xFFFFFFFF)
|
|
return out
|
|
|
|
# ---- 1) de-grid the CSM1 palette to index order, get each index's RGB ----
|
|
clut_words = load_words(CLUT)
|
|
clut_bytes = bytearray()
|
|
for w in clut_words:
|
|
clut_bytes += (w & 0xFFFFFFFF).to_bytes(4, "little")
|
|
pal = [0]*256
|
|
for i in range(256):
|
|
a = ct32_addr(0, 1, i & 15, i >> 4) # palette entry i sits at grid (i%16, i//16)
|
|
pal[i] = int.from_bytes(clut_bytes[a:a+4], "little") if a+4 <= len(clut_bytes) else 0
|
|
rgb = [(p & 0xFF, (p >> 8) & 0xFF, (p >> 16) & 0xFF) for p in pal] # PSMCT32 low byte = R
|
|
|
|
# ---- 2) greedy farthest-point pick of NCHOSEN maximally-contrasting indices ----
|
|
def d2(a, b): return sum((a[k]-b[k])**2 for k in range(3))
|
|
chosen = [max(range(256), key=lambda i: rgb[i][0]+rgb[i][1]+rgb[i][2])] # start brightest
|
|
while len(chosen) < NCHOSEN:
|
|
nxt = max(range(256), key=lambda i: min(d2(rgb[i], rgb[c]) for c in chosen))
|
|
chosen.append(nxt)
|
|
print("[banded] chosen indices + RGB:", [(c, rgb[c]) for c in chosen])
|
|
|
|
# ---- 3) build the 16x16-cell pattern as LINEAR raster indices (PSMT8_SWIZZLE=0) ----
|
|
idx = bytearray(TW*TH)
|
|
for y in range(TH):
|
|
cy = y // CELL
|
|
for x in range(TW):
|
|
cx = x // CELL
|
|
idx[y*TW + x] = chosen[(cx + cy) % NCHOSEN] # diagonal bands of contrasting flat cells
|
|
|
|
# ---- 4) pack 4 indices / LE word, write through the exact uploader format ----
|
|
if os.path.exists(TEX) and not os.path.exists(TEX + ".REAL.bak"):
|
|
os.rename(TEX, TEX + ".REAL.bak")
|
|
print("[banded] backed up real texture ->", os.path.basename(TEX) + ".REAL.bak")
|
|
nwords = (TW*TH)//4
|
|
with open(TEX, "w") as f:
|
|
f.write("// Ch352 DIAGNOSTIC banded 16x16-cell texture (contrasting SH3 palette indices). "
|
|
"LINEAR de-swizzled, PSMT8_SWIZZLE=0. Restore from sh3_real_tex_lpddr.mem.REAL.bak. gitignored.\n")
|
|
sm = 0
|
|
for w in range(nwords):
|
|
word = idx[4*w] | (idx[4*w+1] << 8) | (idx[4*w+2] << 16) | (idx[4*w+3] << 24)
|
|
sm = (sm + word) & 0xFFFFFFFF
|
|
f.write("%08x\n" % word)
|
|
print(f"[banded] wrote {nwords} words to {TEX} sum32=0x{sm:08x}")
|
|
print("[banded] upload as usual; on HDMI expect a perspective-warped grid of FLAT contrasting cells.")
|
|
print("[banded] CLEAN flat cells => authentic texture (not corruption). SPECKLED cells => real corruption.")
|