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>
130 lines
6.1 KiB
Bash
Executable File
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)" |