#!/usr/bin/env bash # SAFE Xenia-Canary launcher for THIS box (shared AMD GPU + GPU-accelerated VS Code). # # Canary's vkd3d-proton renders D3D12->Vulkan; if it picks the AMD GPU it CRASHES # VS Code. This wrapper forces software Vulkan (llvmpipe/lavapipe) IN THE SAME # process as wine (env vars do NOT survive across separate shells!), and REFUSES # to launch if any hardware Vulkan device is still visible (hard pre-flight gate). # # Usage: tools/run-canary-safe.sh [audit61_pcs_csv] [seconds] # e.g. tools/run-canary-safe.sh 0x82507458,0x8250747c 95 # Output: /tmp/canary_video.stdout (+ xenia.log in the binary dir). Prints rc + ADV.wmv hit count. set -u # --- force software Vulkan, belt-and-suspenders across loader/driver variants --- 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 export DXVK_FILTER_DEVICE_NAME=llvmpipe export VKD3D_FILTER_DEVICE_NAME=llvmpipe export LIBGL_ALWAYS_SOFTWARE=1 # Paths come from where this script sits — tools/ inside the repo, whose parent # directory is the workspace holding the fork checkouts and the game data. Both # are overridable, so a machine that lays things out differently sets the env # var instead of editing the script. (This file used to hardcode one machine's # absolute paths, which is why it could not be checked in.) HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" WORKSPACE="$(cd "$HERE/../.." && pwd)" BIN="${CANARY_WINE_BIN_DIR:-$WORKSPACE/xenia-canary/build-cross/bin/Windows/Debug}" 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; } PROBES="${1:-}" SECS="${2:-95}" # --- HARD PRE-FLIGHT GATE: only proceed if Vulkan exposes software devices ONLY --- devs="$(vulkaninfo --summary 2>/dev/null | grep -i deviceName || true)" if echo "$devs" | grep -qiE 'radv|amd|radeon|nvidia|geforce|intel\b'; then echo "ABORT(pre-flight): a HARDWARE Vulkan device is still visible -> refusing (would crash VS Code):" echo "$devs" exit 3 fi if ! echo "$devs" | grep -qiE 'llvmpipe'; then echo "ABORT(pre-flight): llvmpipe not visible; lavapipe ICD missing? devs=[$devs]" exit 3 fi echo "pre-flight OK: software-only Vulkan -> $devs" # --- clean slate --- pkill -x xenia_canary_i2d.exe 2>/dev/null; wineserver -k 2>/dev/null; pkill -x Xvfb 2>/dev/null; sleep 1 Xvfb :99 -screen 0 1280x720x24 -nolisten tcp >/tmp/xvfb.log 2>&1 & XVFB=$! sleep 2 export DISPLAY=:99 cd "$BIN" || { echo "ABORT: bin dir missing"; kill "$XVFB" 2>/dev/null; exit 4; } rm -f xenia.log # Binary is overridable (default keeps the historical _i2d snapshot); extra # cvars pass through via CANARY_EXTRA_ARGS (space-separated, values w/o spaces). # ⚠️ THIS WINE BUILD HAS NO INSTRUMENTATION AND CANNOT BE REFRESHED HERE. # Measured 2026-09-20: `xenia_canary_i2d.exe` does not exist at all, and the # `xenia_canary.exe` that does (2026-06-19) has ZERO hits for both # `audit_61_branch_probe_pcs` and `RE-INPUT`/`RE-DRAW`. Rebuilding it needs the # clang-cl + xwin cross toolchain on the `cross-build-wine` branch. # # 🔴 FOR PROBE RUNS USE `run-canary-native-safe.sh` INSTEAD -- same hard Vulkan # gate, same headless behaviour, and it runs the Checked native binary, which # carries audit_61 and the RE-INPUT/RE-DRAW logging. BIN_EXE="${CANARY_BIN:-xenia_canary_i2d.exe}" if [ ! -f "$BIN/$BIN_EXE" ]; then echo "ABORT: no Wine binary at $BIN/$BIN_EXE" >&2 echo " This build is stale and uninstrumented; use run-canary-native-safe.sh" >&2 echo " for anything needing audit_61 or the RE-* logging." >&2 exit 4 fi args=(--log_level=3 --mute=true) [ -n "$PROBES" ] && args+=("--audit_61_branch_probe_pcs=$PROBES") if [ -n "${CANARY_EXTRA_ARGS:-}" ]; then read -ra EXTRA <<< "$CANARY_EXTRA_ARGS" args+=("${EXTRA[@]}") fi echo "launch (sw-vulkan, muted, ${SECS}s): wine $BIN_EXE ${args[*]}" timeout "$SECS" wine "./$BIN_EXE" "$ISO" "${args[@]}" >/tmp/canary_video.stdout 2>&1 rc=$? pkill -x xenia_canary_i2d.exe 2>/dev/null; wineserver -k 2>/dev/null; kill "$XVFB" 2>/dev/null; pkill -x Xvfb 2>/dev/null echo "rc=$rc ADV.wmv=$(grep -ac 'ADV.wmv' xenia.log 2>/dev/null) logsize=$(wc -c < xenia.log 2>/dev/null)"