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>
87 lines
3.1 KiB
Python
Executable File
87 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Rank one-triangle runtime-scheduler epochs by 640x480 pixel coverage.
|
|
|
|
Usage: rank_sched_triangle_coverage.py TAG [--top N]
|
|
|
|
The generated feeder format stores an eight-word header followed by three
|
|
{RGBAQ, ST, XYZ2} vertex triplets. This is a capacity preflight: it uses the
|
|
same center-sample inside test as the fixture reference and reports epochs
|
|
whose unthrottled fragment burst may exceed the production request FIFO.
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
|
|
DATA = os.path.join(ROOT, "sim", "data", "top_psmct32_raster_demo")
|
|
|
|
|
|
def edge(ax, ay, bx, by, px, py):
|
|
return (px - ax) * (by - ay) - (py - ay) * (bx - ax)
|
|
|
|
|
|
def coverage(vertices, width=640, height=480):
|
|
(x0, y0), (x1, y1), (x2, y2) = vertices
|
|
area = edge(x0, y0, x1, y1, x2, y2)
|
|
if not area:
|
|
return 0
|
|
inv = 1.0 / area
|
|
minx = max(0, int(min(x0, x1, x2)))
|
|
maxx = min(width - 1, int(max(x0, x1, x2)) + 1)
|
|
miny = max(0, int(min(y0, y1, y2)))
|
|
maxy = min(height - 1, int(max(y0, y1, y2)) + 1)
|
|
count = 0
|
|
for py in range(miny, maxy + 1):
|
|
cy = py + 0.5
|
|
for px in range(minx, maxx + 1):
|
|
cx = px + 0.5
|
|
w0 = edge(x1, y1, x2, y2, cx, cy) * inv
|
|
w1 = edge(x2, y2, x0, y0, cx, cy) * inv
|
|
w2 = 1.0 - w0 - w1
|
|
if w0 >= -0.001 and w1 >= -0.001 and w2 >= -0.001:
|
|
count += 1
|
|
return count
|
|
|
|
|
|
def main(argv):
|
|
if len(argv) < 2:
|
|
print(__doc__.strip())
|
|
return 2
|
|
tag = argv[1]
|
|
top = int(argv[argv.index("--top") + 1]) if "--top" in argv else 12
|
|
rows = []
|
|
table = os.path.join(DATA, f"sh3_{tag}_epochs.txt")
|
|
with open(table) as source:
|
|
for line in source:
|
|
fields = line.split()
|
|
if not fields or not fields[0].isdigit():
|
|
continue
|
|
epoch, list_name, ntris = int(fields[0]), fields[8], int(fields[10])
|
|
words = []
|
|
with open(os.path.join(DATA, list_name)) as feeder:
|
|
for text in feeder:
|
|
text = text.strip()
|
|
if text and not text.startswith("//"):
|
|
words.append(int(text, 16))
|
|
total = 0
|
|
peak = 0
|
|
peak_vertices = None
|
|
for ti in range(ntris):
|
|
base = 8 + ti * 9
|
|
xyz = [words[base + 2], words[base + 5], words[base + 8]]
|
|
vertices = [((word >> 4) & 0xFFF, (word >> 20) & 0xFFF) for word in xyz]
|
|
count = coverage(vertices)
|
|
total += count
|
|
if count > peak:
|
|
peak = count
|
|
peak_vertices = vertices
|
|
rows.append((total, epoch, ntris, peak, peak_vertices))
|
|
rows.sort(reverse=True)
|
|
print(f"[coverage] tag={tag} epochs={len(rows)}")
|
|
for count, epoch, ntris, peak, vertices in rows[:top]:
|
|
print(f"[coverage] epoch={epoch:4d} pixels={count:6d} tris={ntris:3d} peak_tri={peak:6d} vertices={vertices}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main(sys.argv))
|