Files
xenia-rs/HANDOFF-intro-video-done.md
MechaCat02 cc9ebbb5e7 [iterate-4A] docs: handoff for intro-video-done milestone + speed frontier
HANDOFF-intro-video-done.md: what to push/copy, the 6 branch commits, build/run,
root-cause summary, and the profiled emulator-speed frontier with ranked levers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 07:45:11 +02:00

5.9 KiB
Raw Blame History

Handoff — Intro video SOLVED (iterate-4A/apu-xma-stage1, tag intro-video-done)

The original frontier — why dat/movie/ADV.wmv never played vs Xenia Canary — is solved. The intro renders authentically: white SQUARE ENIX logo + cyan glow + red diamonds on a near-black background, correct color / geometry / luminance, playing reliably. This doc is the handoff for that state and the newly-opened emulator-speed frontier.

Method (unchanged): first-divergence vs canary · fix causes not symptoms · NO masking · measure the oracle, never infer. Full setup for this branch is in HANDOFF-iterate-4A-milestone2.md (FFmpeg dev libs, DuckDB tooling, etc.) — read that first on a fresh machine.


0. What to push / copy for handoff

Git (the only repo): xenia-rs/. Branch iterate-4A/apu-xma-stage1, 6 commits ahead of origin.

cd xenia-rs
git push origin iterate-4A/apu-xma-stage1      # the 6 commits below
git push origin intro-video-done               # the annotated milestone tag (-> 5573ac1)

Not in git (machine-local — copy manually for a full-context handoff):

  • ../CLAUDE.md — project working instructions (project root is NOT a git repo).
  • ~/.claude/projects/-home-fabi-RE---Project-Sylpheed/memory/ — the auto-memory (MEMORY.md index + topic files). This is where the detailed step-by-step history lives.
  • Large local artifacts (NOT pushed): the real ISO (sylpheed.iso symlink target), sylpheed.db (DuckDB static-analysis DB, ~1h35m to regenerate — see CLAUDE.md), canary build.

1. Commits on this branch (ahead of origin)

Commit What
645feb8 ROOT #1 decode-timeout clock (IPM 10k→1M), #1b feeder starvation (incumbent-pick), #2 k_8 texture decoder
4344152 re-baseline boot golden 50M→200M after the clock fix
3559c8f ROOT #3 host render path — multi-texture YUV, tfetch dest-swizzle, PS const-bank +256
deb9292 RectangleList quad completion (fix diagonal seam)
5573ac1 MULSC/ADDSC/SUBSC scalar-const operand addressing (fix squared-luma) — tag intro-video-done
2c883e9 diagnostics snapshot: XENIA_PROFILE profiler + probe/tooling (this handoff)

Working tree is clean — all diagnostics/tooling are now committed in 2c883e9.


2. Build & run (see CLAUDE.md for the authoritative version)

cd xenia-rs
export CARGO_BUILD_JOBS=4 && cargo build --release          # ~8s incremental
# Headless oracle run (threaded GPU, single-thread CPU lockstep):
RUST_LOG=warn ./target/release/xenia-rs exec sylpheed.iso -n 3000000000
# Watch the movie (windowed): add --ui ; the first on-screen frame is at ~81s WALL
# (mostly boot). Give it >=150s. Boot is DETERMINISTIC; only wall speed varies.

Movie oracles: sylph-run.sh [runs] [n] [timeout] (default 180s). Static analysis: zq.py over sylpheed.db (DECIMAL bounds, never 0x). Both are committed at repo root now.


3. Root-cause summary (the fixes)

  • #1 clock deadline — movie handler sub_821B4968 has a 2000 ms decode-ready timeout; INSTRUCTIONS_PER_MS 10k ran ~320× too fast so a legit 720p decode looked timed-out → abort. Fixed to 1_000_000 (state.rs; XENIA_INSTR_PER_MS overrides).
  • #1b feeder starvation — co-located feeder tid24 lost the equal-priority rotation; pick_runnable now has an incumbent-preference tiebreak (scheduler.rs; XENIA_INCUMBENT_PICK).
  • #2 k_8 decoder — the movie uploads YUV planes as linear k_8; added decode_k8.
  • #3 host render path — multi-texture (8 YUV slots), tfetch 12-bit dest-swizzle, PS constant bank +256 (Xenos splits VS 0..255 / PS 256..511), RectangleList quad synthesis (v3=v0+v2v1), and MULSC operand addressing (src3, not src_a/src_b). Details: memory topic file STEPs 88→97.

4. Open frontier — emulator SPEED (profiled, not yet worked)

Playback is slow (~1419 fps). First quantified profile (XENIA_PROFILE=1, headless):

  • Effective ~35 MIPS overall (3 B guest instr / 86 s clean).
  • Interpreter body ~40% @ ~95102 MIPS; kernel HLE ~4%; block-cache lookup ~56%; texture decode 0.3% (cache works — not a bottleneck); present ~0%; no default IPS throttle.
  • The rest is per-block dispatch + scheduler plumbing — ~13 instr/block over ~229 M blocks, each paying fixed prologue/epilogue/lookup/borrow costs. Overhead-bound, not interpreter-body bound. (Note: default run is single-thread lockstep run_superblock, confirming the "serialized single-core" architecture; the console's 6 HW threads are time-sliced onto one host thread. --parallel exists but is not validated for the movie.)

Ranked levers:

  1. Coarsen the execution unit — longer superblock chains (raise superblock_budget). Cheap, reversible, targets the dominant overhead. ⚠️ chaining is also the scheduling lever (can starve the movie subsystem — validate against the oracles). Start here.
  2. JIT / block-recompiler — collapses both the interpreter body and per-block dispatch; the real ceiling (~510×), but a multi-week subsystem.
  3. True multi-core (guest threads on separate host threads) — huge for a 6-thread workload but riskiest: would invalidate the IPM=1M + incumbent-pick timing fixes that made the video work.

Caveat for the next session: precise remainder attribution needs a sampling profiler (perf_event_paranoid=4 blocks perf without sudo here; gdb ptrace_scope=1 blocks non-descendant attach). The XENIA_PROFILE coarse timers are the current best tool and are now gated zero-cost when off.


5. XENIA_PROFILE quick reference

XENIA_PROFILE=1 <run> → periodic snapshots (every 500 M guest instr, or every 500 presents) + a clean-exit report on stderr. Buckets: interp step_block, kernel HLE call_export, block decode/cache lookup_or_build, texture decode, host draw, present, and the unaccounted remainder. Zero-cost when unset (cached is_on() gate). Source: crates/xenia-gpu/src/prof.rs.