Commit Graph
294 Commits
Author SHA1 Message Date
maxjivi05 aefd8a3b60 fix(xbox): report a failed class registration in the launch log 2026-10-24 11:14:20 -04:00
maxjivi05 fee8ce91f3 fix(xbox): register the runtime's WinRT classes and load its wintypes so Minecraft starts 2026-10-24 11:14:20 -04:00
maxjivi05 a66d7d74a4 fix: Steam Input mouse clicks, scrolling and pointer moves reach games again 2026-10-24 09:07:04 -04:00
maxjivi05 0b671b2144 fix: match an annotated overlay header and keep the settings file's mode 2026-10-24 06:27:46 -04:00
maxjivi05 31cead9b32 fix: keep blank lines inside the overlay section and stage settings under a unique name 2026-10-24 06:27:46 -04:00
maxjivi05 26c3dcc885 fix: turn off the Ubisoft Connect overlay so Ubisoft games stop crashing at start 2026-10-24 06:27:46 -04:00
maxjivi05 476642be71 chore: drop the added comments 2026-10-24 01:42:20 -04:00
Nikolay Nadorichev 8c86b718a0 fix: find the signed-in Steam account when loginusers.vdf has no MostRecent
droiddeck-steam-shortcuts and AddedGames.accountConfig took the account
marked "MostRecent" in loginusers.vdf, else the only userdata folder.
The arm64 client here writes no MostRecent, so with two accounts in one
install nothing was picked: no added or store game reached
shortcuts.vdf ("no signed-in account yet; nothing written") and Steam
answered their launch with "App configuration unavailable".

Without MostRecent, take the account marked AutoLogin, then the one with
the latest timestamp. Both sides use the same order so the app reads the
config the guest script writes.
2026-10-24 01:42:20 -04:00
maxjivi05 f89dc04072 fix: Proton's EasyAntiCheat and BattlEye runtimes are not listed as games
Steam installs Proton EasyAntiCheat Runtime (1826330) and Proton BattlEye Runtime (1161040) as tool depots. The launcher's Games tab and the desktop's game entries now skip them like the other runtimes.
2026-10-24 00:47:45 -04:00
maxjivi05 42026b382f fix: keep manifest launch arguments to the installed build and their own additions
The manifest's arguments apply only when its build matches the installed version, only arguments the merge inserted are tracked as its own, escaped quotes split like a Windows command line, and the REDprelauncher rule needs Cyberpunk2077.exe beside it.
2026-10-23 23:59:37 -04:00
maxjivi05 8209a707f4 fix: Caravan SandWitch and Cyberpunk 2077 run at D3D12 feature level 12_1
Feature level 12_2 makes vkd3d-proton report mesh shaders and ray tracing that Turnip doesn't provide. Caravan SandWitch (Unreal Engine 5) then builds mesh shader pipelines without a pipeline layout and the driver crashes; Cyberpunk 2077 stops at ray tracing initialization. Only these two games get 12_1, and a value set in a game's own settings still wins.
2026-10-23 23:59:37 -04:00
maxjivi05 6e1621fe53 fix: Steam's Ubisoft games install Ubisoft Connect again
The redistributable seeder marked every process in a game's install scripts as already run, so the Ubisoft Connect installer that Ubisoft games list was skipped and they stopped with "Unable to locate Uplay PC". It is now left to run like the Vulkan runtime installer, and a marker an earlier seeding wrote is taken back out.
2026-10-23 23:58:39 -04:00
maxjivi05 96e2bf992d fix: an HTTP 4xx part hands over to the next CDN at once 2026-10-23 21:20:50 -04:00
maxjivi05 4a57c6f6f1 chore: drop the comments this change added 2026-10-23 20:45:14 -04:00
maxjivi05 2d9d4dbeb0 Merge branch 'main' into fix/steam-client-download
# Conflicts:
#	tools/linuxfs/overlay/usr/local/bin/droiddeck-steam-install
#	tools/tests/test_steam_install.py
2026-10-23 20:23:44 -04:00
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
MaxsTechReview 8f0bd51fd8 Merge pull request #1401 from Droid-Deck/perf/ntsync-fast-paths
## Summary

droiddeck-ntsync (the userspace stand-in for the Linux ntsync driver,
Wine sync = ntsync) was slower than droiddeck-esync on every cheap
operation. On the tablet a `SetEvent` cost 0.94 µs against esync's 0.21
µs, and a wait on a signaled event 0.45 µs against 0.08 µs. Four things
made it slow:

- **Signal masking:** every operation blocked and restored the signal
mask, so each call made 2 `rt_sigprocmask` syscalls, and a blocking wait
made 4. The masking itself is needed: if Wine's suspend signal stopped a
thread while it held an object lock, a GC thread that suspended it and
then touched the same object would deadlock.
- **Queueing for objects that were already free:** a wait linked itself
onto every object and unlinked again even when the first object could
simply be taken.
- **Wakes nobody needed:** a futex wake syscall went out for every
handoff, even when the waiter was still spinning and would have seen the
change anyway.
- **One shared counter:** every call took and dropped a reference on a
single process-wide device counter, so threads working on unrelated
objects bounced one cache line between cores.

### Changes

- **Signals are deferred instead of masked:** handlers installed by
Wine's `ntdll.so` run behind a small trampoline. If such a signal
arrives inside a critical section (a per-thread depth count), it is
saved with its `siginfo` and sent again with `rt_tgsigqueueinfo`
(falling back to `tgkill`) as soon as the section ends.
  - `sigaction` queries still return Wine's own handler.
- Synchronous signals (SEGV, BUS, ILL, FPE, TRAP, SYS) are never
wrapped, as before.
  - Handlers installed by anything other than `ntdll.so` are left alone.
- **Wait-any fast path:** an object that is signaled and has nobody
queued on it is taken directly, in index order. A wait whose timeout has
already passed returns `ETIMEDOUT` without building a queue.
- **Short spin before sleeping:** a waiter spins for up to 4 µs, bounded
by time rather than by iteration count, before it sleeps on the futex.
- **Wake only sleeping waiters:** the waiter publishes a `sleeping`
flag, and the waker only calls `FUTEX_WAKE` when it is set. Both sides
use seq_cst ordering, so a wake can't be lost. The queue layout changed,
so `NS_VERSION` is now 2.
- **Per-thread device reference:** a thread takes one reference on the
device the first time it uses it and keeps it until it exits or moves to
another device, instead of two atomics on the shared counter per call.
- **More than four signals in one section:** a fifth distinct signal is
held pending with the thread's signal mask, then released once the
section ends. Its handler never runs while an object lock is held.
- **Replay:** deferred signals are replayed with every signal blocked,
so each one is sent exactly once. A held signal is released at the same
signal-nesting level that held it. Handlers installed with
`SA_RESETHAND` are not wrapped, so a one-shot handler keeps its kernel
behaviour.
- **Waits from a handler during another wait's sleep:** they get their
own queue and, for a second device, a reference for that call only. The
outer wait keeps its queue and can't pick up the inner wait's result.

### ntsync becomes the default

- **New installs:** start on ntsync.
- **Existing installs:** move to ntsync once, on the first start of this
version, whatever sync they were on before (a one-time `ntsyncDefaultV1`
marker). Anything picked after that is kept, including esync, fsync and
wineserver.
- **Wording:** the ntsync switch in Performance no longer says
"experimental" or "for testing", in all 33 languages.
- **Unchanged:** per-game sync choices on a game's settings page still
win over the app-wide choice. Proton builds without ntsync still fall
back to droiddeck-esync, then droiddeck-fsync.
- **Tests:** `SyncBackendTest` covers a fresh install, each earlier
choice moving to ntsync once, and a later choice surviving the next
start. All 2,160 unit tests pass.

## Performance (REDMAGIC tablet)

Windows microbenchmark (`syncbench.exe`, x86-64 under FEX), µs per
operation:

| | esync | ntsync before | ntsync after |
|---|---|---|---|
| SetEvent | 0.57 / 0.70 | 0.51 / 0.65 | 0.38 / 0.35 |
| wait on signaled event | 0.13 / 0.13 | 0.44 / 0.43 | 0.27 / 0.20 |
| wait, timeout 0 | 0.27 / 0.25 | 0.52 / 0.51 | 0.19 / 0.18 |
| semaphore release + wait | 0.72 / 0.68 | 0.66 / 0.63 | 0.12 / 0.16 |
| mutex wait + release | 0.77 / 0.73 | 0.66 / 0.64 | 0.12 / 0.12 |
| wait on 8 objects | 0.10 / 0.09 | 0.59 / 0.57 | 0.15 / 0.15 |
| alertable wait | 0.06 / 0.05 | 0.43 / 0.42 | 0.07 / 0.07 |
| event ping-pong, 2 threads | 25.6 / 24.5 | 24.4 / 29.3 | 1.97 / 1.66 |
| 4 threads on one semaphore | 9.4 / 4.6 | 20.3 / 19.1 | 7.3 / 7.6 |

The backend each run actually used was checked from its file
descriptors:
- **esync:** wineserver held eventfds.
- **ntsync:** wineserver held the `droiddeck-ntsync` device and its
timerfd objects.

Native arm64 benchmark against the device directly, µs (before / after):
- set: 0.31–0.36 → 0.06–0.08
- signaled wait: 0.37–0.45 → 0.04–0.08
- semaphore pair: 0.56–0.58 → 0.06–0.07
- mutex pair: 0.56–0.61 → 0.04
- ping-pong: 15–30 → 1.7–2.5

Removing the shared device counter on its own takes 4 threads working on
their own objects from 0.21 to 0.04 µs per operation (x86-64 host).

Games, default Steam launch, The Forest and PEAK at the same scene each
run, 20 s pacing. Columns are esync, ntsync before and ntsync after;
each cell gives two runs.

| | esync | ntsync before | ntsync after |
|---|---|---|---|
| The Forest Low, fps | 64.5 / 61.9 | 70.1 / 74.8 | 72.1 / 72.1 |
| The Forest Low, CPU | 489 / 511% | 434 / 419% | 436 / 426% |
| The Forest High, fps | 58.3 / 57.8 | 72.0 / 69.8 | 72.5 / 69.9 |
| The Forest High, CPU | 506 / 504% | 417 / 429% | 425 / 435% |
| PEAK, fps | 50.4 / 48.6 | — | 47.0 |
| RDR2, launch to signed in / game process | — | — | 29.2 / 42.0 s and
28.3 / 41.1 s |

Two more games, esync against ntsync after, three runs each, default
settings:

| | esync | ntsync after |
|---|---|---|
| Among Us, menu fps (59 cap) | 59.0 / 58.9 / 59.3 | 59.0 / 59.0 / 58.7
|
| Among Us, launch to main menu | 6.65 / 6.84 / 6.85 s | 6.39 / 6.52 /
6.64 s |
| Among Us, CPU | 123 / 132 / 133% | 133 / 133 / 124% |
| Mortal Kombat X attract fight, fps | 56.7 / 54.1 / 56.3 | 61.1 / 56.9
/ 56.2 |
| Mortal Kombat X, 1% low | 20.0 / 30.3 / 30.3 | 30.3 / 30.3 / 30.3 |
| Mortal Kombat X, launch to window | 7.75 / 7.79 / 7.75 s | 7.81 / 7.71
/ 7.63 s |

Mortal Kombat X's CPU moves between 140% and 275% in both modes because
the attract mode changes fighters and stage, so it isn't compared.

The Forest's 1% low was 41.7 fps in every run. PEAK is GPU-bound and
stays in run-to-run noise. Its second ntsync run stopped at the title
menu because the rig's menu input didn't register; the game was still
running at 87 fps, and the same rig miss happened on esync before. RDR2
signs in and reaches the game on the new code.

## Tests

- **`tools/tests/test_ntsync_preload.py` (new):** builds the preload and
checks the emulation against the semantics documented for the kernel
driver:
  - semaphore counts and `EOVERFLOW`;
- mutex owners, recursion, `EPERM`, kill/abandon with `EOWNERDEAD` on
read and on the next wait;
  - auto and manual events, set/reset/pulse previous state;
- wait-any index order, duplicates, the alert object, `EINVAL` limits,
timeouts;
  - wait-all atomicity, duplicates and alert;
- wakes across threads and across processes (inherited fds and fds sent
with `SCM_RIGHTS`);
- 20,000-round ping-pong and 4-thread semaphore stress with infinite
timeouts;
- two signal cases. In one, a handler that re-enters the same object is
fired 2,000 times at a busy thread. In the other, a handler parks the
thread while another thread uses the same object, as Wine's suspend does
under a GC.
- eight real-time signals fired in bursts at a thread busy on one
object, each handler touching that object, so more signals arrive inside
a section than can be deferred;
- a handler that waits on the same device and on a second device while
its thread sleeps in another wait;
- a one-shot (`SA_RESETHAND`) handler installed and fired 300 times at a
busy thread, every one of which must run.
- **The signal tests catch a broken implementation:** with signal
protection removed, the program hangs and the test fails. Before the
last fix, the burst test hung and the outer wait returned the nested
wait's result.
- **The suite passes:** 8 of 8 runs natively on arm64 under proot on the
tablet, and 40 of 40 on the host.
- **On the final build:** The Forest Low ran at 77.7 fps, PEAK at 47.5
fps, and Among Us and two Mortal Kombat X runs played through.
- **The new paths stay out of the way in games:** a build that logged
them saw about 1,400 Wine signals land during ntsync sleeps over two
Mortal Kombat X runs and one The Forest run. None of those handlers
waited on ntsync and no signal was held back, so games run the same code
as before the last fix. The Forest Low ran at 71.6 fps and PEAK at 47.2
fps on the final build.
- **Existing preload tests still pass:** fsync, openat2, usr2 (also with
`BL_SYNC=1`), tracer, dircache, noexec, binfmt, faultreport and esync
packs.

## Credits

- [Linux](https://github.com/torvalds/linux)
`Documentation/userspace-api/ntsync.rst` (GPL-2.0): the object, wait and
error semantics the new test checks. Also added to the README credits.
2026-10-23 15:10:28 -04:00
maxjivi05 9438aac0db fix: droiddeck-ntsync leaves one-shot handlers alone and replays deferred signals exactly once
- Handlers installed with SA_RESETHAND are no longer wrapped, so a deferred one-shot signal can't fall through to the default action.
- Deferred signals are replayed with every signal blocked, so a signal landing mid-replay can't send an entry twice.
- Taking a deferral slot and holding a signal are safe when one signal interrupts another, and a held signal is released only at the nesting level that held it, so a handler's return can't block it again.
2026-10-23 14:55:33 -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
maxjivi05 77dd04ec8c fix: droiddeck-ntsync keeps protection when more than four signals arrive and keeps waits intact when a handler waits again
- A fifth distinct signal inside a critical section is now held pending with the thread's signal mask and released once the section ends, instead of running its handler while an object lock is held.
- A wait from a signal handler during another wait's sleep uses its own queue and, for a second device, a reference for that call only, so the outer wait keeps its queue and can't return the inner wait's result.
2026-10-23 12:15:43 -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
maxjivi05 4bcd4e3cca perf: droiddeck-ntsync without signal-mask syscalls, waits that skip the queue, and per-thread device references 2026-10-23 10:48:06 -04:00
Kurt Himebauch a25081df7c Merge branch 'main' into fix/steam-client-download 2026-10-23 10:16:19 -04:00
MaxsTechReview ac0909eaa3 perf: let Wine read process memory counters from /proc directly (#1374) 2026-10-23 07:18:56 -04:00
MaxsTechReview ffa40a15d5 perf: run Wine's arm64 SIGUSR2 context switch without a kernel signal (#1371) 2026-10-23 02:12:49 -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 f27d0b006f perf: Wine's write watches stop costing a signal per page on arm64 (#1333)
Wine asks for userfaultfd with the i386 syscall number on arm64, so it
never gets one and falls back to mprotect and a SIGSEGV per first write,
which under proot is a ptrace stop each time. libblsession hands it the
real userfaultfd and, where Android refuses the PAGEMAP_SCAN ioctl, answers
it from /proc/self/pagemap and UFFDIO_WRITEPROTECT.
2026-10-22 19:53:12 +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 8c0fcd8475 Merge current main into PR #1317 2026-10-22 13:11:09 -04:00
Kurt Himebauch bde9ca733f Merge current main into PR #587 2026-10-22 13:11:02 -04:00
Kurt Himebauch e4a7e52f81 Fix nested KWin rendering on Android (#1330)
Select the explicitly configured Android render node for nested KWin 6.8, apply OpenGL settings before Plasma starts, and pin the original signed Mesa 26.2.4 package that passed Thor rendering. Remove build-directory runtime search paths and fail closed on ELF inspection errors.

Native ARM64 build passed. Thor validated a visible nested Wayland terminal, active OpenGL ES/Zink on Turnip, 1280x720 output, and keyboard input. Mesa pin regression tests, launcher and ELF failure controls, shell syntax, and human authorship checks passed. Published desktop pin remains r2; full latest-head CI is pending and maintainer authorized this merge after device validation.
2026-10-22 13:10:16 -04:00
Kurt Himebauch e8a8de1b22 Merge current main into PR #1317 2026-10-22 12:13:54 -04:00
Kurt Himebauch 0819aa725d Merge current main into PR #587 2026-10-22 12:13:46 -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 1b14939731 fix: suspend page-out waits for each handler's ack and can be cancelled 2026-10-22 10:01:49 -04:00
xXJsonDeruloXx c8cc17bf3a Merge main into Steam client download PR 2026-10-22 10:01:34 -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