superx-goes-arch/tools/steam-egpu-toggle.py
Kay Türtscher ed130e79bd 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
2026-06-06 19:43:46 +02:00

99 lines
3.4 KiB
Python

#!/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()