mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
* 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.
80 lines
2.9 KiB
C
80 lines
2.9 KiB
C
/*
|
|
* A zero-timeout KGSL timestamp wait answered as the poll it was meant to be.
|
|
*
|
|
* Turnip's KGSL backend emulates timeline semaphores with timestamps, and asks "has this one
|
|
* retired yet?" by waiting on it with IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID and a timeout of 0.
|
|
* KGSL reads a timeout of 0 as no timeout at all, so the poll blocks until the GPU gets there.
|
|
* Mesa's timeline bookkeeping polls like that under a lock on every signalling submit, which put
|
|
* vkd3d-proton, DXVK, gamescope and Zink in lock-step with the GPU: one frame queued, never two.
|
|
* Found and measured by Bannerlator (PROGRESS_LOG 2026-09-29: a D3D12 demo went from 614 to
|
|
* 4335 fps with the same answer given in its Vulkan adapter); the driver-side fix is on
|
|
* Banners-Turnip, and this covers the drivers that do not carry it yet.
|
|
*
|
|
* The answer comes from the context's retired timestamp, compared the way KGSL compares them
|
|
* (with wrap-around). Anything the read does not answer - an unknown context, a device that is not
|
|
* KGSL - goes to the kernel as before. BL_NO_KGSL_POLL_FIX=1 turns it off.
|
|
*/
|
|
#define _GNU_SOURCE
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#define KGSL_IOC_TYPE 0x09
|
|
#define KGSL_TIMESTAMP_RETIRED 0x00000002
|
|
|
|
struct kgsl_device_waittimestamp_ctxtid {
|
|
unsigned int context_id;
|
|
unsigned int timestamp;
|
|
unsigned int timeout;
|
|
};
|
|
|
|
struct kgsl_cmdstream_readtimestamp_ctxtid {
|
|
unsigned int context_id;
|
|
unsigned int type;
|
|
unsigned int timestamp;
|
|
};
|
|
|
|
#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \
|
|
_IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid)
|
|
#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID \
|
|
_IOWR(KGSL_IOC_TYPE, 0x16, struct kgsl_cmdstream_readtimestamp_ctxtid)
|
|
|
|
static int enabled(void) {
|
|
static int cached = -1;
|
|
const char *off;
|
|
|
|
if (cached >= 0) return cached;
|
|
off = getenv("BL_NO_KGSL_POLL_FIX");
|
|
cached = !(off != NULL && off[0] == '1');
|
|
return cached;
|
|
}
|
|
|
|
/* True when the call was answered here, with its result in *rc (and errno set on failure). */
|
|
__attribute__((visibility("hidden"))) int bl_kgsl_poll(int (*real)(int, unsigned long, void *),
|
|
int fd, unsigned long request, void *arg,
|
|
int *rc) {
|
|
const struct kgsl_device_waittimestamp_ctxtid *wait = arg;
|
|
struct kgsl_cmdstream_readtimestamp_ctxtid read;
|
|
int saved = errno;
|
|
|
|
if (request != IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID || arg == NULL || wait->timeout != 0 ||
|
|
!enabled())
|
|
return 0;
|
|
read.context_id = wait->context_id;
|
|
read.type = KGSL_TIMESTAMP_RETIRED;
|
|
read.timestamp = 0;
|
|
if (real(fd, IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID, &read) != 0) {
|
|
errno = saved;
|
|
return 0;
|
|
}
|
|
if ((int32_t)(read.timestamp - wait->timestamp) >= 0) {
|
|
errno = saved;
|
|
*rc = 0;
|
|
} else {
|
|
errno = ETIMEDOUT;
|
|
*rc = -1;
|
|
}
|
|
return 1;
|
|
}
|