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.
* 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.
* 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.
* 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
* 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 <maxjividen@gmail.com>
* 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
The Steam menu is an overlay that takes input without changing gamescope's focus
window. A fullscreen wine game minimizes itself when it loses input, and gamescope
only takes a window out of iconic when the focus window changes, so after Resume
the game stayed minimized: a black screen with its caption in the top-left corner
(Titanfall 2 on GE-Proton 11, proven on device).
gamescope patch 0112 remembers the iconify request and puts the window back to
NormalState before input returns to it, then hands focus over again so wine
restores and activates it. The session script also asks gamescope to restore the
game once input comes back from the client (GAMESCOPE_RESTORE_FOCUS_WINDOW);
BL_RESTORE_ON_RESUME=0 turns that off.
* perf: cache pinned downloads, skip unchanged proot rebuilds, and wait out a Docker Desktop restart in the local build
* perf: skip xalia and gamescope realtime queues by default, add a realtime toggle, default the mic off
* fix: show the saved Steam Deck mode on the Steam page before Performance has been opened
The gamepad-cursor port queried the X pointer on every vblank, a
blocking round trip to Xwayland on the paint thread. With no cursor
image the position comes from wlserver as upstream; while the cursor is
hidden for inactivity X is asked every 50 ms. The realtime-queue comment
now says it is a no-op on KGSL Turnip.
The session's watchers slept with sleep(1) and read files with cat, an
exec each under proot; they now wait in bash itself. steam-compat
writes its tool, the adopted wrappers and config.vdf only when they
change, the games watcher probes ownership when its matches change or
every five minutes instead of every 30 s, and Proton no longer inherits
the client's steamrtarm64 library path.
fake_id0 (loaded by -i for Xwayland's set*id) now traces only the set*id
family and the xattr fixups when the ids given are proot's own, and the
seccomp filter traces ioctl only for the termios and FICLONE requests
proot rewrites. The faccessat2 and statx exit stops are dropped on
kernels that have the calls.
* Add ownership-aware Steam game folder imports
* Fix Steam title lookup and installed game manifests
---------
Co-authored-by: MaxsTechReview <6025299+maxjivi05@users.noreply.github.com>
On a foldable's inner panel (Galaxy Z Fold8: 2448x1848, ~4:3) gamescope
is started with the nested size equal to the output, so games are asked
for the panel's own shape. Many cannot do it and letterbox themselves,
and gamescope's scaler has nothing to stretch. "Stretch games to fill
the screen" only forces window size, so it does not help.
New Steam setting "Stretch 16:9 games to a narrower screen" (off by
default): bannerlator-session then gives games a 16:9 surface at the full
output height (-w) and adds -S stretch, so they render at a shape they
support and fill the panel with no bars and no crop. An output that is
already 16:9 or wider is left untouched. Passed as
BL_GAMESCOPE_STRETCH_16X9 and listed in device.txt.
A local build was signed with the testkey alone, which a release refuses
as an update ("signatures do not match"): testing on a device with a CI
build meant uninstalling it and losing its data first.
With an untracked .signing.env (RELEASE_KEYSTORE, RELEASE_STORE_PASSWORD,
RELEASE_KEY_ALIAS) in the checkout, or in the main checkout for a
worktree, build_local.sh finishes with tools/release/sign-apk.sh as CI's
main builds do, and the apk installs over a release. Without the file
nothing changes. DROIDDECK_SIGNING_ENV points at the file explicitly.
The desktop forced a software cursor (WLR_NO_HARDWARE_CURSORS=1) because
labwc's cursor never showed when handed to the app's compositor. With a
software cursor wlroots never scans out: every frame of a full-screen game
was composited by labwc first ("Direct scan-out disabled by software
cursor", 2284 times in one Adreno 825 report).
Why the cursor never showed: wlroots' Wayland backend attaches and commits
its cursor surface before wl_pointer.set_cursor gives it the cursor role,
and sets it again with nothing new committed each time the pointer enters.
The compositor released a role-less surface's buffer on commit, so the
cursor surface had no image by the time it became the cursor.
- A role-less surface's last buffer (cursor-sized only) is held until the
next commit; set_cursor publishes it, and a repeat set_cursor of the
surface already shown unhides its last image.
- A dma-buf cursor is read back after the client's implicit render fence,
as the zero-copy path waits for it.
- The desktop no longer forces a software cursor.
Device-tested on the AYN Thor (Adreno 740, 1920x1080): labwc's own cursor
is drawn, with its shapes (I-beam over a terminal); wlroots logs "Direct
scan-out enabled" for a full-screen glxgears. At the same 60 fps on screen
the GPU is 3.0 % busy against 4.6 % with the software cursor, both at
550 MHz.