Files
Sylpheed/tools/run-canary-native.sh
sim 94f84b1356
All checks were successful
CI / Native — linux (pull_request) Successful in 2h16m47s
CI / WASM — Web (pull_request) Successful in 31m15s
CI / Formatting (pull_request) Successful in 1m19s
chore: hand the workspace over — the gated launchers, and the state of play
Resuming happens on the other machine, so anything that lived only in this
workspace either comes into the repo or gets named as something to carry.

**The launchers come in.** `run-canary-safe.sh` (Wine) and
`run-canary-native-safe.sh` (native) are the ONLY sanctioned way to start Canary
from the editor — they force software Vulkan and refuse to launch while a
hardware Vulkan device is visible, because Canary on the AMD GPU takes VS Code
with it. They sat in the workspace root, outside git, hardcoding one machine's
absolute paths, which is exactly why they could not be checked in. They now
derive the workspace from their own location and honour `$SYLPHEED_ISO` and
`$CANARY_BIN`, so the layout is a default rather than a requirement. Same for
`run-canary-native.sh` (interactive, hardware Vulkan — not from the IDE),
`diagnose-freeze.sh`, `live-guest-state.sh`, `heaptrack-wrap.sh` and the
`asound-null.conf` the native launcher needs beside it.

Both safe launchers were run from `tools/` before this commit: the native one
reached content in 20 s (`VERDICT: HEALTHY`, title + 25,398 XMA lines, no
faults), the Wine one ran 25 s and logged 4 `ADV.wmv` hits.

**`docs/agents/HANDOFF-2026-09-18.md`** records what changed since 2026-09-16,
what is on the server, what cannot travel through git, and the traps this machine
paid for — chiefly that the guest-PC branch probe exists only on the fork's
snapshot branch, so a rebuild from `sylpheed-re` silently loses it.

**`HANDOFF-2026-09-06.md`** gets a correction note rather than an edit: a plain
clone works again now that the 545 MB branch is gone, and its baselines are two
baselines old.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 07:17:36 +02:00

130 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# INTERACTIVE launcher for the NATIVE Linux Xenia-Canary build.
#
# Opens a REAL window on your desktop (display :0) and — unlike
# run-canary-native-safe.sh — uses HARDWARE Vulkan (the AMD GPU) and leaves
# audio ON. This is for hands-on play/testing, not headless tracer runs.
#
# ⚠ WARNING: this renders on the same AMD GPU that drives your VS Code / desktop.
# The historical "crashes VS Code" issue was vkd3d-proton (D3D12->Vulkan under
# Wine); the native build talks to Vulkan directly, so it MAY be fine — but if
# the desktop glitches or VS Code dies, fall back to run-canary-native-safe.sh
# (software Vulkan) or set CANARY_SOFTWARE=1 below.
#
# Usage: tools/run-canary-native.sh [seconds] (no arg => runs until you close it)
# env: CANARY_BIN override binary (default = worktree Release build)
# CANARY_SOFTWARE=1 force software Vulkan (lavapipe) even here
# CANARY_MUTE=1 start muted / no audio device (--apu=nop)
# CANARY_GPU=<substr> pick a specific Vulkan device by name (e.g. radv, 6800)
# CANARY_EXTRA_ARGS space-separated extra cvars
# DISPLAY target X display (default :0 = your screen)
# Output: /tmp/canary_native_interactive.stdout (+ xenia.log in the binary dir).
set -u
# Paths derive from where this script sits — see the note in run-canary-safe.sh.
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORKSPACE="$(cd "$HERE/../.." && pwd)"
BIN_DEFAULT="$WORKSPACE/xenia-canary-native/build/bin/Linux/Release/xenia_canary"
BIN_EXE="${CANARY_BIN:-$BIN_DEFAULT}"
ISO="${SYLPHEED_ISO:-$WORKSPACE/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso}"
[ -f "$ISO" ] || { echo "ABORT: no ISO at '$ISO' — set \$SYLPHEED_ISO"; exit 4; }
SECS="${1:-0}" # 0 => no timeout (interactive)
export DISPLAY="${DISPLAY:-:0}"
[ -x "$BIN_EXE" ] || { echo "ABORT: native binary not found/executable: $BIN_EXE"; exit 4; }
# --- Vulkan device selection ---
if [ "${CANARY_SOFTWARE:-0}" = "1" ]; then
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.json
export VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.json
export MESA_VK_DEVICE_SELECT=llvmpipe
echo "GPU: forced software Vulkan (lavapipe)."
else
# Hardware Vulkan. Optionally pin a device by substring (RADV AMD is default [0]).
[ -n "${CANARY_GPU:-}" ] && export MESA_VK_DEVICE_SELECT="$CANARY_GPU"
echo "GPU: HARDWARE Vulkan${CANARY_GPU:+ (pinned: $CANARY_GPU)}."
echo " Visible devices:"; vulkaninfo --summary 2>/dev/null | grep -i deviceName | sed 's/^/ /'
fi
# --- logging: keep it QUIET so kernel/APU debug spam doesn't starve the audio
# worker thread. At --log_level=3 (Debug) the d>/A> firehose (piped through
# tee) stalls the ALSA pipeline and mission audio dies permanently — the
# exact "mission-audio silence" that commit f10484834 fixes in code; the
# log flood defeats the keepalive. log_mask=13 = suppress Kernel|Cpu|Gpu.
# (guest_audio_flags defaults to 0 = Digital Stereo, the Linux-safe path.)
LOGLEVEL="${CANARY_LOGLEVEL:-1}"
LOGMASK="${CANARY_LOGMASK:-13}"
# --- audio ---
args=(--log_level="$LOGLEVEL" --log_mask="$LOGMASK")
if [ "${CANARY_MUTE:-0}" = "1" ]; then
export SDL_AUDIODRIVER=dummy
args+=(--mute=true --apu=nop)
echo "AUDIO: muted (apu=nop)."
else
echo "AUDIO: on (ALSA)."
fi
# --- audio RE: capture true XMA per-stream params (channels/rate/head bytes) to
# xenia.log as you play. Deduped (one line per unique sound); logs at Warning
# so it shows at the audio-safe log level without spam. Off unless requested.
if [ "${CANARY_XMA_PROBE:-0}" = "1" ]; then
args+=(--xma_param_probe=true)
echo "XMA-PARAM probe: ON (params captured to xenia.log)."
fi
# --- audio watchdog: when audio dies mid-mission and never returns, report
# WHICH pipeline stage stopped (guest callback blocked / no XMA decode /
# no frames submitted / host driver not writing). Near-silent while healthy.
if [ "${CANARY_AUDIO_WD:-0}" = "1" ]; then
args+=(--audio_watchdog=true)
echo "AUDIO watchdog: ON (logs 'AUDIO-WD ...' when audio dies)."
fi
# --- hang watchdog: if the guest stops presenting frames for N seconds, the
# emulator dumps every guest thread's registers + guest call stack to
# xenia.log by itself. No debugger, no ptrace, no need to keep the window
# open -- the freeze autopsy is already in the log.
if [ -n "${CANARY_HANG_WD:-}" ]; then
args+=(--hang_watchdog_secs="$CANARY_HANG_WD")
echo "HANG watchdog: ON (${CANARY_HANG_WD}s without a frame => guest dump to xenia.log)."
fi
if [ -n "${CANARY_EXTRA_ARGS:-}" ]; then
read -ra EXTRA <<< "$CANARY_EXTRA_ARGS"
args+=("${EXTRA[@]}")
fi
# --- CPU stress: the mid-mission audio death only shows up under host CPU load
# (the guest's audio callback misses its 5.33ms deadlines and the game tears
# its own audio client down). CANARY_STRESS=<n> spins n busy loops for the
# duration of the run so the bug reproduces on demand instead of by luck.
# They are killed when the run ends. Silent (no audio involvement).
STRESS_PIDS=()
stress_cleanup() {
if [ ${#STRESS_PIDS[@]} -gt 0 ]; then
kill "${STRESS_PIDS[@]}" 2>/dev/null
echo "stress: stopped ${#STRESS_PIDS[@]} load generators."
fi
}
trap stress_cleanup EXIT INT TERM
if [ -n "${CANARY_STRESS:-}" ] && [ "${CANARY_STRESS}" -gt 0 ] 2>/dev/null; then
for _i in $(seq 1 "$CANARY_STRESS"); do
# Pure userspace spin; no I/O, no audio, no privileges.
( while :; do :; done ) &
STRESS_PIDS+=($!)
done
echo "STRESS: ON -- ${CANARY_STRESS} busy loops competing for CPU (of $(nproc) cores)."
fi
pkill -x xenia_canary 2>/dev/null
cd "$(dirname "$BIN_EXE")" || { echo "ABORT: bin dir missing"; exit 4; }
rm -f xenia.log
echo "launch (interactive, DISPLAY=$DISPLAY): $(basename "$BIN_EXE") ${args[*]}"
if [ "$SECS" -gt 0 ] 2>/dev/null; then
timeout -k 5 "$SECS" "$BIN_EXE" "$ISO" "${args[@]}" 2>&1 | tee /tmp/canary_native_interactive.stdout
else
"$BIN_EXE" "$ISO" "${args[@]}" 2>&1 | tee /tmp/canary_native_interactive.stdout
fi
rc=${PIPESTATUS[0]}
echo "rc=$rc ADV.wmv=$(grep -ac 'ADV.wmv' xenia.log 2>/dev/null)"