Put the player on a real volume, and find the write window is the frame
ROADMAP K3. src/player/packed.s (2,898 B) brings up its own display, builds
its own 193-entry DMA chain, keeps its own frame clock off V-DISP and fetches
every record itself with READ(10) off a CZ-6BS1. The rig writes no picture
byte, no palette entry and no CRTC register.
120 of 120 frames pixel-exact, every one compared, in both palette orders --
the gate had to grow to do it, because a packed frame is a LITERAL and the
codec's recursion was what made one comparison audit 120.
And the write window turns out to be the frame. A packed write requires R20
bit 11, buffer mode blanks the layer, and a DMAC-direct player holds the
window open for the whole data phase, so
dark fraction of a slot = record bytes / (DATA-PHASE rate x slot)
which is 1.0 at the container's own 582.0 KB/s: every frame delivered, on
time, pixel-exact, and none of them displayed. The rate in that expression is
the BURST rate, a third hardware number B1 has no test for. It reverses 61.5's
ranking -- a packed player that DMAs to RAM and paints with the measured 27.3%
blit is on screen 72.7% of every slot at any rate, and the two are equal only
at 2,131 KB/s = 3.7x the wire.
And a held channel costs the frame clock half its ticks without the clock
being able to tell: 487 of 1,038 V-DISP edges lost, zero late frames reported,
the player believing 12 fps while the screen ran at 6.37.
FINDINGS 64. ROADMAP K4 opened and fenced behind B2.
check.sh ALL GREEN before and after.
Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
"""The README still for the PACKED player -- ROADMAP K3, FINDINGS 64.
|
||||
|
||||
python3 tools/media/make_packed_media.py [container.dlxp]
|
||||
[--snap tmp/snap_packed_gate] [--map tmp/packed_snaps_gate.csv]
|
||||
[--src tmp/fr_singe] [--frame N] [--out docs/img/packed-player.png]
|
||||
|
||||
Blu-ray source | what the emulated 68000 actually put on screen. The right-hand
|
||||
panel is MAME's own snapshot, de-double-scanned and cropped to the picture -- not
|
||||
a re-render, not `dlxp.render`. It is the same rule the codec's still is built on
|
||||
(tools/media/make_readme_media.py) and it is the only reason the picture is worth
|
||||
printing: an encoder can be checked against its own inverse, and a screen cannot.
|
||||
|
||||
THE FRAME IS CHOSEN, NOT PICKED. --frame defaults to the one whose PSNR against
|
||||
the source is CLOSEST TO THE MEAN over the whole gated window, so the still is
|
||||
representative rather than flattering. The chosen frame and its distance from the
|
||||
mean are printed, so a reader can see it was not the best one.
|
||||
"""
|
||||
import argparse, csv, os, sys
|
||||
sys.path.insert(0, "tools/encoder")
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw
|
||||
from dlxp import DLXP
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("container", nargs="?", default="tmp/packed_singe.dlxp")
|
||||
ap.add_argument("--snap", default="tmp/snap_packed_gate")
|
||||
ap.add_argument("--map", default="tmp/packed_snaps_gate.csv")
|
||||
ap.add_argument("--src", default="tmp/fr_singe")
|
||||
ap.add_argument("--frame", type=int, default=None)
|
||||
ap.add_argument("--out", default="docs/img/packed-player.png")
|
||||
a = ap.parse_args()
|
||||
|
||||
d = DLXP(a.container)
|
||||
SNAP_W, SNAP_H = 256, 512
|
||||
with open(a.map) as fh:
|
||||
shot = {int(r["frame"]): r["snapshot"] for r in csv.DictReader(fh)}
|
||||
if not shot:
|
||||
sys.exit(f"{a.map} is empty -- run tools/bench/packed_run.sh first")
|
||||
|
||||
|
||||
def screen(fr):
|
||||
"""The 256x192 picture out of one MAME native snapshot."""
|
||||
p = f"{a.snap}/x68000/{shot[fr]}.png"
|
||||
s = np.asarray(Image.open(p).convert("RGB"))
|
||||
if s.shape[:2] != (SNAP_H, SNAP_W):
|
||||
sys.exit(f"{p}: expected {SNAP_W}x{SNAP_H}, got {s.shape[1]}x{s.shape[0]}")
|
||||
g = s[0::2] # undo the double scan
|
||||
y = (g.shape[0] - d.H) // 2 # the picture is centred
|
||||
return g[y:y + d.H]
|
||||
|
||||
|
||||
def source(fr):
|
||||
p = f"{a.src}/f{fr+1:04d}.png"
|
||||
if not os.path.exists(p):
|
||||
sys.exit(f"missing {p} -- re-extract the frames the container was built "
|
||||
f"from, or point --src at them")
|
||||
return np.asarray(Image.open(p).convert("RGB"))
|
||||
|
||||
|
||||
def psnr(x, y):
|
||||
e = ((x.astype(float) - y.astype(float)) ** 2).mean()
|
||||
return float("inf") if e == 0 else 10 * np.log10(255.0 ** 2 / e)
|
||||
|
||||
|
||||
frames = sorted(shot)
|
||||
scores = {f: psnr(source(f), screen(f)) for f in frames}
|
||||
mean = float(np.mean(list(scores.values())))
|
||||
if a.frame is None:
|
||||
pick = min(scores, key=lambda f: abs(scores[f] - mean))
|
||||
else:
|
||||
pick = a.frame
|
||||
if pick not in scores:
|
||||
sys.exit(f"frame {pick} was not sampled by that run")
|
||||
|
||||
# THE PANEL IS GATED, not just drawn. A still of the player is a claim that the
|
||||
# player drew it, and the snapshot has to still be pixel-exact against the
|
||||
# container for that claim to hold -- verify_packed.py checks all of them and
|
||||
# this checks the one being printed, so the picture cannot outlive the result.
|
||||
ref = d.render(pick)
|
||||
if not np.array_equal(screen(pick), ref):
|
||||
sys.exit(f"frame {pick} is NOT pixel-exact against {a.container}. The still "
|
||||
f"is not being written: it would be a picture of a failure with a "
|
||||
f"caption saying otherwise.")
|
||||
|
||||
Z, BAR = 2, 22
|
||||
|
||||
|
||||
def captioned(img, text):
|
||||
up = np.repeat(np.repeat(img, Z, 0), Z, 1)
|
||||
out = Image.new("RGB", (up.shape[1], up.shape[0] + BAR), (16, 16, 18))
|
||||
out.paste(Image.fromarray(up), (0, BAR))
|
||||
ImageDraw.Draw(out).text((6, 6), text, fill=(190, 190, 196))
|
||||
return out
|
||||
|
||||
|
||||
left = captioned(source(pick), "Blu-ray source, cropped 256x192")
|
||||
right = captioned(screen(pick),
|
||||
"emulated 68000, MAME's own snapshot, no decoder")
|
||||
out = Image.new("RGB", (left.width + right.width + 8, left.height), (16, 16, 18))
|
||||
out.paste(left, (0, 0))
|
||||
out.paste(right, (left.width + 8, 0))
|
||||
os.makedirs(os.path.dirname(a.out), exist_ok=True)
|
||||
out.save(a.out)
|
||||
print(f"{a.out}: frame {pick} of {d.nframes}, {scores[pick]:.2f} dB against the "
|
||||
f"24-bit source")
|
||||
print(f" chosen as the frame CLOSEST TO THE MEAN ({mean:.2f} dB over "
|
||||
f"{len(frames)} gated frames), {abs(scores[pick]-mean):.3f} dB from it -- "
|
||||
f"best in the window is {max(scores.values()):.2f}, worst "
|
||||
f"{min(scores.values()):.2f}")
|
||||
print(f" and it is pixel-exact against {a.container}, checked before writing")
|
||||
Reference in New Issue
Block a user