Commit Graph
201 Commits
Author SHA1 Message Date
MaxsTechReview 4fa467c800 Fetch the Steam client again when it never shows up (#225)
A client stopped part way through updating itself can be left unable to
draw anything. Its files and our install stamp are still on disk, so the
installer never looked at it again and every session sat on "Waiting for
Steam" with nothing retried.

The session now adds a line to package/droiddeck-unconfirmed each time it
starts the client, and the app removes the file on the client's first
frame. After two starts in a row with nothing shown, the installer:
- drops Steam's update manifests, the stamp, .crash and steam.pid
- deletes package zips whose sha1 no longer matches their name
- downloads the client again over the old one

steamapps, config and userdata are left alone. An automatic repair runs
once per failure, until a start is seen again.

The Steam page's Client settings get a "Repair Steam client" item that
queues the same repair for the next start. The request is only cleared
once the download completes, so an interrupted repair is retried.
2026-10-04 21:33:16 -04:00
MaxsTechReview 6dc74523c3 Start every title with a Valve pick on the Compatible Proton (#224)
The client runs in Steam Deck mode, where a title's "Default" is not the
"0" mapping but Valve's own pick for it: the Steam Deck compatibility
recommended_runtime (proton-stable, a pinned Proton, or native for the
Steam Linux Runtime) or an app_mappings entry in the SteamPlay manifests.
A title the session had not mapped yet - not installed, or installed
while the client was running on a build without the live helper - showed
"Default (Proton Stable)" and launched with a Proton that cannot run
here.

Every playable Windows title in the appinfo cache with such a pick is now
mapped to the default tool up front, before the client starts and in the
live helper, the same way installed titles are. A runnable tool the user
picks for one of them is kept, and they follow a change of the default.
2026-10-04 13:44:10 -04:00
MaxsTechReview 49a5f4aa94 ESync, FSync, NTSync + OpenNow + FEX for Desktop Apps (#197)
* Make the Compatible Proton ARM64 the default and label compatible builds

The CompatToolMapping "0" default always points at DroidDeck's Proton
ARM64 tool, and per-game picks of adopted GE/CachyOS builds are kept,
including when the shortcuts writer remaps.

The tool is named after the Proton build it runs, Proton Experimental
ARM64 (Compatible), or Proton 11.0 ARM64 (Compatible) once that newer build
is installed. Adopted builds carry the same Compatible mark, read from a
string resource the app stages into the runtime, and the Proton page
explains which builds have the prefix fixes.

The registrar is renamed steam-compatibility and the tool
droiddeck-proton-arm64. Existing installs migrate on the next session: the
old tool directory is removed, every mapping that named it moves to the new
tool, and the retired bannerlator-steam-compat script is removed from the
runtime. CI and local packaging include the renamed script.

* Drop the duplicate R import left by merging main

* Add userspace ntsync for Proton on Android

Android kernels have no /dev/ntsync and its app policy refuses futex_waitv,
so every Proton 11 build here fell back to wineserver for every wait.
libblsession now serves /dev/ntsync itself: wineserver opens a memfd region,
each sync object is a timerfd that carries its slot, and the kernel ntsync
ioctls are answered in shared memory with futexes, following the kernel
driver's wake order. Valve's Proton Experimental ARM64, GE-Proton and
proton-cachyos use it unchanged.

Locks record their owner so a killed process cannot wedge the others,
signals are held off inside each critical section, dead processes and
exiting threads are swept, and object lifetimes follow close, dup2, dup3,
close_range and received descriptors.

Fast sync is on by default under Performance > Session fixes, and
PROTON_NO_NTSYNC=1 turns it off per game.

* Add droiddeck-esync as the default sync for Proton on Android

Without a kernel ntsync driver, Proton 11 builds here fell back to
wineserver for every wait. droiddeck-esync brings eventfd and shared-memory
sync to the exact Proton build a game runs on: a pack holds that build's
ntdll.so and wineserver with the patch series in tools/droiddeck-esync
applied, and the guest runs Proton from a shadow tree that links the stock
tool and swaps in those two files. A wineserver from a pack still prefers
/dev/ntsync when a kernel driver or droiddeck-ntsync is there.

Packs are built in Valve's SDK image from each release's own wine source
(Proton Experimental ARM64 tags, GE-Proton and proton-cachyos releases); the
control build must reproduce the release binaries byte for byte, and a
signed index lists the packs. The APK bundles the packs pinned in
release.env, the app fetches newer ones, and Steam's compatibility tool
picks the pack for each Proton build, so new Proton releases get packs
without an app update.

The ntdll side reads, writes and polls its eventfds with raw system calls,
so the guest's LD_PRELOAD wrappers stay out of the sync path. The server
abandons a mutex once a thread killed by TerminateThread has really exited
and when its process dies, and a mutex's owner and recursion count change
in one atomic step, so a killed owner cannot touch the next owner's count.

droiddeck-esync is on by default and PROTON_NO_ESYNC=1 turns it off per
game; droiddeck-ntsync, the userspace ntsync, is now an opt-in toggle.

* Watch Valve's Proton releases and build droiddeck-esync packs for them

A scheduled workflow reads the Proton ARM64 builds Steam ships (anonymous
steamcmd app info) and the upstream source tags, compares them with the
previous watch state and starts the pack build for any build that has no
pack yet. The pack build applies the patch series with --fuzz=0 and runs a
smoke test of each new pack against the esstress suite before it is
published.

* Add droiddeck-fsync, keep Steam and the app on one Proton, fix DirectAudio

droiddeck-fsync: libblsession answers futex_waitv(2), which the app
sandbox refuses, in userspace, so Proton's own fsync runs on the stock
Proton files with no pack. Waiters register the words they wait on in a
table beside the fsync shared memory and sleep on a futex of their own;
FUTEX_WAKE on the fsync memory wakes the registered waiters. Slots carry
one owner word that the sweeper and the owner claim with a CAS, and the
mapping table is rebuilt under a lock held across the real munmap, so a
reused address or a recycled slot cannot lose a waiter. It stands in for
a Proton build without a pack (droiddeck-ntsync where fsync is off), takes
over for games with esync off, and the "droiddeck-fsync first" toggle
(BL_FSYNC_FIRST, also per game) puts it ahead of the packs. The games
Proton keeps off fsync and esync never get it. A launch into a prefix
whose wineserver is still running keeps that server's sync choice.

One Proton for Steam and the app: the Components page's Proton is the
default Steam uses, applied live through the client while Steam runs
(droiddeck-steam-compat) and at the next start otherwise; a choice made in
Steam's menu comes back to the app. Requests are ordered by a sequence that
never goes backwards, and the page no longer jumps back to the default
after a swap or restore.

DirectAudio: the wrapper wrote the driver key with its backslashes
stripped, so no game ever used DirectAudio. Wine 11 also loads a builtin
only from the prefix, so the driver is now linked into system32 and
syswow64 before "directaudio,pulse" is selected; mmdevapi falls back to
winepulse whenever DirectAudio cannot start.

* Pick esync, ntsync or fsync from the Steam settings' Games group

A three-way tab row above the FEX preset sets the sync Proton games use. It
writes the existing switches together (droiddeck-ntsync, droiddeck-fsync
first, droiddeck-esync), so the Performance toggles and the tabs always agree,
starts on esync and keeps the choice until it is changed again.

* Make droiddeck-fsync the default sync for Proton games

A fresh install, or one that never picked a sync, starts on fsync; a choice made
in the Steam settings' Games group still sticks. Games Proton keeps off fsync
still fall back to droiddeck-esync.

* Add wineserver to the Wine sync tabs and order them ntsync, fsync, esync, wineserver

wineserver turns every in-process sync off so games wait through wineserver;
picking any other tab turns sync back on. The tabs shrink to fit a narrow pane.

* Shorten the Wine sync description

* Answer openat2 and execveat for FEX in the session preload

FEX opens every file of its x86 rootfs with openat2(RESOLVE_IN_ROOT) and
only falls back to the host path on EXDEV. Under proot on Android openat2
answers ENOSYS, so each lookup of an x86 library silently went to the host
and missed. The exported syscall() now turns openat2 into openat once the
real call reports ENOSYS: RESOLVE_IN_ROOT paths are taken relative to the
root fd (FEX has already resolved the links inside the rootfs), and an
absolute path under RESOLVE_BENEATH fails with EXDEV as the kernel would.

execveat with an absolute path, or relative to AT_FDCWD, and without
AT_EMPTY_PATH or AT_SYMLINK_NOFOLLOW, is plain execve; it is sent as such
because proot refuses execveat with a directory fd, which FEX uses when it
re-executes itself for a child x86 program.

* Run x86 Linux games and programs through FEX

Steam: Linux-only titles that have no ARM64 build (from the client's
appinfo cache: type game, demo, application or beta) are mapped to a new
compatibility tool, droiddeck-fex ("Linux x86 (FEX)", linux to linux,
no required runtime). Valve's own "fex" tool needs pressure-vessel, which
cannot run under proot, so a mapping to it or to a Steam Linux Runtime is
replaced; any other pick the user made stays. Titles that also ship for
Windows stay on Proton. When such a title is installed and FEX or the
sniper runtime is missing, the client is asked to install them.

droiddeck-fex runs the program under the FEX that Steam installs (app
3127680), with Steam Linux Runtime 3.0 (sniper, app 1628350) as the x86
rootfs:
- the sniper platform is linked in place from its usr-mtree (relative
  links only, files/usr -> .), once per runtime version;
- the x86_64 and i386 builds of libblsession and libfakeinput go into the
  runtime's lib/<triplet>/droiddeck and its etc/ld.so.preload, mirroring
  the session's own list, so x86 programs get the pads and the session
  fixes (FEX passes their system calls straight to the kernel, so the
  ARM64 preloads cannot reach them);
- Config.json sets RootFS and the GL and Vulkan thunks, so x86 games draw
  with the device's Turnip and Mesa;
- the FEX preset and the game's own environment from the Steam settings
  apply, and ARM64 entries are dropped from LD_PRELOAD/LD_LIBRARY_PATH.
It also links ~/.steam/sdk64 and sdk32 to the client's x86 steamclient
when the client has one and nothing is there yet.

Desktop: x86_64 and i386 AppImages can be imported now; they unpack
through FEX (or unsquashfs) and record their architecture. Scripts,
AppImages and programs started in a run session use FEX automatically
when they are x86, and each added app has a "Use FEX" Auto/On/Off choice
in its edit dialog. The launchers' "still running" checks also look at
FEX processes, whose exe is FEX rather than the program. A GitHub release
without an ARM64 AppImage falls back to its x86_64 one. Decky's x86
loader starts through droiddeck-fex instead of the fex-mesa rootfs path,
which no runtime ships.

The x86 preloads are built against glibc 2.31 (Debian 11) so they load
in sniper: tools/linuxfs/build-x86-preloads.sh, run in CI and by
build_local.sh. fakeinput's stat hooks fall back to __xstat on a glibc
without a stat export, and mmap64 takes off64_t for the i386 build.

* Keep a FEX unixlib from outliving its DLL

A FEX package or original bundle without the aarch64-unix helpers left
the previous version's libarm64ecfex.so / libwow64fex.so in the Proton,
so the new DLLs loaded a unixlib built for another FEX. A swap now removes
the helpers the package does not carry; FEX then runs DLL-only, which it
already falls back to when Wine cannot load the unixlib.

* Fix the Wine sync choices an audit found

- wineserver tab: it passed Proton's environment through, so a build with
  esync built in (GE, cachyos) still ran esync and a kernel ntsync would
  still be used. It now sets PROTON_NO_ESYNC, PROTON_NO_FSYNC and
  PROTON_NO_NTSYNC (unless the game's own environment sets them).
- ntsync tab: a Proton whose wineserver has no /dev/ntsync client got
  wineserver-only sync although fsync would work. The hash cache records
  whether the wineserver has one; without it the launch goes to
  droiddeck-fsync, and no stand-in or pack turns droiddeck-ntsync on.
- A build with esync built in returned before the per-game fallbacks, so
  a game that turns esync off ran with no in-process sync. It now gets
  droiddeck-fsync, or droiddeck-ntsync where fsync is off too.
- When a pack's proton cannot start and the stock one is used, or the
  selection fails, the prefix's record now says stock, so a second
  launch into the same running prefix no longer picks the pack's ntdll.
- droiddeck-fsync: its mutex is held across fork and re-made in the
  child, a closed or replaced shm fd is forgotten (close, dup2, dup3,
  close_range, closefrom), and a waiter woken while it was leaving on a
  timeout or signal reports the wake instead of losing it.
- BL_SYNC_MIN_NOFILE applies per game to every verb, debug logs carry
  prefixes.json, the device report names the chosen sync instead of the
  three raw switches, and PATCHES.md and the proot notes describe the
  selector, the fsync default and droiddeck-fsync's futex_waitv.

* Name the runtime's scripts and files droiddeck, migrating old installs

The guest scripts are droiddeck-* now (droiddeck-session and the other 19),
as are the files the app and scripts generate (etc/droiddeck, the network
state files, the components dir, the Steam install stamp, the redist marker,
the extra-Proton wrapper and backups) and the compositor's own names
(libdroiddeckwayland, droiddeck_* sources, DROIDDECK_* switches, the
wl_output and seat names).

Installed runtimes carry on: LegacyNames moves etc/bannerlator and
share/bannerlator over and leaves relative links at the old paths before
every proot command, turns any old script into a link to its new name,
moves the generated files and points menu entries at the new scripts.
The session scripts and steam-compatibility move their markers on first
use, the components dir's desired.tsv is rewritten with it, and the
runtime counts as installed under either session script.

Kept: the banner_ahb_v1/banner_desktop_v1 wire names and BANNER_AUDIO_DIRECT
(read by prebuilt Turnip and Wine builds), Banners-Turnip and other
third-party names, BL_* switches, libblsession, and credits to Bannerlator.

* Unpack x86 AppImages without FEX, then ask Steam for FEX

Importing an x86 AppImage failed when FEX was not installed yet ("needs FEX
to unpack and no unsquashfs is installed"). AppImages now unpack with
uruntime (VHSgunzo, MIT, v0.8.1 aarch64, pinned by sha256 and shipped
unmodified with its licence), which reads SquashFS and DwarFS images of any
architecture natively. FEX's own --appimage-extract and unsquashfs stay as
fallbacks, and an ARM64 image whose own runtime cannot unpack it goes the
same way.

An x86 import with FEX missing records that FEX is wanted, so the next
Steam session requests FEX and the Steam Linux Runtime, and the program's
page says FEX is not set up yet and how to get it.

* Run Vulkan Qt Quick AppImages on Wayland

OpenNOW (Qt 6.8, Qt Quick on Vulkan) closed within two seconds in a run
mode. The session sends toolkits to gamescope's Xwayland, and Qt's xcb
backend only presents with Vulkan when Mesa's X11 WSI does, which needs
DRI3; Xwayland on KGSL has none, so Qt found no queue that can present and
aborted ("Failed to create RHI").

An AppImage that bundles Qt Quick, the Vulkan loader and Qt's Wayland
plugin now runs on gamescope's Wayland socket (the desktop's, outside
gamescope), where Turnip presents as it does for games, with Qt's xcb
backend as the fallback. SDL_VIDEODRIVER and XDG_SESSION_TYPE follow, so
helpers that pick their window system from them (OpenNOW's streamer) agree
with Qt. Everything else stays on X11; a qt file in the app's directory
(wayland or xcb) overrides the choice.

* Keep gamescope's WSI layer away from Qt apps on its Wayland socket

OpenNOW still closed at once: its FFmpeg (the Raspberry Pi fork, libavutil
61) creates its Vulkan queues internally synchronized whenever the driver
offers VK_KHR_internally_synchronized_queues, which DD-Turnip does. The
gamescope WSI layer registers every queue of a new device through
vkGetDeviceQueue, which only returns queues created without flags, so it
got VK_NULL_HANDLE and vkroots aborted on assert(obj) before Qt opened a
window.

Programs that draw on gamescope's Wayland socket do not need the layer,
which only carries X11 windows past Xwayland, so it is turned off for
them. OpenNOW bundles no Vulkan loader (it reaches Vulkan through Qt and
dlopen), so a binary that uses QVulkanInstance counts as a Vulkan app too,
and a Qt Quick app left on X11 says why in the session log.

* Keep the end of the session log, and say when FEX is missing

The session sends its output through head -c into session.log. head
writes through stdio, so it held up to 4 KB that proot's --kill-on-exit
threw away when the guest ended: every log stopped mid-line at a 4096-byte
boundary, losing exactly the lines that say why a program quit (an x86
AppImage's "x86 Linux programs need FEX" among them). dd writes each read
as it comes and keeps the same cap.

A run mode always ends with status 0 (gamescope does not pass its child's
on), so a program that could not start just closed. When the log says FEX
is missing, the ended screen now says so and how to get it.

The app reads FEX's readiness from status.json, which only a launch or an
import wrote, so it still said "not set up" after Steam installed FEX.
droiddeck-fex status rewrites it, and a Steam session ends with it while
FEX is wanted. FEX is also looked for at the tool's root and under files/,
and a tool folder without it lists what it holds.

* Let FEX and its runtime install runnable on an SD card library

A Steam library on shared storage loses the executable bits, so native
tools are staged in private directories bound over it; only Proton and
SteamLinuxRuntime folders were. FEX (3127680) installed there could never
run, droiddeck-fex saw no FEX and kept asking Steam for it. FEX and the
sniper runtime (1628350) now get private directories from their first
download, whatever their install folder is called.

* Keep fsync off in the pack smoke test

A runner whose kernel allows futex_waitv started stock Proton with fsync,
so the server-side baseline never said what the test waits for and every
pack was waved through as untestable; the esync run would have measured
fsync too.

* Judge a pack against stock's own esstress failures

Stock Proton fails esstress's dup wait all under server-side sync as well
(a Wine bug, seen on the phone too), and any stock failure made the test
call the runner unusable. A pack now fails only when it crashes, hangs or
fails a check stock passes.

* Ask Steam for FEX and its runtime one at a time

Both steam://install requests were started together, and the running client
took only the first: FEX installed, the sniper runtime FEX needs never did.
Each request now waits for the client to take it before the next.

* Bundle the first published droiddeck-esync packs in the apk

* Log how an x86 program under FEX ends

FEX keeps its own errors quiet unless asked, so a program it could not run
left nothing in the session log. Its log now goes to stderr, and the AppImage
launcher records the program's exit status or the signal that ended it.

* Show the log a failed AppImage program wrote

Programs like Eden stop themselves on a failed check and say why only in
their own log under the home folder. When the program ends badly, the end of
any log it wrote during the run is copied into the session log.

* Report where an x86 program under FEX hit an illegal instruction

A tiny x86_64 preload, built without libc, catches SIGILL and writes the
address, the instruction bytes and the mapping they belong to before the
program dies as it would have. droiddeck-fex preloads it into x86_64 programs.

* Load the fault reporter from the x86 runtime

Programs under FEX look libraries up in the x86 runtime, so the reporter is
copied there with the other preloads and named by its path inside it.

* Hand FEX its x86 runtime and thunks through the environment

Valve's FEX runs portable and reads its config beside itself, so the
Config.json droiddeck-fex writes was not seen: programs ran without the
runtime. The runtime, thunk libraries and thunk list now also go in FEX's
own environment variables, and each launch says what it was given.

* Use the sync pack built for the installed Proton release

Some Proton releases ship byte-identical ntdll.so and wineserver (Valve
11.0-2b/2c, CachyOS 0702/0703), so a pack built for a newer release
matched an older install exactly and the older install never fetched its
own pack. A pack from a newer release no longer counts as an exact match;
among matches the one built for the installed version wins, then rev.

The app ranks the pack a tool already uses the same way and only fetches
a pack that ranks higher, reads the release epoch from tools.tsv and
refetches when tools.tsv changes. A prefix whose server is still running
re-checks its recorded pack on waitforexitandrun and starts fresh when a
better one now applies.

* Keep published sync packs and revocations consistent

The publish step never replaces a pack that has an entry beside it; a
pack left without its entry by an interrupted run is replaced so the
build stops repeating. Discovery counts revocations the signed index does
not show yet, including superseded packs only the flavor releases list,
so the index is signed again. The release watch always builds every
flavor.

* Fetch the droiddeck-esync packs from DroidDeck-Components

The packs, the signed index and the apk bundle now live in the releases
of Droid-Deck/DroidDeck-Components, together with the pipeline that
builds them, so this repository keeps only the app and the guest code
that consumes them. The app's index and asset URLs point there,
release.env names the repository its bundle comes from, and the apk
builds drop bundled packs that the published index revokes.

* Stop the apk build when the published sync index cannot be read

* Ask Steam for one FEX dependency at a time

The client shows a confirmation dialog for each steam://install, and a
second request replaces the first dialog, so FEX was never installed
when the runtime was requested right after it. The next dependency is
now requested once the previous one has an app manifest.

* Use generic names in the AppImage test fixtures

* Give x86-64 apps under FEX the Vulkan thunk

Apps that bring their own glibc and Vulkan loader skipped FEX's thunk
overlay and loaded their bundled desktop Mesa drivers, which crash on the
phone's GPU during Vulkan setup. droiddeck-fex now adds an x86-64 audit
module when a program's bundled glibc and libstdc++ meet the thunk's
version needs. The module sends libvulkan.so.1 lookups to a nodelete stub
that needs FEX's thunk path. That keeps the thunk mapped when an app
unloads Vulkan and loads it again, since FEX keeps its first trampoline
links and the old addresses get reused.

The fault reporter now restores the default action before re-raising,
because FEX ignores SA_RESETHAND and the handler looped.
2026-10-04 12:43:57 -04:00
Kurt Himebauch b0d7fc01d8 Add opt-in Steam storage diagnostics (#158) 2026-10-04 08:19:48 -04:00
Magarto 9cc40246a3 Start .NET and Godot games under FEX without per-game setup (#168) 2026-10-04 08:19:11 -04:00
The412Banner 423cf11919 Effects page in the session menu: scaling modes, screen effects and texture filtering (#198) 2026-10-04 08:17:00 -04:00
Kurt Himebauch 6f1fb462ed Add controller and desktop quality-of-life options (#194) 2026-10-04 00:56:09 -04:00
MaxsTechReview e7b6876877 Add the droiddeck-esync pack pipeline (#189)
Builds esync packs for new Valve, GE and CachyOS Proton 11 releases on arm64
runners, smoke-tests them against stock with esstress, and on main publishes
each pack and a signed index as non-latest releases. A watcher checks Steam
and the GE/CachyOS releases every 20 minutes and starts a build for new ones.
The app side lands separately with feat/userspace-esync-ntsync.
2026-10-04 02:58:55 +00:00
Kurt Himebauch db2e1d7da2 Fix runtime removal and first-run Steam setup (#185)
* Fix runtime removal races and show removal progress

* Bootstrap Steam from the selected client channel

* Show runtime progress below its Setup row

* Always stage current session helpers and verify APK assets

* Initialize Steam UI scale once using the handheld default
2026-10-03 22:03:26 -04:00
Kurt Himebauch 6357543b44 Merge branch 'main' into fix/steam-sleep-resume-black-screen 2026-10-03 14:18:44 -04:00
xXJsonDeruloXx ba140c4ab5 Merge remote-tracking branch 'origin/main' into preview-history-status-card 2026-10-03 13:30:13 -04:00
Juan Marti Mercado 90ae85da4d Fix Steam sleep resume handshake 2026-10-03 12:08:40 -04:00
xXJsonDeruloXx 2d8befe1cb Add Preview update history 2026-10-03 00:06:09 -04:00
xXJsonDeruloXx f982ffcaf7 Add game launcher shortcuts 2026-10-02 23:49:26 -04:00
xXJsonDeruloXx c236e9711f Restore Steam after idle sleep through session pause and login1 wake 2026-10-02 21:32:12 -04:00
xXJsonDeruloXx eda5ece382 Add Android clipboard text paste into Steam sessions 2026-10-02 17:29:41 -04:00
xXJsonDeruloXx 5614621d6e Expose Android Wi-Fi names and nearby networks to Steam 2026-10-02 15:39:49 -04:00
xXJsonDeruloXx 0816562065 Report Android Wi-Fi and cellular connections to Steam 2026-10-02 15:05:03 -04:00
xXJsonDeruloXx 17ef33ee31 fix: find the stable app release and accept fork builds when signing PR test builds 2026-10-01 21:19:55 -04:00
MaxsTechReview 1c161a76dd Feature adding custom Linux applications (#130)
* Add your own apps to the Desktop page

An Add tile on Desktop takes a .sh script, an AppImage, a GitHub repo
(newest ARM64 AppImage release) or a Flatpak ID, with an optional name
and icon. Script folders are linked into the session, or copied when
they hold Linux programs (shared storage is noexec); folders outside
internal storage are bound at their own path.

Each app's page opens it under gamescope, edits its name and icon (with
icons suggested from its GitHub repo), checks a GitHub app for a newer
release and updates it in place, or removes it. Replaces the beta
AppImages section.

* Put Add at the end of the installable emulators

Installed emulators and added apps keep the top section, shown once there is one. Add closes the installable grid, or the installed one when nothing is left to install.

* Import DwarFS AppImages and their SVG icons

uruntime images built with sharun keep one program under several names
as hard links, which Android denies apps, so dwarfsextract aborted. The
extraction runs with proot's link2symlink, and each linked name becomes
a file of its own afterwards; their AppDir is followed through the
squashfs-root link.

An image's icon is a PNG of at least 128 px from the name its entry
gives, else its SVG (drawn with AndroidSVG), else the largest PNG, else
.DirIcon.

* Give AppImages the session's pads

sharun images start the app through their own ld.so, patched not to read
/etc/ld.so.preload, and drop LD_PRELOAD unless allowed, so the app never
loaded libfakeinput and saw no controller. The launcher now hands the
preload list over in LD_PRELOAD with SHARUN_ALLOW_LD_PRELOAD set.

Pad defaults also put Player 1 on the controller for yuzu-family
emulators, once, while it is still on the keyboard.

* Redesign the Add and Edit app dialogs

Source and appearance sit in two panels side by side, with a live
preview of the Desktop tile. A disabled primary button keeps an outline
so it still reads as a button.
2026-10-01 18:23:47 -04:00
maxjivi05 7e24327621 Merge branch 'main' into feat/performance-fixes-2 2026-10-01 16:40:42 -04:00
xXJsonDeruloXx 466419407d Keep secondary-library prefixes and Steam tools on private storage 2026-10-01 16:11:19 -04:00
Kurt Himebauch e51698e01f Merge branch 'main' into fix/qam-keeps-game-focused 2026-10-01 14:56:59 -04:00
xXJsonDeruloXx 519091dd86 chore: stage gamescope-3.16.29-p5 2026-10-01 14:53:28 -04:00
xXJsonDeruloXx 972088f1b3 fix: skip the pointer warps that jolted the game as the QAM opened and closed 2026-10-01 14:43:30 -04:00
Kurt Himebauch 8f9a849c48 Merge branch 'main' into feat/performance-fixes-2 2026-10-01 14:38:33 -04:00
xXJsonDeruloXx 0a58a7faee fix: keep the game running behind the Steam menu and QAM, as on a Steam Deck 2026-10-01 14:31:30 -04:00
Kurt Himebauch 0d21e2f913 Merge branch 'main' into fix/mangoapp-drm-listing 2026-10-01 14:31:23 -04:00
MaxsTechReview ebb82d2dc9 Merge branch 'main' into feat/performance-fixes-2 2026-10-01 14:03:18 -04:00
xXJsonDeruloXx 08b2cf0894 feat: feed the overlay's fan, GPU memory and Valve msm reader paths 2026-10-01 13:28:26 -04:00
Kurt Himebauch 0e1f6f15a1 Merge branch 'main' into feat/performance-fixes-2 2026-10-01 12:44:00 -04:00
Kurt Himebauch 4df0e012fd Merge branch 'main' into stretch-to-panel 2026-10-01 12:41:57 -04:00
xXJsonDeruloXx 1f29cd92a5 fix: log an empty focused-app or touch-mode property as none 2026-10-01 10:37:58 -04:00
xXJsonDeruloXx 01674b7c6f feat: log controller, touch-mode and pad-ring evidence for input reports 2026-10-01 09:58:51 -04:00
xXJsonDeruloXx 65733c23a1 fix: keep touch scrolling the Steam interface when the client finds no controller at start 2026-10-01 08:18:24 -04:00
Kurt Himebauch d59734e375 Merge branch 'main' into feat/performance-fixes-2 2026-09-30 23:56:24 -04:00
Kurt Himebauch 14db12290e Merge branch 'main' into fix/a840v2-linux-turnip 2026-09-30 23:55:50 -04:00
xXJsonDeruloXx a91be68992 fix: reflect republished PR test freshness 2026-09-30 23:04:34 -04:00
xXJsonDeruloXx 8dc24f244c feat: publish and consume update catalog 2026-09-30 22:46:44 -04:00
maxjivi05 8cfd54a739 Add proot fast path for in-process path lookups
Preload library answers stat/open/access/readlink in-process via a
trampoline page proot 0014 lets through seccomp. On by default with a
Performance toggle; also sets GLIBC_TUNABLES rseq=0 and malloc top_pad.
2026-09-30 21:05:10 -04:00
xXJsonDeruloXx 8565acf12b Merge main into PR #93 2026-09-30 19:41:59 -04:00
MaxsTechReview 941a6c3ef9 fix: carry the installed Steam build into imported games so Steam sto… (#108)
* fix: carry the installed Steam build into imported games so Steam stops re-verifying them

A second-library game downloaded by WinNative was registered with a bare
manifest (no buildid or InstalledDepots), so Steam treated it as build 0 and
verified all ~92 GB of Final Fantasy XV through proot. Reuse WinNative's
.winnative-steam manifest, or a completed .DepotDownloader/depot.config, so
Steam only fetches what changed since the recorded build.

* fix: give queued Steam fresh installs of imported games the recorded build

Steam rewrites a bare import manifest into a fresh install at build 0
before downloading anything. While nothing is downloaded or staged, the
WinNative build is still safe to carry over, so Steam skips the full
re-download (FF7 Remake was queued for 98 GB this way).

* fix: mount the game storage at /mnt/droiddeck-sd

The second library was bound at /mnt/bannerlator-sd, a name left from the
Bannerlator port, which is what Steam shows in its paths and errors. Bind
it at /mnt/droiddeck-sd, keep the old path as an alias for links and
prefixes that still name it, move Steam's library entry in place, re-point
import links, read ownership snapshots taken under the old path, and key
added-game shortcut ids by the old path so their prefixes stay put.

* fix: restart Steam once when owned added games are confirmed

On a fresh install the importer runs before any ownership snapshot exists,
so every added game became a non-Steam shortcut and stayed one until the
client happened to restart. Once the watcher confirms owned titles that are
not imported, it asks the session for one restart, while no game runs and
no download is in progress, and the importer turns them into Steam entries.
2026-09-30 19:34:15 -04:00
Kurt Himebauch fe84c050ad Preserve added game launch options (#111) 2026-09-30 19:08:57 -04:00
MaxsTechReview 8ee1cbe3eb Additional performance fixes (#87)
* perf: answer Turnip's zero-timeout KGSL timestamp polls without blocking

Turnip polls a timeline point with IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID
and a timeout of 0, which KGSL reads as wait forever; Mesa does it under
a lock on every signalling submit, so vkd3d-proton, DXVK, gamescope and
Zink ran in lock-step with the GPU. The session preload now answers
those polls from the context's retired timestamp and passes everything
else to the kernel. Bannerlator measured a D3D12 demo at 614 -> 4335 fps
with the same answer in its Vulkan adapter. BL_NO_KGSL_POLL_FIX=1 turns
it off.

* perf: frame limiter, live panel refresh, opt-in GPU clock pin, cheaper cursor sync

- A per-mode frame limit (Steam and desktop settings, off by default):
  gamescope's -r, the compositor's buffer-release pacer, the display
  layer's frame-rate vote and a panel mode the cap divides evenly, as
  WinNative's per-shortcut limit does. BL_FPS was always 0 and the
  pacer's limit was never set.
- The compositor follows the panel's refresh rate when it changes
  mid-session instead of reporting the rate read at start. (WinNative.)
- Performance > GPU: hold the Adreno clock at its top through KGSL's
  power-control property, no root (Bannerlator's PerfGpuTurbo). Off by
  default; cleared when the session stops and at the next app start if
  a killed process left it set.
- The cursor image is copied across JNI only when its serial changes,
  not on every pointer move.

* perf: stop re-seeding every prefix every 5 s, and run the library helpers only on change

- bannerlator-seed-redists stamped its change check from a block that
  carried the current time, so it never matched: every prefix had ~32
  keys appended to system.reg on every beat. The stamp now comes from
  the names; Proton's prefix template is seeded too (date kept), with
  WinNative's built-in list until the client has the install scripts.
- The library beat runs the seeder every 15 s and steam-compat only
  when a directory it reads has changed, or once a minute.
- The client-core pin reads /proc itself and runs taskset -a only for
  new processes or ones that grew threads.
- The games watcher backs off after a failed ownership probe and does
  not probe while a game runs.
- The Proton launcher runs the newest ARM64 depot by build number, and
  PROTON_USE_PIPEWIRE defaults to 0. (WinNative.)

* perf: Mesa's database shader cache, and proot's tracer above the guest

- MESA_DISK_CACHE_DATABASE=1 for the session: the file cache opens a
  file per lookup and opens and renames one per store, each a proot
  stop; the database is opened once and used with pread/pwrite.
- proot's single tracer thread is raised to nice -6 (under the
  compositor's -8) two seconds after it starts, so the first guest
  process it forks keeps nice 0. setpriority() directly, not
  Process.setThreadPriority, which would also move its cgroup.
2026-09-30 16:43:52 -04:00
MaxsTechReview 6c5d6cda73 Added LSFG/Import/License Checking (#96)
* feat(lsfg): take Lossless Scaling from Steam by itself, import it once owned, rebuild on update

- Lossless.kt owns the DLL and its shader cache. The copy the Steam
  client installs (runtime library or the card's) is taken by itself
  and taken again when the client updates it (size/mtime stamp). The
  DLL is copied in and built into a cache named after its SHA-256, so
  a new DLL hands the compositor a new path; a build that fails keeps
  the working cache. Builds are serialized.
- The Steam session asks the signed-in client once per session whether
  the account owns app 993090 until the answer is yes, then records it
  and the app stops asking (BL_LOSSLESS_OWNED). Once owned, the frame
  generation menu offers "Import Lossless.dll…", on the main screen and
  in the session drawer; an import stays until Steam's copy changes.
- The compositor restarts the LSFG engine when its cache path changes,
  and a new engine selection clears an earlier start failure, so an
  updated DLL or a retry no longer needs the app restarted.
- The HUD says when LSFG is waiting on Lossless Scaling instead of
  "starting"; frame generation strings are resources.
- Removed LsfgNative's unused DLL variant and cache-match calls.

* Find Lossless.dll in added Games libraries too

* LSFG: 120, 90 and 60 fps targets alongside 2x-4x

The pacer's target-rate mode picks 0-3 generations per game frame. While it
is warm the input ring and shared chain follow every frame, so frames that
generate nothing don't leave the next one without history.

* Credit LSFG: Camille LaVey / Eden, ported to WinNative and DroidDeck by @maxjivi05

* LSFG: aim 0.1 fps under the target so output never passes the refresh rate
2026-09-30 16:40:46 -04:00
xXJsonDeruloXx 93382ff241 fix: report Adreno 840v2 as the A840 the runtime's Turnip knows 2026-09-30 07:53:12 -04:00
Magarto 24b74d8346 Merge branch 'main' into stretch-to-panel 2026-09-30 09:30:37 +02:00
Kurt HimebauchandMaxsTechReview 9ed25d8ae5 feat: Flatpak apps and a Flathub store (#77)
* feat: run Flatpak apps through a proot bwrap stand-in and add a Flathub store

* feat: give Flatpak apps the KGSL GPU, the controllers and a CPU LLVM can target

* feat: Flatpak games on the desktop, Store apps on the Desktop page, safer remove

* test: cover the sandbox planner and store helpers; docs: explain Flatpak on DroidDeck

* fix: keep controller focus through Store tabs and app pages; show progress per Flatpak step

* fix: let Chromium, Electron and Firefox Flatpaks start without their own sandboxes

* fix: fetch Flatpak's supporting libraries when the runtime lacks them

* fix: add Flathub without a download, log store commands, keep Electron apps on X11 under gamescope

* feat: import ARM64 AppImages from storage and run them from the Desktop page

* fix: report failed Flatpak installs as failures and deploy runtimes that ship a resolv.conf link

* fix: let Flatpak create its repo where Android denies hard links

* fix: point store commands at the current network's DNS

* fix: keep failed Flatpak extensions non-fatal, give Electron AppImages a bus, X11 and time to relaunch

* docs: AppImage import and what x86 apps would take

* feat: put the Flathub Store and AppImage import behind beta toggles in Setup

---------

Co-authored-by: MaxsTechReview <[email protected]>
2026-09-30 00:35:49 -04:00
The412Banner 7c7bf2dcbe Merge branch 'main' into fix/resume-restore-minimized 2026-09-29 22:10:04 -04:00
Kurt Himebauch 75593cfd29 feat: the pad as SteamOS has it - Steam Input's virtual pads for games, a Steam Deck controller for the client (#86)
* feat: stand in for /dev/uinput so Steam Input's virtual pads reach games

* feat: present the pad to the Steam client as a Steam Deck controller over hidraw

* docs: log the uinput stand-in and the Steam Deck controller

* feat: feed the handheld's gyro and accelerometer to the Steam Deck controller

* feat: let the Steam page choose between the Steam Deck controller and the Xbox 360 pad

* feat: Deck back grips and trackpads on the second screen

* fix: serialize ring teardown with its writers, fall back to the Xbox pad when the Deck cannot be set up, and read motion only for a Deck

* fix: keep the second screen's choice through sleep and bring it back on wake
2026-09-29 21:57:52 -04:00