gamescope: start sessions at the panel refresh rate; daemon stamps flips on the latch grid
Description
Drops the fixed 1200 Hz vblank grid (-r 1200) from gamescope sessions: gamescope now takes its refresh from the mode the gamenative-drm daemon advertises, which is the panel's active rate. Ships the daemon that stamps gamescope's flips on the panel latch grid.
Branch gamescope-panel-rate-vblank.
-ris removed from the launch command entirely (GamescopeSettings.gridArgandSESSION_GRID_HZare gone). The daemon already learns the panel's active rate fromnativeSetPanelRefreshHz, advertises it as the mode and measures its latch grid, so gamescope's tick follows it; a mode change mid-session is forwarded by the daemon as thegn_panel_refreshConVar.display/PanelRefresh.kt(new):PanelRefresh.activeHzreads the panel's active rate once, rounded to Hz, 60 when unreadable.nativeSetPanelRefreshHzand the FPS limiter ceiling both use it, so they always agree. A panel the user holds at 60 Hz counts as 60.XServerScreen.detectRefreshRateHzdelegates toPanelRefresh.activeHz.jniLibs/arm64-v8a/libgamenative_drm.so: the daemon from the gamenative-drm PRflip-stamps-on-the-panel-latch-grid(0630e1a). It sets the latch grid for gamescope clients that ask for it (GNLGclient cap) and forwards panel-rate changes to a running session as thegn_panel_refreshConVar.
Depends on:
- gamenative-drm
flip-stamps-on-the-panel-latch-grid(the daemon in this PR's jniLibs); - gamenative-drm
present-wait-answered-at-commit-in-mailbox(ICD shim, ships in the gamescope payload): the fix that takes cap 60 from 47 to 60 fps; - gamescope
vblank-on-panel-latch-grid(A53/A54).
Not in this PR: the device test used payload 20261030.3 with the fix-1 gamescope binary and the fix-3 shim (libadrenotools_gamescope.so) swapped in by hand. Shipping needs a gamescope payload built with both and a payload VERSION bump, in a follow-up PR.
Compatibility: with the current payload's gamescope (no A53), dropping -r 1200 leaves gamescope on the daemon's advertised mode (the panel rate), which still cuts its wakeups; the daemon keeps its legacy timeline for it (the latch-grid cap is never requested). The A52 FPS limiter stays exact at the panel rate.
Results (Retroid Pocket 6, Dave the Diver):
Setup, every column. Retroid Pocket 6 (Adreno 740 class, 1080x1920 panel at 120 Hz, landscape), Dave the Diver (1868140), DXVK 2.7.1-gplasync, proton-10.0-arm64ec-2, container 1280x720, FPS limiter as listed, the same boat-deck scene. Segments are 180 s (launch 4: 60-120 s). "SF" = the game's SurfaceFlinger layer histogram; "PowerMetrics" = the app's own counter (5 s samples). gamescope-xwm is the steamcompmgr thread.
| Cap 60, cursor hidden | X11 | Shipped gamescope (A52, -r 1200) | Fix 1 | Fix 1 + shim fix |
|---|---|---|---|---|
| fps, SF | 59.89 | 47.05 | 46.91 | 59.13 (47 s segment) |
| fps, PowerMetrics | 59.9 | 47.1 | 46.9 | 59.97 (59.3-60.3) |
| 2x / 3x panel-period share, SF | 95.2 / 2.5 % | 41.5 / 41.3 % | 43.3 / 45.6 % | 94.2 / 2.7 % |
| frame interval p95 / p99, SF, ms | 16.7 / 25.0 | 33.3 / 41.6 | 33.3 / 33.3 | 16.7 / 25.0 |
| game process CPU, % of a core | 176.1 | 127.7 | 128.4 | 135.0 (fix 1 + shim + cursor plane run, 60 s) |
| gamescope CPU, % of a core | — | 8.1 | 5.9 | 6.6 (same run) |
| gamescope wakeups/s | — | 1723 | 623 | not captured (segment cut) |
| gamescope-xwm voluntary wakeups/s | — | 1411 | 424 | ~520 (same run) |
| GPU busy %, PowerMetrics | 79.9 | 60.4 | 59.8 | 77.3 |
| CPU temp °C, PowerMetrics mean | 76.5 | 69.8 | 66.3 | 73.7 |
| Cap 30, cursor hidden | X11 | Shipped gamescope (A52, -r 1200) | Fix 1 | Fix 1 + shim fix |
|---|---|---|---|---|
| fps, SF | not run | 30.00 | 30.00 | not run |
| 2x / 3x / 4x share, SF | not run | 0.1 / 7.0 / 85.4 % | 0.1 / 5.3 / 88.9 % | not run |
| gamescope CPU, % of a core | — | 10.2 | 4.2 | not run |
| gamescope wakeups/s | — | 1510 | 401 | not run |
| gamescope-xwm voluntary wakeups/s | — | 1281 | 269 | not run |
| GPU busy %, PowerMetrics | not run | 38.5 | 38.1 | not run |
| CPU temp °C, PowerMetrics mean | not run | 61.9 | 63.9 | not run |
The fix 1 + shim fix column: SF fps and histogram from a 47 s cap-60 segment (launch 4); PowerMetrics 59.97 fps over 143 samples; game/gamescope CPU from the 60 s hidden-cursor segment of the cursor-plane run (fix 1 + shim + cursor layer, cursor hidden), where the SF fps was 60.00. Temperatures are loose: the X11 run started hot (CPU zone 92.7 °C at segment start).
Recording
No visible UI change. Measurements above.
Type of Change
- Bug fix
- Performance / stability improvement
- Compatibility improvements
- Other (requires prior approval)
Checklist
- If I have access to
#code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed. - This change aligns with the current project scope (core functionality, stability, or performance). If not, it has been explicitly approved beforehand.
- I have attached a recording of the change.
- I have read and agree to the contribution guidelines in
CONTRIBUTING.md.
Summary by CodeRabbit
- New Features
- Display refresh-rate detection now uses the active screen’s rate, with a 60 Hz fallback when a usable rate is unavailable.
- Updates
- Gamescope no longer applies a fixed refresh-rate setting when launching games. Other display settings remain unchanged.