Commit Graph
217 Commits
Author SHA1 Message Date
maxjivi05 7eb4717d4c chore: drop the comments added with the Unity TSO fix 2026-10-23 16:16:10 -04:00
MaxsTechReview 0c26a829ec fix: keep FEX's TSO on for Unity games (#1415)
The default FEX preset (Performance + TSO) is fine for Unity. But when
the Default profile is switched to a preset
that turns TSO off (Performance, Extreme, Extreme-gn, Denuvo), Unity
players break. DroidDeck already keeps full TSO
for .NET games (`coreclr.dll`) whatever the preset; this gives Unity
players the same safety net for TSO.

Tested on a Pixel 10 Pro Fold (PowerVR DXT-48-1536), shared preset
Performance (TSO off):

| Game | Build | TSO off | TSO on |
| --- | --- | --- | --- |
| Megabonk | Unity 2023.2 IL2CPP, native Linux, "Linux x86 (FEX)" |
froze on about half of launches (every thread parked on a futex) | 5 of
5 starts, played run stayed responsive |
| Crab Game | Unity IL2CPP, Windows, Proton arm64 | 9 of 10 starts; 1
access violation in `UnityPlayer.dll` (read of a garbage pointer) | 10
of 10 starts |

Measured cost of TSO on Megabonk: none (+2% fps with TSO on, within
noise).

What changes:
- `droiddeck-game-env`: `unity_memory_ordering` sets `FEX_TSOENABLED=1`
when `UnityPlayer.dll`, `UnityPlayer.so` or
`GameAssembly.so` sits next to the executable (or one folder below). A
FEX preset chosen for the game still wins
(fixes sit between the shared preset and the per-game entry, as for
.NET).
- `droiddeck-fex`: the FEX tool now applies the environment half of
these game-file fixes, so native Linux Unity builds
  get it too. Launch arguments some fixes add stay Proton-only.
- Docs paragraph in `docs/development/game-environment.md`; tests in
`test_game_environment.py` and
  `test_droiddeck_fex.py`.

Device check of the change itself: with the session's
`droiddeck-game-env` patched, shared TSO off and no per-game
entry, Crab Game started with `FEX_TSOENABLED=1`.

Related to #1386, but not a fix for its Risk of Rain 2 crash: that game
is Unity Mono, which with the default preset
already has TSO on; the report points at multiblock instead (as the .NET
fix turns off). Both games tested here are
IL2CPP, so this PR doesn't change multiblock. #1386's other points
(`steam_appid.txt`, `device.txt`) aren't covered.

Tests (WSL, on main `16bedf36` with the patch): `test_game_environment`
+ `test_droiddeck_fex` 119 OK. Full `tools/tests`: 1114 tests, one
failure,
`test_appimage_run…test_a_failed_program_shows_the_log_it_wrote`, which
fails the same way without the patch.
2026-10-23 16:15:59 -04:00
MaxsTechReview 9010d275ab fix(steam): the last change to a game's compatibility tool wins (#1347)
Refs #1248

## Problem
Users report that changing a game's compatibility tool in Steam's game
properties doesn't stick: it goes back to DroidDeck's default. #1248 was
closed by #1250, but its reporter still saw it after clearing the game's
DroidDeck profile.

A game's tool can be chosen in two places, DroidDeck's per-game Proton
(`games.json`, written by `ProtonDefault.requestGame`) and Steam.
`plan_mapping` treats every `games.json` entry as an override that
always wins, so the live helper (`droiddeck-steam-compat`, on
`CompatManager.NotifyStateChanged`) sets it back within a second, and
`steam-compatibility` does again at every session start. A `null` entry
("use the default", also written by a profile reset) is forced as the
default, so resetting the profile made it worse.

Reproduced with the real `plan_mapping` (game 220, Steam set to
`droiddeck-fex`):

| `games.json` entry | before |
|---|---|
| none | kept |
| `null` (profile reset / "Default") | reverted to default |
| a DroidDeck Proton | reverted to it |

## Change
Whichever side changed a game's tool last wins:
- A DroidDeck choice is applied once (as now). Once applied, a different
pick in Steam stands:
- a pick of one of DroidDeck's Protons becomes the DroidDeck choice too
(`games.json` updated, so the app shows it);
- any other pick (FEX, a Steam Linux Runtime, clearing the forced tool)
removes the game from `games.json`.
- `null` is applied once and then dropped, so the game follows the
default like one DroidDeck never managed.
- What was applied is kept in `state.json` as `games_applied`. Choices
an earlier build already applied count as applied (when `state.json` is
from an earlier build), so upgrading respects the Steam picks users
already made.
- `games.json` is rewritten only if the app didn't replace it after it
was read, so a newer app choice is never overwritten.
- An x86-only Valve Proton picked in Steam is still replaced
(`unrunnable`), unchanged.

Both paths share the logic: `register_default` (session start, reads
config.vdf; with the client stopped, an app missing from the mapping
counts as cleared) and the live helper's `reconcile`.

## Tests
- `test_steam_compat_live.py` + `test_game_environment.py`: 109 pass
locally (103 existing + 6 new). The 6 new tests fail on the old scripts.
- Steam pick after an app choice is kept live, and a new app choice
applies again
  - Steam pick of a DroidDeck Proton becomes the app's choice
  - "use the default" applies once, then Steam picks stand
  - upgrade: choices an earlier build applied give way to Steam picks
  - an app choice written during a sync is not overwritten
  - session start keeps a Steam pick from config.vdf

Not device-tested.

## Side note: `test_authorship` writes into the global git hooks
`InstalledHooksTest.setUp` runs
`tools/release/install_authorship_hooks.py` in a temp repo, but the
installer reads `core.hooksPath` from the **global** config. On a
machine with a global hooks path, running the suite replaced the user's
global `commit-msg`/`prepare-commit-msg`/`pre-push` with hooks pointing
into the deleted temp repo (every later commit failed), and the saved
originals were deleted with the temp repo. The test should isolate
`HOME`/`GIT_CONFIG_GLOBAL`. Not changed in this PR.
2026-10-23 16:13:28 -04:00
maxjivi05 3e85e4a614 chore: drop comments 2026-10-23 15:51:06 -04:00
maxjivi05 a4abb797a7 Merge remote-tracking branch 'origin/main' into fix/steam-compat-pick-wins 2026-10-23 15:51:00 -04:00
maxjivi05 f909c7a69c fix: x86 Linux games under FEX keep LD_PRELOAD libraries given by name
droiddeck-fex dropped every LD_PRELOAD entry that was not an existing path, so a bare soname the loader finds through LD_LIBRARY_PATH (MelonLoader's bootstrap in Drova, for one) never reached the game. Names without a slash are now kept; missing paths and arm64 libraries are still dropped.
2026-10-23 15:44:35 -04:00
coffeemeist3r 5d1e70cd20 Keep FEX's TSO on for Unity games
A FEX preset that turns TSO off (Performance, Extreme, Extreme-gn, Denuvo)
breaks Unity players under FEX:
- Megabonk (Unity 2023.2, IL2CPP, native Linux build, "Linux x86 (FEX)")
  froze on about half of its launches, every thread parked on a futex.
  With TSO on: 5 of 5 starts, and a played run stayed responsive.
- Crab Game (Windows IL2CPP build under Proton arm64) crashed on 1 of 5
  starts with an access violation in UnityPlayer.dll on a garbage pointer.
  With TSO on: 5 of 5 starts.

A Unity player (UnityPlayer.dll, UnityPlayer.so or GameAssembly.so beside
the executable) now keeps FEX_TSOENABLED=1 over the shared preset, the way
.NET games already keep full TSO. The FEX tool applies the environment half
of the game-file fixes too, so native Linux builds get it as well. A FEX
preset chosen for the game itself still wins.

Related: #1386 (its Mono crash happens with TSO already on)
2026-10-23 13:38:59 -05:00
0x1Nawaf 7c51e6e904 fix: draw the gamescope cursor only when that option is on
The extra plane costs frames on a phone, so compositing stays off unless Performance asks for it.
2026-10-23 13:30:42 -04:00
Kurt Himebauch b76f13f7ac fix: keep the shader pre-caching choice until a session confirms it, and read it from its own VDF section 2026-10-23 13:05:04 -04:00
Kurt Himebauch f88227ed74 feat: toggle Steam shader pre-caching from DroidDeck's Steam settings 2026-10-23 13:05:04 -04:00
ovurrsl 70eec3cc32 fix: a half-built steamrt shim is removed, and its launcher accepts --directory DIR 2026-10-23 12:03:41 -04:00
ovurrsl 7aeb7779bb fix: fall back to Valve's stable Steam client when the beta one keeps failing
The native arm64 client follows steamdeck_publicbeta, so a Valve beta
regression reaches every user at once. If the repaired beta client is still
started twice without being shown, or the beta manifest carries no arm64
client, droiddeck-steam-install now installs steamdeck_stable, keeps it, and
logs why (listing the manifest's blocks in the second case). The session asks
the installer for the channel, so -clientbeta and package/beta stay in sync.
BL_STEAM_CHANNEL or ~/.config/droiddeck/steam-channel (beta|stable) pins it.

Valve's 2026-10-15 beta moved the x86 client into a Steam Runtime container.
In case the arm64 client follows, its session now exports
STEAM_STEAMRT_RECURSION_GUARD=1 and, only if steamrtarm64 carries pv-runtime
or a steam-runtime-check-requirements probe, starts it through the same
steamrt shim the x86-64 client uses (now droiddeck-steamrt-shim) and logs it.
2026-10-23 12:03:41 -04:00
The412Banner 449dc301bd fix(steam): keep the applied record for a game the client did not report, and apply nothing after a lost write
Review: a game the client briefly refused lost its games_applied record, so its
unchanged request later looked new and overwrote the Steam pick; it now keeps
what was applied before. When the app rewrote games.json during both tries,
the stale second read was applied; that pass now applies no per-game choice
and keeps the record.
2026-10-22 22:29:03 +00:00
The412Banner 663da2948c fix(steam): the last change to a game's compatibility tool wins
A game's tool can be chosen in DroidDeck (per-game Proton) and in Steam's
game properties. When they disagreed, DroidDeck always put its own choice
back: the live helper within a second of the change, and again at every
session start. Resetting the game's DroidDeck profile made it worse - it
saved "use the default" (null), which was then forced onto the game.

A DroidDeck choice is now applied once, and the client's later pick stands:
a pick of one of DroidDeck's Protons becomes the DroidDeck choice too, any
other pick (FEX, a Steam Linux Runtime, clearing the forced tool) ends it.
"Use the default" and a profile reset are applied once and then dropped, so
the game follows the default like one DroidDeck never touched. What was
applied is kept in state.json (games_applied); choices an earlier build
already applied count as applied. games.json is rewritten only if the app
did not replace it meanwhile. An x86-only Proton picked in Steam is still
replaced, since it cannot start on the phone.
2026-10-22 22:12:20 +00:00
MaxsTechReview 9a4a611d38 fix: Steam starts again on phones where PipeWire took every client for a sandboxed app (#1338)
PipeWire's access module checks each client's /proc/<pid>/root for a
Flatpak marker. Where that lookup fails under proot (seen on a nubia
NX809J), PipeWire treats the client as sandboxed and holds it until the
session manager grants permissions, and WirePlumber, itself held, never
does. gamescope then waits forever for its capture stream and never
starts Steam: a black screen until the session is closed.

The session's PipeWire now gives both of its sockets unrestricted access
and WirePlumber keeps those clients at full permissions, so nothing
depends on that lookup.
2026-10-22 19:30:35 +00:00
Kurt Himebauch e8a8de1b22 Merge current main into PR #1317 2026-10-22 12:13:54 -04:00
Kurt Himebauch 3a09e5698b fix: stop Steam's Steam Controller welcome tour from opening on every boot (#1321)
* fix: stop Steam's Steam Controller welcome tour from opening on every boot

* fix steam tour failure not to block helper attach
2026-10-22 11:27:59 -04:00
3331edf265 perf: session log step times carry milliseconds (#993)
The == STEP lines in session.log now read HH:MM:SS.mmm, so the setup
steps before Steam starts can be timed; with whole seconds most of them
showed the same time.

Co-authored-by: ovurrsl <ovurrsl@users.noreply.github.com>
Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com>
2026-10-22 10:40:48 -04:00
Jordan Y d9328c39df fix: Game cores also apply to games started through "Linux x86 (FEX)" (#1294)
* Run FEX-tool games on the chosen game cores

Performance > Game cores reached only the Proton launchers: games started
through "Linux x86 (FEX)" ran on every core, including the slowest cluster.

* Test that SteamVR FEX launches keep the game cores
2026-10-22 10:08:25 -04:00
9ed658c45c fix: seed HKCU redist markers in the user registry (#1286)
* fix: seed current-user redist markers in user.reg

* test: skip permission case when running as root

---------

Co-authored-by: Jammo <8018115+kaosjammo@users.noreply.github.com>
Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com>
2026-10-22 10:07:56 -04:00
xXJsonDeruloXx 240b7fcce6 feat: page the session out to zram before suspending it, and zram is always on where supported 2026-10-22 09:02:37 -04:00
MaxsTechReview ed29f77fc2 fix: Chromium browsers start on the desktop (#1280)
A process's status read for another process is served read-only, so
Chromium's ReadOnlyFile check no longer kills the browser. Chromium-based
AppImages without chrome-sandbox get --no-sandbox, and Flathub Chromium and
Electron apps skip zypak's spawn portal, which cannot work here.
2026-10-21 18:17:07 -04:00
Kurt Himebauch e5b54f6248 feat: SteamVR controller types, phone controls on glasses, flat games as VR panels (#1268) 2026-10-21 21:22:21 +00:00
MaxsTechReview bd1350ac25 perf: games skip Steam's install-script evaluator once it has finished (#1273) 2026-10-21 16:59:52 -04:00
Kurt Himebauch e9891d5a29 feat: Remote Play host: PipeWire capture, hardware encoding, touch and game audio (#1139)
* feat: run SteamOS PipeWire and WirePlumber for gamescope screen capture

* feat: hardware Remote Play encoding through MediaCodec behind Steam's V4L2 stage

* feat: deliver Remote Play touches to gamescope as touches

* feat: route game audio through PulseAudio while a Remote Play client is connected

* fix: keep the Remote Play marker when a forked child closes the encoder

* fix: allow standalone preload tests without V4L2 encoder hook
2026-10-21 17:57:24 +00:00
MaxsTechReview 3eb0400df8 fix: clearing a game's compatibility tool in Steam keeps the Linux build (#1250) 2026-10-21 06:07:16 -04:00
MaxsTechReview 11674b711b fix: browsers added as non-Steam games show their window and load pages in Gaming Mode (#1243) 2026-10-21 02:02:18 -04:00
Resul Övür abeaf7ccb6 fix: a failed Steam client download ends the session with a message instead of silently (#997) 2026-10-21 00:56:05 -04:00
Kurt Himebauch 2a8618ab5c feat: launch Easy Anti-Cheat games offline when they support it (#1039) 2026-10-20 18:58:56 +00:00
MaxsTechReview 8ca389149b fix: native Linux games under FEX reach FEXServer, and a refused compat app no longer loops the sync (#1213)
FEX launched through a script (Valve's _v2-entry-point) was judged 32-bit, so the
fast path stayed off in the FEX client while FEXServer bound its socket through it.
The fast path now follows #! lines before judging the program.

The live compat sync drops apps the client refuses GetCompatTools for instead of
reattaching forever.
2026-10-20 14:58:30 -04:00
MaxsTechReview 862afdf0a9 fix: the on-screen pad steps aside while Steam's or DroidDeck's keyboard is open (#1217) 2026-10-20 14:29:50 -04:00
MaxsTechReview b8b3ecf915 fix: a store game's first launch creates its prefix before the cloud save download (#1215) 2026-10-20 14:11:46 -04:00
MaxsTechReview e308224391 fix: RetroArch fills the screen from the emulator rail (#1194) 2026-10-20 10:38:52 -04:00
MaxsTechReview 4f799ea59c fix: open Flatpak apps in renamed app variants (#1192)
Flatpak starts bwrap with an empty environment, so the bwrap shim lost DROIDDECK_BWRAP_SOCKET and dialled the default package's socket. The session now writes the socket name to /etc/droiddeck/bwrap-socket and the shim reads it when the variable is missing.

Fixes #1092
2026-10-20 09:38:14 -04:00
MaxsTechReview b868863133 perf: tile rendering for games, faster session start (#1188)
Games launched from Steam get Turnip's own per-render-pass choice between
tile memory and system memory again; TU_DEBUG=sysmem now stays with the
Steam client, whose interface it was set for. A per-game TU_DEBUG, the
debug override file and the Adreno 710/720 driver still win. On the
REDMAGIC tablet (Adreno 840) PEAK runs 46.8 -> 52.3 fps over 7 alternating
pairs and Valheim's 3D menu needs 12.6 % less GPU time per frame; light
games are unchanged.

droiddeck-seed-redists remembers the identity (inode, size, mtime) of each
prefix registry it has verified and skips re-reading it while it is
unchanged. Steam started after it on every session, ~1.8 s later.

SessionFiles keeps a ledger of the files it staged for the installed APK
and copies only the ones that changed, ~180 ms less per session start.

Session start to Steam ready: 5.57 -> 3.57 s.
2026-10-20 09:19:46 -04:00
MaxsTechReview ca352bf225 fix: RPCS3 opens from the emulator rail again (#1191)
RPCS3's AppImage could not start: its own runtime unpacks the image with
a dwarfsextract it runs from a memfd, which Android refuses (EACCES), and
it has no other way to run it. Emulator AppImages for arm64 now start
through the shipped uruntime, which falls back to a file in /tmp.

RPCS3 then stopped with "Null object" in utils::shm (errno 13): it reads
/proc/sys/vm/overcommit_memory to pick memfd for guest memory, and apps
cannot read it. The guest now gets the kernel's default policy (0) there
when the real file is unreadable, like file-max.
2026-10-20 08:52:31 -04:00
MaxsTechReview bc3715aad6 fix: route ALSA to PulseAudio for x86 Linux games under FEX (no game audio) (#1166)
fix: route ALSA to PulseAudio for x86 Linux games under FEX
2026-10-20 00:44:56 -04:00
MaxsTechReview 79f43d8def fix: GOG games miss the registry entries their install script sets (#1159)
A GOG download only places the files, so games that look up their own registry keys (Fallout: New Vegas reads HKLM\Software\Bethesda Softworks\FalloutNV "Installed Path") said they were not installed. Every GOG launch now reads the setRegistry actions of the game's goggame-<id>.script and imports them into the prefix's 32-bit view through Proton's reg.exe, once per change of the script, so games already downloaded are fixed on their next launch.
2026-10-20 00:38:08 -04:00
MaxsTechReview fd74819c50 fix: Steam no longer sleeps again right after a paused session resumes (#1162) 2026-10-19 23:06:48 -04:00
MaxsTechReview da916e7ed7 fix: give x86 programs under FEX the runtime's OpenSSL 3 (libcrypto.so.3 not found) (#1167)
fix: give x86 programs under FEX the runtime's OpenSSL 3
2026-10-19 21:27:25 -04:00
MaxsTechReview cfc6dfb05f fix: let x86 apps under FEX use the device's fonts (Epic launcher CJK text shows boxes) (#1168)
fix: let x86 apps under FEX use the device's fonts for CJK text
2026-10-19 21:27:18 -04:00
Kurt Himebauch 7eae6ca3e7 Restrict Xbox credential IPC and address launch review findings (#1164)
* Restrict Xbox credentials to host backends and lease game launches

* Verify mapped PRoot backend images and retry lease heartbeat timeouts

* Bound Xbox backend shutdown and isolate service socket lifetimes

* Keep unique Xbox service sockets within Unix address limits

* Own licensed launch directories and recover abandoned views safely

* Serialize Xbox account revocation with sign-in commits and launch authorization
2026-10-19 20:10:54 -04:00
Kurt Himebauch a63f3b1fbc Add experimental Xbox and PC Game Pass store support (#1156) 2026-10-19 18:44:10 -04:00
Kurt Himebauch adcb04f624 fix: skip DirectAudio for Steam install scripts (#1046) 2026-10-19 14:19:10 -04:00
Kurt Himebauch 2ea86b4abb fix: run x86 Proton under FEX in the Steam runtime it requires (#1034) 2026-10-19 14:18:52 -04:00
Kurt Himebauch a789d60f6a fix: register SteamVR only during a DroidDeck VR session (#1137) 2026-10-19 12:31:23 -04:00
MaxsTechReview 5c07c122fe Steam x86-64 client: menus come up, sign-in stays put, games listed once (#1096)
* Steam x86-64 client: menus come up, sign-in stays put, games listed once

Switching the Steam client from arm64 to x86-64 left the client on a blank
screen behind "Downloading the Steam client update 100%", and each switch
signed one of the clients out.

- The x86-64 client is Valve's steamrt64 platform, but it was installed and
  synced from the ubuntu12 manifest, which lags it (1792108788 against
  1792192922). The client was therefore never the arm64 client's build, the
  arm64 web helper was never used, and the client then updated itself in
  place after the helper had been chosen. Install, sync and the build check
  now read the steamrt64 manifest.
- The x86 web helper's GPU process loads libpci, which exits when
  /sys/bus/pci/devices lists a device whose files the app may not read (a
  RedMagic's PCIe root ports). Every GPU process exited with status 1, even
  in software, until Chromium gave up and the menus stayed blank. An empty
  folder is bound over /sys/bus/pci/devices on such devices.
- Steam refuses one client's login token from the other ("Invalid
  Password" for a token the arm64 client signed in with minutes before), so
  copying the newer token at every start signed the other client out. Each
  client now keeps its own token; a client with no accounts only gets the
  other's account list.
- Games could be listed twice: an added game whose folder a Steam import
  already covers is now shown as that Steam game only, a client switch
  drops the old client's imported entries, an import stays one when its
  ownership cannot be confirmed instead of gaining a shortcut beside it,
  and only the client's own library folders count as an install.

* Steam x86-64 client: share the arm64 sign-in again

The x86-64 client refused the arm64 client's login token because it did
not know the account's SteamID: it takes it from Accounts in
config/config.vdf, which this script creates without one. It logged on as
[U:1:0] with a valid token, Steam answered "Invalid Password", and the
client dropped the token and AutoLoginUser, so every switch asked for the
password.

The newer sign-in is copied between the clients again, each start adds
the accounts either client knows to the other's config.vdf, and an
AutoLoginUser or RememberPassword one client lacks is filled in. Device:
the x86 client signs in with the arm64 token on a fresh install and on an
install left signed out, and the arm64 client stays signed in.
2026-10-18 20:38:48 -04:00
Resul Övür 25082786aa fix: added games are handed to Steam right away and retried only if they never take focus (#994) 2026-10-18 14:59:39 -04:00
Kurt Himebauch 5d07c575e2 fix: skip DirectAudio setup for Proton queries (#1044) 2026-10-18 14:21:46 -04:00
MaxsTechReview 64a4cc887c fix: only start SteamVR for VR-only games from Steam's library (#1076)
Games that merely support VR (No Man's Sky) were held at Play while
DroidDeck downloaded and started SteamVR, so they always opened in VR.
They now launch normally; VR-only games still wait for SteamVR.
2026-10-18 09:26:01 -04:00