mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 19:27:09 -04:00
x86-64 client: the arm64 client's Proton tools and one shared library
Each of the arm64 client's Proton tools (bannerlator-proton-arm64, GE-Proton, CachyOS) gets a wrapper in the x86-64 client with the same folder and tool name. The wrapper, an x86 script under FEX, starts bannerlator-x64-arm-proton through an arm64 binary - FEX hands it to the CPU (device: an x86 shell under FEX ran arm64 uname natively) - which puts back the arm64 session's environment (saved by x64_env), points Proton at the arm64 client's install folder (its steamclient.so) and runs the tool's own launcher: same Proton, Components swaps, per-game environment as from the arm64 client. The arm64 client's library folders become this client's too, and ARM64 Proton is its Steam Play default, so a Windows game installed by either client is installed for both and stays the Windows build. Titles it runs as Linux builds (DroidDeck direct) keep their own copy.
This commit is contained in:
1 parent
43fcfe626b
commit
25ca971058
3 files changed
+143
No files matched your search
@@ -46,6 +46,7 @@ object SessionFiles {
|
||||
"usr/local/bin/bannerlator-steam-launch" to "usr/local/bin/bannerlator-steam-launch",
|
||||
// Experimental: Valve's x86-64 client under FEX (desktop menu entry).
|
||||
"usr/local/bin/bannerlator-steam-x64" to "usr/local/bin/bannerlator-steam-x64",
|
||||
"usr/local/bin/bannerlator-x64-arm-proton" to "usr/local/bin/bannerlator-x64-arm-proton",
|
||||
"usr/local/bin/bannerlator-desktop-games" to "usr/local/bin/bannerlator-desktop-games",
|
||||
"usr/local/bin/bannerlator-steam-shim" to "usr/local/bin/bannerlator-steam-shim",
|
||||
"usr/local/bin/bannerlator-steam-shortcuts" to "usr/local/bin/bannerlator-steam-shortcuts",
|
||||
|
||||
@@ -289,6 +289,109 @@ for app in apps:
|
||||
'\t\t\t\t\t\t"config"\t\t""\n\t\t\t\t\t\t"priority"\t\t"250"\n\t\t\t\t\t}' % app)
|
||||
s = s[:open_] + entry + inner + s[close:]
|
||||
open(path, "w", encoding="utf-8", errors="surrogateescape").write(s)
|
||||
PY
|
||||
fi
|
||||
# The arm64 client's Proton tools (bannerlator-proton-arm64, GE-Proton, CachyOS): one wrapper per
|
||||
# tool, same folder and tool name (Components swaps and per-title mappings are keyed by them). The
|
||||
# wrapper is an x86 script under FEX; it starts bannerlator-x64-arm-proton through an arm64 binary,
|
||||
# which FEX hands to the CPU, so Wine and the game run exactly as from the arm64 client.
|
||||
arm_tools=$ARM_STEAM/compatibilitytools.d
|
||||
mkdir -p "$X64_HOME/arm64"
|
||||
cp -f /usr/bin/env "$X64_HOME/arm64/env"
|
||||
for w in "$STEAM_X64"/compatibilitytools.d/*/.droiddeck-arm64-proton; do
|
||||
[ -e "$w" ] || continue
|
||||
d=${w%/.droiddeck-arm64-proton}
|
||||
[ -d "$arm_tools/${d##*/}" ] || rm -rf "$d"
|
||||
done
|
||||
for src in "$arm_tools"/*/; do
|
||||
src=${src%/}; name=${src##*/}
|
||||
[ -f "$src/compatibilitytool.vdf" ] && [ -f "$src/toolmanifest.vdf" ] || continue
|
||||
[ "$name" = droiddeck-direct ] && continue
|
||||
dst=$STEAM_X64/compatibilitytools.d/$name
|
||||
mkdir -p "$dst"
|
||||
: > "$dst/.droiddeck-arm64-proton"
|
||||
# The tool's own name and display name, as the arm64 client shows it.
|
||||
python3 - "$src/compatibilitytool.vdf" "$dst/compatibilitytool.vdf" <<'PY' || { rm -rf "$dst"; continue; }
|
||||
import re, sys
|
||||
s = open(sys.argv[1], encoding="utf-8", errors="replace").read()
|
||||
m = re.search(r'"compat_tools"\s*\{\s*"([^"]+)"', s)
|
||||
if not m:
|
||||
sys.exit(1)
|
||||
key = m.group(1)
|
||||
d = re.search(r'"display_name"\s*"([^"]*)"', s)
|
||||
name = d.group(1) if d else key
|
||||
open(sys.argv[2], "w").write(
|
||||
'"compatibilitytools"\n{\n "compat_tools"\n {\n "%s"\n {\n "install_path" "."\n'
|
||||
' "display_name" "%s"\n "from_oslist" "windows"\n "to_oslist" "linux"\n }\n }\n}\n'
|
||||
% (key, name))
|
||||
PY
|
||||
cat > "$dst/toolmanifest.vdf" <<'VDF'
|
||||
"manifest"
|
||||
{
|
||||
"version" "2"
|
||||
"commandline" "/run %verb%"
|
||||
}
|
||||
VDF
|
||||
printf '#!/bin/sh\n# The arm64 client'"'"'s %s, run natively (bannerlator-x64-arm-proton).\nexec "%s" /usr/local/bin/bannerlator-x64-arm-proton "%s" "$@"\n' \
|
||||
"$name" "$X64_HOME/arm64/env" "$name" > "$dst/run"
|
||||
chmod 755 "$dst/run"
|
||||
done
|
||||
# One library with the arm64 client: its library folders become this client's too, so a Windows
|
||||
# game installed by either is installed for both. Titles this client runs as Linux builds (the
|
||||
# DroidDeck direct ones) keep their own copy in its own folder - the arm64 client needs the
|
||||
# Windows build of the same title. Written while no x86 client runs: it rewrites these on exit.
|
||||
if ! pgrep -f 'steamrt64/steam( |$)' >/dev/null 2>&1; then
|
||||
python3 - "$ARM_STEAM/config/libraryfolders.vdf" \
|
||||
"$STEAM_X64/config/libraryfolders.vdf" "$STEAM_X64/steamapps/libraryfolders.vdf" <<'PY' || step "could not share the arm64 client's library folders"
|
||||
import os, re, sys
|
||||
src, dsts = sys.argv[1], sys.argv[2:]
|
||||
if not os.path.isfile(src):
|
||||
sys.exit(0)
|
||||
want = re.findall(r'"path"\s*"([^"]+)"', open(src, encoding="utf-8", errors="replace").read())
|
||||
for dst in dsts:
|
||||
if os.path.isfile(dst):
|
||||
s = open(dst, encoding="utf-8", errors="surrogateescape").read()
|
||||
else:
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
s = '"libraryfolders"\n{\n}\n'
|
||||
have = set(re.findall(r'"path"\s*"([^"]+)"', s))
|
||||
nums = [int(n) for n in re.findall(r'^\t"(\d+)"\s*$', s, re.M)]
|
||||
n = max(nums) + 1 if nums else 0
|
||||
add = ""
|
||||
for path in want:
|
||||
if path in have:
|
||||
continue
|
||||
add += ('\t"%d"\n\t{\n\t\t"path"\t\t"%s"\n\t\t"label"\t\t""\n\t\t"contentid"\t\t"0"\n'
|
||||
'\t\t"totalsize"\t\t"0"\n\t\t"apps"\n\t\t{\n\t\t}\n\t}\n' % (n, path))
|
||||
n += 1
|
||||
if add:
|
||||
end = s.rstrip().rfind("}")
|
||||
s = s[:end] + add + s[end:]
|
||||
open(dst, "w", encoding="utf-8", errors="surrogateescape").write(s)
|
||||
PY
|
||||
fi
|
||||
# Steam Play for every title not mapped otherwise: the arm64 client's own ARM64 Proton, so a
|
||||
# shared install stays the Windows build the arm64 client also runs.
|
||||
if [ -d "$STEAM_X64/compatibilitytools.d/bannerlator-proton-arm64" ] && [ -f "$STEAM_X64/config/config.vdf" ] &&
|
||||
! pgrep -f 'steamrt64/steam( |$)' >/dev/null 2>&1; then
|
||||
python3 - "$STEAM_X64/config/config.vdf" <<'PY' || step "could not make ARM64 Proton the default"
|
||||
import re, sys
|
||||
path = sys.argv[1]
|
||||
s = open(path, encoding="utf-8", errors="surrogateescape").read()
|
||||
m = re.search(r'"CompatToolMapping"\s*\{', s)
|
||||
if not m:
|
||||
sys.exit(0)
|
||||
depth, k = 1, m.end()
|
||||
while depth:
|
||||
depth += s[k] == "{"
|
||||
depth -= s[k] == "}"
|
||||
k += 1
|
||||
if re.search(r'^\s*"0"\s*$', s[m.end():k], re.M):
|
||||
sys.exit(0)
|
||||
entry = ('\n\t\t\t\t\t"0"\n\t\t\t\t\t{\n\t\t\t\t\t\t"name"\t\t"bannerlator-proton-arm64"\n'
|
||||
'\t\t\t\t\t\t"config"\t\t""\n\t\t\t\t\t\t"priority"\t\t"75"\n\t\t\t\t\t}')
|
||||
s = s[:m.end()] + entry + s[m.end():]
|
||||
open(path, "w", encoding="utf-8", errors="surrogateescape").write(s)
|
||||
PY
|
||||
fi
|
||||
# A FEX process takes its rootfs from FEXServer, not from its own environment, and a server
|
||||
@@ -308,6 +411,10 @@ x64_gpu() {
|
||||
|
||||
# The environment the client and everything it starts run in.
|
||||
x64_env() {
|
||||
# The arm64 session's environment as it is now, for the arm64 Proton tools this client starts
|
||||
# (bannerlator-x64-arm-proton puts it back before Proton runs).
|
||||
export -p | grep -v -E '^declare -x (PWD|OLDPWD|SHLVL|_)=' > "$X64_HOME/arm-session.env.new" || true
|
||||
mv -f "$X64_HOME/arm-session.env.new" "$X64_HOME/arm-session.env"
|
||||
# The arm64 session's library paths and preloads are aarch64 and mean nothing to x86 processes.
|
||||
unset LD_LIBRARY_PATH LD_PRELOAD STEAM_RUNTIME STEAM_RUNTIME_PREFER_HOST_LIBRARIES
|
||||
# The client and its browser draw in software, as they always have: with the thunks the browser's
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
# The x86-64 client's way into the arm64 Proton tools (bannerlator-steam-x64 makes one wrapper per
|
||||
# tool in its compatibilitytools.d). The wrapper is an x86 script under FEX; it starts this one
|
||||
# through an arm64 binary, which FEX hands straight to the CPU, so from here on everything is native
|
||||
# and sees the guest as the arm64 client does: the same Proton, launcher, Components swaps, per-game
|
||||
# environment and Steam client library (~/.steam/sdk64) as a launch from the arm64 client.
|
||||
# bannerlator-x64-arm-proton <tool folder> <verb> <command...>
|
||||
tool=$1; shift
|
||||
x64_home=$HOME
|
||||
|
||||
# Drop the x86 side: FEX's settings, the x86 library paths and preloads, the client's software GL.
|
||||
for v in $(compgen -e); do
|
||||
case $v in FEX_*) unset "$v" ;; esac
|
||||
done
|
||||
unset LD_LIBRARY_PATH LD_PRELOAD STEAM_RUNTIME_STEAMRT STEAM_STEAMRT_RECURSION_GUARD \
|
||||
LIBGL_ALWAYS_SOFTWARE LIBGL_DRI3_DISABLE GALLIUM_DRIVER BL_WEBHELPER_HIDE_TRACER PROOT_FP_OFF
|
||||
|
||||
# The arm64 session's environment, saved by bannerlator-steam-x64 before it made the x86 one: HOME,
|
||||
# PATH, the GPU (Turnip, Zink), audio, input, the proot fast path. Steam's per-game variables
|
||||
# (SteamAppId, STEAM_COMPAT_*) are not in it and stay as the client set them.
|
||||
if [ -f "$x64_home/arm-session.env" ]; then
|
||||
. "$x64_home/arm-session.env"
|
||||
else
|
||||
export HOME=/root
|
||||
fi
|
||||
# Proton takes its Steam client parts from the client's install folder; the x86-64 client's are x86.
|
||||
export STEAM_COMPAT_CLIENT_INSTALL_PATH=$HOME/.local/share/Steam
|
||||
|
||||
dir=$HOME/.local/share/Steam/compatibilitytools.d/$tool
|
||||
manifest=$dir/toolmanifest.vdf
|
||||
[ -f "$manifest" ] || { echo "bannerlator-x64-arm-proton: no tool $dir" >&2; exit 127; }
|
||||
# "commandline" "/bannerlator-proton %verb%": the entry point, relative to the tool's folder.
|
||||
cmd=$(sed -n 's/^[[:space:]]*"commandline"[[:space:]]*"\([^"]*\)".*/\1/p' "$manifest" | head -n 1)
|
||||
entry=${cmd%% *}
|
||||
exec "$dir/${entry#/}" "$@"
|
||||
Reference in new issue
Block a user