tools: capture targets, and a Z-aware draw-order decoder
`ui_draw_capture.sh` grows three knobs the second iteration needed: * ARM=early presses F10 before the title exists, so a long window contains the frames in which a screen is BUILT (it turns out none are — the title screen submits the same 11 draws every frame and never rebuilds); * TARGET=menu taps A once on the title and arms on the main menu, skipping attract movies on the way — it does not get there, but the blocker it hits is documented rather than worked around; * EXTRA_FLAGS passes emulator cvars through (--create_profile_if_none, --mem_watch=false, --log_level). `ui_draw_order.py` follows the capture's new vertex format (x, y, z) and reports the Z it now has.
This commit is contained in:
@@ -29,7 +29,7 @@ wide(){ [ "$(identify -format '%w' "$1" 2>/dev/null || echo 0)" -gt 1000 ]; }
|
|||||||
xsetroot -solid black 2>/dev/null || true
|
xsetroot -solid black 2>/dev/null || true
|
||||||
# ATTACH=1 watches an emulator that is already up instead of launching one.
|
# ATTACH=1 watches an emulator that is already up instead of launching one.
|
||||||
if [ "${ATTACH:-0}" != "1" ]; then
|
if [ "${ATTACH:-0}" != "1" ]; then
|
||||||
( cd "$OUT" && nohup run-canary --log_ui_draws=true --ui_draw_capture_frames="${FRAMES:-3}" --ui_draw_capture_max="${MAXDRAWS:-20000}" >"$OUT/canary.stdout" 2>"$OUT/canary.stderr" & )
|
( cd "$OUT" && nohup run-canary --log_ui_draws=true --ui_draw_capture_frames="${FRAMES:-3}" --ui_draw_capture_max="${MAXDRAWS:-20000}" ${EXTRA_FLAGS:-} >"$OUT/canary.stdout" 2>"$OUT/canary.stderr" & )
|
||||||
# Grace period before the liveness check: run-canary is a shell that execs the
|
# Grace period before the liveness check: run-canary is a shell that execs the
|
||||||
# binary, and polling `ps -C xenia_canary` in the first moments reports GONE
|
# binary, and polling `ps -C xenia_canary` in the first moments reports GONE
|
||||||
# for a process that is merely not exec'd yet.
|
# for a process that is merely not exec'd yet.
|
||||||
@@ -66,6 +66,33 @@ while [ $SECONDS -lt $deadline ]; do
|
|||||||
d=$(compare -metric RMSE /tmp/u1.png /tmp/u2.png null: 2>&1 | sed 's/ .*//' | cut -d. -f1); d=${d:-0}
|
d=$(compare -metric RMSE /tmp/u1.png /tmp/u2.png null: 2>&1 | sed 's/ .*//' | cut -d. -f1); d=${d:-0}
|
||||||
s=$(python3 "$SD/screen_id.py" /tmp/u2.png | awk '{print $1}')
|
s=$(python3 "$SD/screen_id.py" /tmp/u2.png | awk '{print $1}')
|
||||||
echo "t=${SECONDS}s screen=$s rmse=$d"
|
echo "t=${SECONDS}s screen=$s rmse=$d"
|
||||||
|
# TARGET=menu walks one step further: tap A ONCE on the title, then arm on the
|
||||||
|
# main menu. One tap, and only from a full-width grab — the run that tapped
|
||||||
|
# repeatedly (off a 10-pixel sliver it had classified) crashed the guest in the
|
||||||
|
# save-data probe behind that button.
|
||||||
|
if [ "${TARGET:-title}" = "menu" ]; then
|
||||||
|
if [ "$s" = "title" ] && [ "${tapped:-0}" = "0" ]; then
|
||||||
|
echo "TITLE at ${SECONDS}s -> one A"; python3 "$SD/pad.py" tap A 0.25; tapped=1
|
||||||
|
elif [ "$s" = "menu" ]; then
|
||||||
|
cp /tmp/u2.png "$OUT/menu-before-f10.png"
|
||||||
|
xdotool windowactivate "$win" 2>/dev/null
|
||||||
|
xdotool key --window "$win" F10
|
||||||
|
xdotool key F10
|
||||||
|
sleep 3
|
||||||
|
screenshot "$OUT/menu-after-f10.png" >/dev/null 2>&1
|
||||||
|
if ls "$OUT"/xenia_re_ui_draws_*.log >/dev/null 2>&1; then
|
||||||
|
echo "MENU CAPTURED at ${SECONDS}s"; break
|
||||||
|
fi
|
||||||
|
echo "F10 pressed on the menu; no log yet"
|
||||||
|
elif [ "$d" -gt 1500 ]; then
|
||||||
|
# Still in the attract loop. Without this the menu target waits forever:
|
||||||
|
# the attract movie returns to the title and away again, and a run that
|
||||||
|
# only ever watches never gets there.
|
||||||
|
echo "movie (rmse $d) -> skip A"; python3 "$SD/pad.py" tap A 0.25; sleep 3
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$s" = "title" ] && [ "${ARM:-title}" = "early" ]; then
|
if [ "$s" = "title" ] && [ "${ARM:-title}" = "early" ]; then
|
||||||
cp /tmp/u2.png "$OUT/title-reached.png"
|
cp /tmp/u2.png "$OUT/title-reached.png"
|
||||||
echo "TITLE REACHED at ${SECONDS}s (capture was armed early)"
|
echo "TITLE REACHED at ${SECONDS}s (capture was armed early)"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import glob
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
W, H = 1280, 720
|
W, H = 1280, 720
|
||||||
VERT = re.compile(r"\[([0-9A-F]{8}),([0-9A-F]{8})=(-?\d+\.\d+),(-?\d+\.\d+)\]")
|
VERT = re.compile(r"\[(-?\d+\.\d+),(-?\d+\.\d+),z=(-?\d+\.\d+)\]")
|
||||||
|
|
||||||
|
|
||||||
def sprite_index(texdir):
|
def sprite_index(texdir):
|
||||||
@@ -78,7 +78,7 @@ def main():
|
|||||||
continue
|
continue
|
||||||
if "vb=0x" in line and pending:
|
if "vb=0x" in line and pending:
|
||||||
if want is None or frame == want or frame is None:
|
if want is None or frame == want or frame is None:
|
||||||
verts = [(float(a), float(b)) for _, _, a, b in VERT.findall(line)]
|
verts = [(float(a), float(b)) for a, b, _z in VERT.findall(line)]
|
||||||
if verts:
|
if verts:
|
||||||
# Two conventions in one log: the UI sprite shader emits NDC,
|
# Two conventions in one log: the UI sprite shader emits NDC,
|
||||||
# the full-screen pass emits pixels already (-0.5 .. 1279.5).
|
# the full-screen pass emits pixels already (-0.5 .. 1279.5).
|
||||||
|
|||||||
Reference in New Issue
Block a user