steam: auto-egpu-detection via VDF-patch statt Shell-Wrapper
Proton sandboxed keine Env-Vars aus dem Wrapper → direkt in LaunchOptions schreiben. steam-egpu: launcher checkt card0 vor Steam-Start und patcht localconfig.vdf steam-egpu-toggle.py: schaltet 120+ Spiele auf einmal um udev: automatisch bei eGPU-Connect/Disconnect
This commit is contained in:
parent
44e6b00fb7
commit
ed130e79bd
3 changed files with 132 additions and 19 deletions
|
|
@ -1,18 +1,32 @@
|
|||
#!/bin/bash
|
||||
# steam-egpu — Wrapper der vor jedem Steam-Start die Launch Options sync't
|
||||
# Ersetzt den normalen "steam"-Aufruf. Trägt superx-game-wrapper
|
||||
# automatisch in alle Spiele ein, die noch keine LaunchOptions haben.
|
||||
# steam-egpu — Auto-eGPU-Detection vor jedem Steam-Start
|
||||
#
|
||||
# Installation: siehe tools/install-egpu.sh (Schritt 5)
|
||||
# Erkennt ob die eGPU da ist und patcht die LaunchOptions entsprechend.
|
||||
# Kein Shell-Wrapper für einzelne Spiele (Proton sandboxed Env-Vars),
|
||||
# sondern direktes Patchen der VDF-Datei.
|
||||
#
|
||||
# Installation: tools/install-egpu.sh oder manuell:
|
||||
# cp tools/steam-egpu ~/.local/bin/steam-egpu
|
||||
# Hyprland exec-once: ~/.local/bin/steam-egpu (startet Steam mit Sync)
|
||||
#
|
||||
# Als Steam-Launcher verwenden (statt /usr/bin/steam):
|
||||
# cp configs/steam-egpu.desktop ~/.local/share/applications/
|
||||
|
||||
WRAPPER_STRING="/home/nepharius/SuperX-goes-Arch/tools/superx-game-wrapper.sh %command%"
|
||||
CONFIG="$HOME/.local/share/Steam/userdata/19491507/config/localconfig.vdf"
|
||||
SYNC_SCRIPT="/home/nepharius/SuperX-goes-Arch/.venv/bin/python3 /home/nepharius/SuperX-goes-Arch/tools/steam-egpu-patch-all.py"
|
||||
VDF="$HOME/.local/share/Steam/userdata/19491507/config/localconfig.vdf"
|
||||
TOGGLE="$HOME/SuperX-goes-Arch/.venv/bin/python3 $HOME/SuperX-goes-Arch/tools/steam-egpu-toggle.py"
|
||||
EGPU_CARD="/dev/dri/card0"
|
||||
|
||||
# Sync: alle Spiele ohne LaunchOptions bekommen den Wrapper
|
||||
if [ -f "$CONFIG" ]; then
|
||||
$SYNC_SCRIPT -y 2>/dev/null &
|
||||
# Prüfen ob eGPU da ist
|
||||
if [ -e "$EGPU_CARD" ] && [ "$(cat /sys/class/drm/card0/device/vendor 2>/dev/null)" = "0x1002" ]; then
|
||||
MODE="egpu"
|
||||
echo "[steam-egpu] eGPU erkannt → setze DRI_PRIME=1" >&2
|
||||
else
|
||||
MODE="igpu"
|
||||
echo "[steam-egpu] Keine eGPU → iGPU-Modus" >&2
|
||||
fi
|
||||
|
||||
# Steam starten
|
||||
# Nur patchen wenn nötig (Änderungen werden gezählt)
|
||||
$TOGGLE "$MODE" 2>&1 | grep -q "Geändert: 0" && echo "[steam-egpu] Bereits aktuell, kein Patch nötig" >&2
|
||||
|
||||
# Steam weitergeben
|
||||
exec /usr/bin/steam "$@"
|
||||
|
|
|
|||
99
tools/steam-egpu-toggle.py
Normal file
99
tools/steam-egpu-toggle.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Schaltet Steam-Launch-Options zwischen eGPU und iGPU um.
|
||||
|
||||
Wird per udev getriggert wenn die eGPU verbunden/getrennt wird.
|
||||
Patched localconfig.vdf direkt — Steam muss danach neu gestartet werden.
|
||||
|
||||
Usage:
|
||||
steam-egpu-toggle.py egpu # eGPU-Modus: DRI_PRIME=1 in alle Spiele
|
||||
steam-egpu-toggle.py igpu # iGPU-Modus: DRI_PRIME entfernen
|
||||
steam-egpu-toggle.py status # Aktuellen Modus anzeigen
|
||||
"""
|
||||
import sys, shutil
|
||||
from pathlib import Path
|
||||
import vdf
|
||||
|
||||
STEAM_USERDATA = Path.home() / ".local/share/Steam/userdata/19491507/config/localconfig.vdf"
|
||||
|
||||
EGPU_OPTS = "DRI_PRIME=1 VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/radeon_icd.json VKD3D_CONFIG=force_host_gpu DXVK_CONFIG=dxgi.allowUnsupportedDrivers=True %command%"
|
||||
IGPU_OPTS = "%command%"
|
||||
LAUNCH_KEY = "LaunchOptions"
|
||||
|
||||
# Spiele die NIEMALS angerührt werden (z.B. Proton, Steam Runtime, Tools)
|
||||
SKIP_APPIDS = {
|
||||
"1493710", # Proton Experimental
|
||||
"4183110", # Steam Linux Runtime 4.0
|
||||
"228980", # Steamworks Common Redistributables
|
||||
}
|
||||
|
||||
|
||||
def get_apps(config):
|
||||
return config.get("UserLocalConfigStore", {}).get("Software", {}).get("Valve", {}).get("Steam", {}).get("apps", {})
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: steam-egpu-toggle.py {egpu|igpu|status}")
|
||||
sys.exit(1)
|
||||
|
||||
cmd = sys.argv[1]
|
||||
|
||||
if not STEAM_USERDATA.exists():
|
||||
print(f"ERROR: {STEAM_USERDATA} nicht gefunden")
|
||||
sys.exit(1)
|
||||
|
||||
# Backup
|
||||
backup = STEAM_USERDATA.with_suffix(".vdf.togglebak")
|
||||
shutil.copy2(STEAM_USERDATA, backup)
|
||||
|
||||
with open(STEAM_USERDATA) as f:
|
||||
config = vdf.load(f)
|
||||
|
||||
apps = get_apps(config)
|
||||
|
||||
if cmd == "status":
|
||||
e_count = sum(1 for a in apps.values() if a.get(LAUNCH_KEY, "").startswith("DRI_PRIME=1"))
|
||||
w_count = sum(1 for a in apps.values() if "superx-game-wrapper" in a.get(LAUNCH_KEY, ""))
|
||||
o_count = sum(1 for a in apps.values() if a.get(LAUNCH_KEY, "") and not a[LAUNCH_KEY].startswith("DRI_PRIME=1") and "superx-game-wrapper" not in a[LAUNCH_KEY])
|
||||
print(f"eGPU-Modus: {e_count} Spiele")
|
||||
print(f"Wrapper: {w_count} Spiele")
|
||||
print(f"Individuell:{o_count} Spiele")
|
||||
return
|
||||
|
||||
target_opts = EGPU_OPTS if cmd == "egpu" else IGPU_OPTS
|
||||
changed = 0
|
||||
cleaned_wrapper = 0
|
||||
|
||||
for appid, appcfg in apps.items():
|
||||
if appid in SKIP_APPIDS:
|
||||
continue
|
||||
current = appcfg.get(LAUNCH_KEY, "")
|
||||
|
||||
# Cleanup: wrapper ersetzen
|
||||
if "superx-game-wrapper" in current:
|
||||
appcfg[LAUNCH_KEY] = target_opts
|
||||
cleaned_wrapper += 1
|
||||
changed += 1
|
||||
# Cleanup: leere oder fehlende LaunchOptions
|
||||
elif not current or current == "%command%":
|
||||
appcfg[LAUNCH_KEY] = target_opts
|
||||
changed += 1
|
||||
elif cmd == "egpu" and not current.startswith("DRI_PRIME=1"):
|
||||
appcfg[LAUNCH_KEY] = target_opts
|
||||
changed += 1
|
||||
elif cmd == "igpu" and current.startswith("DRI_PRIME=1"):
|
||||
appcfg[LAUNCH_KEY] = target_opts
|
||||
changed += 1
|
||||
|
||||
with open(STEAM_USERDATA, "w") as f:
|
||||
vdf.dump(config, f, pretty=True)
|
||||
|
||||
mode = "eGPU (DRI_PRIME=1)" if cmd == "egpu" else "iGPU (Standard)"
|
||||
print(f"Modus: {mode}")
|
||||
print(f"Geändert: {changed} Spiele (davon {cleaned_wrapper} Wrapper ersetzt)")
|
||||
print(f"Backup: {backup}")
|
||||
print(f"\n⚠️ Steam muss NEU GESTARTET werden!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -3,15 +3,15 @@
|
|||
# Installation: sudo cp udev/99-egpu-superx.rules /etc/udev/rules.d/
|
||||
# sudo udevadm control --reload-rules && sudo udevadm trigger
|
||||
#
|
||||
# Triggert superx-egpu-perf.sh wenn die RX 9060 XT (1002:7590)
|
||||
# über USB4/Thunderbolt verbunden oder getrennt wird.
|
||||
# eGPU verbunden → schaltet Steam-Spiele auf DRI_PRIME=1
|
||||
# eGPU getrennt → schaltet zurück auf iGPU
|
||||
|
||||
# RX 9060 XT (1002:7590) verbunden
|
||||
SUBSYSTEM=="pci", ATTR{vendor}=="0x1002", ATTR{device}=="0x7590", ACTION=="add", \
|
||||
RUN+="/usr/local/bin/superx-egpu-perf.sh add"
|
||||
RUN+="/usr/local/bin/superx-egpu-perf.sh add", \
|
||||
RUN+="/usr/bin/su nepharius -c '/home/nepharius/SuperX-goes-Arch/.venv/bin/python3 /home/nepharius/SuperX-goes-Arch/tools/steam-egpu-toggle.py egpu'"
|
||||
|
||||
# RX 9060 XT getrennt
|
||||
SUBSYSTEM=="pci", ATTR{vendor}=="0x1002", ATTR{device}=="0x7590", ACTION=="remove", \
|
||||
RUN+="/usr/local/bin/superx-egpu-perf.sh remove"
|
||||
|
||||
# JHL7440 Controller verbunden — triggert PCI-Rescan für dahinterliegende GPU
|
||||
SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", ATTR{device}=="0x15ef", ACTION=="add", \
|
||||
RUN+="/usr/bin/bash -c 'echo 1 > /sys/bus/pci/rescan'"
|
||||
RUN+="/usr/local/bin/superx-egpu-perf.sh remove", \
|
||||
RUN+="/usr/bin/su nepharius -c '/home/nepharius/SuperX-goes-Arch/.venv/bin/python3 /home/nepharius/SuperX-goes-Arch/tools/steam-egpu-toggle.py igpu'"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue