gamescope: payload 20261103.7, the FPS limiter holds a cap below the panel rate again
Description
Depends on GameNative/gamenative-drm#49 (open). Do not merge before it.
This ships GameNative/gamenative-drm#49 at 5d1e0ae as gamescope payload 20261103.7. The only change in the app is GamescopePayload.VERSION = 20261103.7. libgamenative_drm.so is unchanged.
What was wrong
On master (payload 20261103.4 to .6) the FPS limiter under gamescope stops holding any cap below the panel's rate once a frame outlasts one vblank. A user set 20 for MGS V: The Phantom Pain on a 120 Hz phone and got 40-50 fps; at 60 Hz the cap held. Reproduced on the Retroid Pocket 6 at 120 Hz with Dave the Diver at 1080p, cap 20: the shim census showed cap=20 gate=vsync with gate_holds frozen and gate_late growing once per frame, at the game's own 53 fps.
Cause: GameNative/gamenative-drm#47 added, next to its fix for the cap-rate FIFO cell (kept), a rule that the release after a late start is never more than one grid instant after it. A cap below the rate holds the guest for a whole slot (six vblanks at 20 on 120 Hz); after that rule fired once, the next release was one vblank away, a frame longer than 8.8 ms was late for it too, and the gate never held again. At 60 Hz only games faster than ~58 fps recovered, which hid it there.
What changes
The shim (gamenative-drm#49): a late start keeps its slot's timeline, so the next release is where the cap puts it; only a start past the whole slot restarts the timeline. The cap-equals-rate cells from #47 and #48 are unchanged (slot and period are equal there).
Measured on the RP6 at 120 Hz, DTD 1080p, limiter switched live
| cap | before (payload .6) | after (this shim) |
|---|---|---|
| 20 | ~53 fps (gate never holds) | 20.0 fps, gate_holds +1 per frame |
| 40 | — | 40.0 fps |
| 60 | — | 52-53 fps (the game's own rate) |
Each switch settled within the same second. A 100 s gameplay run: 2010 frames in 100.4 s = 20.02 fps. Shim unit tests: 90 of 90 on the device.
Payload 20261103.7
gamescope-gamenative-20261103.7.tzst, 14308927 B, sha256 1b2dc7308973d068852a77522206e3472cd89a9c8b2eb5b359954a99c66b4f55, served from both CDN hosts and verified. Same 1014 members as 20261103.6; only lib/libadrenotools_gamescope.so differs (sha256 b10cb50957c1b62b708d42311e49f6972cf154cdaa3fc75d05e6ddbd5f7a9122, build string 2026110317065d1e0ae).
Recording
Census excerpt from the RP6 run at cap 20, before and after, in GameNative/gamenative-drm#49.
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 cubic
Ships gamenative-drm#49 as gamescope payload 20261103.7, restoring the FPS limiter so a cap below the panel rate holds again. Only GamescopePayload.VERSION changes.
Bug Fixes
- On payloads
.4–.6, the limit stopped holding once a frame outlasted a vblank (cap 20 on a 120 Hz panel ran at 40–50 fps); a late start now keeps its slot's timeline, so the next release lands where the cap puts it.