Repository navigation
shim: no vblank-grid gate under the cap-rate FIFO declaration; a late start is released at the next grid instant - #47
Merged
Conversation
… start is released at the next grid instant @joshuatam's capture (payload 20261103.3, shim c9b7c31, a 1280x960 device, DTD in game, cap 60, env mailbox, in-game VSync on) found a regression. At 120 Hz the session was declared mailbox with the gate and held 60 fps. After a live switch to 60 Hz it became declared=fifo source=cap-rate gate=vsync and settled at 40 fps within ~10 s: shim commits 400 per 10 s, equal to the daemon's 400/600 publishes with late=0; gate_holds 0, gate_late 400/400, skipped +200 per 10 s; acquire-to-commit 24 ms against 7-16 ms at 120 Hz. Back at 120 Hz it recovered within a second. The RP6 runs of this cell did not show it because their scene's acquire-to-commit stayed near 12 ms. FIFO's back-pressure already holds the guest at the display's rate, and the gate stacked on it: once a frame took longer than a period from acquire to commit, every start was late, and the schedule booked releases on the grid the guest could no longer meet. - The cap-rate cell (a non-FIFO mode under a cap at the display's rate) still declares FIFO, but with the gate off: gamescope's limiter (divisor 1) paces it, which is master's behaviour in that cell. The census reads source=cap-rate gate=off. - The gate never books the release after a late start more than one grid instant after it: under a cap below the display's rate (30 on 60, 60 on 120) a late frame's successor no longer waits a whole slot. On-time guests are held as before. Lateness is measured against the instant the acquire was released for, so the first grid booking after a clock booking is not mistaken for a late one. - The slot count follows the guest's own request whenever the swapchain is declared FIFO at creation for another reason than its own mode (no stamp lead, cap-rate, a guest's FIFO request with no cap), as on master. - icd_shim/src/proxy.rs: gamescope_route_pacing turns the gate off for every FIFO declaration; the slot count from choose_live_mode at creation; comments; tests: 60 on 59.97 Hz is FIFO, cap-rate, gate off; 60 on 120 and 30 on 60 stay mailbox with the gate every second vblank. - icd_shim/src/vsync_gate.rs: the late-start release rule; tests: a late frame on a 30-on-60 cap is followed at the next grid instant while an on-time one is held two vblanks; a guest with 16 ms of work (late every seventh frame) on a 59.97 Hz grid gets a start every vblank. - docs/10, docs/15: the rule table and the reason, with the capture's counters. (cherry picked from commit 2567925)
4 of 8 tasks
This was referenced Nov 3, 2026
utkarshdalal
pushed a commit
that referenced
this pull request
Nov 3, 2026
…ant release after a late start Reported on app master with payload 20261103.6 (shim 762e559): the FPS limiter set to 20 under gamescope on a 120 Hz panel left MGS V: The Phantom Pain at 40-50 fps; at 60 Hz the cap held. Reproduced on the Retroid Pocket 6 at 120 Hz with DTD at 1920x1080, cap 20, env mailbox: census `declared=mailbox requested=immediate source=env cap=20 gate=vsync`, `gate_holds` frozen at 188 for the rest of the session while `gate_late` grew by one per frame, frame spacing 17.2-20 ms (DTD's own ~53 fps). The cap reached the shim; the gate stopped holding. Cause: #47 (1cc98e1) added, next to the fix for the cap-rate FIFO cell (gate off under that declaration, kept here), a rule that the release after a late start is never more than one grid instant after it. A cap below the display's 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 after the late start, a guest whose frame outlasts one period plus ON_TIME_NS (0.5 ms) was late for that release too, and so for every release after: the gate never held again. At 120 Hz (8.3 ms period) that is every game; at 60 Hz a guest faster than ~58 fps recovers, which is why the 60 Hz panel hid it. - icd_shim/src/vsync_gate.rs: Schedule::book: a start late by less than a period is booked to its release point as before; a start late by a period or more but still inside its slot (before `ideal + interval`) is booked to the grid instant it is in and keeps the slot's ideal timeline, so the release after it is where the cap puts it, at most the rest of the slot away; a start past the whole slot restarts the timeline from the instant it is in, so a stall carries no debt. The cap-rate cell is unchanged (slot == period). Tests: the late-frame-on-a-divisor-cap test now expects the slot's release (two vblanks at 30 on 60) and covers late by a whole vblank and past the slot; a new test runs a guest with 18 ms frames, 1 ms late wake-ups and one 80 ms hitch under cap 20 on 120 Hz (and 22 ms frames under 20 on 60 Hz) and requires the 6- (3-) vblank cadence everywhere but the three releases after the hitch, which catch the slot's timeline up, and never more releases than the cap over the run. The existing 16 ms guest on a 59.97 Hz grid under cap 60 still gets every vblank. - docs/15: the gate paragraph states the rule and why the next-grid-instant release is gone.
4 of 8 tasks
utkarshdalal
added a commit
to utkarshdalal/GameNative
that referenced
this pull request
Nov 3, 2026
…panel rate again (#2336) Ships GameNative/gamenative-drm#49: the shim's vsync-grid gate no longer releases the frame after a late start at the next grid instant, a rule from GameNative/gamenative-drm#47 that made every cap below the panel's rate stop holding once a frame outlasted one vblank (MGS V at cap 20 on a 120 Hz panel ran at 40-50 fps; DTD at 53). Only GamescopePayload.VERSION changes. Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #46, which merged at c9b7c31 before this commit reached the branch. Master therefore carries the regression @joshuatam's capture found (see #46 (comment)); this PR is that fix, cherry-picked unchanged from the #46 branch (2567925).
Problem
Under a cap equal to the display's rate, #46 declares FIFO and also kept the vblank-grid acquire gate running. Once a frame takes longer than a period from acquire to commit, every start reaches the gate late and the schedule books every other release a whole vblank later: the game settles at 40 fps on a 60 Hz panel (1,2,1,2 vblank intervals). The capture: at 120 Hz
declared=mailbox source=env gate=vsync, 60 fps; after a live switch to 60 Hzdeclared=fifo source=cap-rate gate=vsync, shim commits 400 per 10 s = daemon publishes 400/600 withlate=0,gate_late400/400,skipped+200 per 10 s, acquire-to-commit 24 ms (7-16 ms at 120 Hz), GPU 65 % against 80 % at 120 Hz where the same scene runs 60.Change
source=cap-rate gate=off): gamescope's limiter (divisor 1) paces it, master's behaviour before shim: the present mode follows the container, the cap runs on the vsync grid under mailbox #46.Tests
cargo test -p adrenotools_gamescope --lib: 88 passed. Clippy on the shim, daemon and android crates with-D warnings: clean. New cases: 60 on 59.97 Hz is FIFO/cap-rate/gate off; 60 on 120 and 30 on 60 stay mailbox with the gate every second vblank; a guest with 16 ms of work on a 59.97 Hz grid gets a start every vblank; a late 30-on-60 frame is followed at the next grid instant.Verified on a Retroid Pocket 6
Dave the Diver in game (diving), cap 60, in-game VSync on, panel switched live from 120 to 60 Hz, shim 2567925 via payload 20261103.4: census
declared=fifo source=cap-rate cap=60 gate=off; SurfaceFlinger 374 of 377 intervals a single vblank, median 16.71 ms; app fps 59.9 / 60.1 / 60.0 at GPU 51-53 %; daemon 596-598 publishes per 600 vsyncs, late 0-2.Delivery
Payload
gamescope-gamenative-20261103.4.tzst(sha2565126c4ee8f042a69e287a3bde16e3be5a79de0cc052aaeadff5554b6a09fe7b9) already carries this shim (sha2566355ee9e…9035, build string2026110307122567925); the app side is utkarshdalal/GameNative#2327. The daemon is unchanged.