Skip to content

shim: at a cap at the display's rate, a self-paced guest keeps the container's mode with the vblank-grid gate - #61

Open
utkarshdalal wants to merge 1 commit into
masterfrom
shim-cap-rate-immediate-guests-get-the-gate
Open

utkarshdalal wants to merge 1 commit into
masterfrom
shim-cap-rate-immediate-guests-get-the-gate

Conversation

@utkarshdalal

Copy link
Copy Markdown
Contributor

One commit on top of master: the last capped cell on gamescope's route that relied on gamescope's FIFO back-pressure now gets the vblank-grid gate like the others.

What changed

  • choose_live_mode: a cap at the display's rate and a guest that asked for mailbox or immediate (in-game VSync off) declare the swapchain's mode (the container's mailbox) with Declared::CapRate, instead of FIFO. gamescope_route_pacing needs no edit: it only turns the gate off for a FIFO declaration, so this cell now reads gate=vsync, one release per vblank.
  • The census keeps source=cap-rate, so logs before and after stay comparable.
  • The swapchain image count is untouched. Since icd_shim: the swapchain image count is the guest's, and one ring behind it #59 it follows the swapchain's own mode, not the per-present declaration, so this cell already had mailbox's floor; there is no CapRate entry left to drop from a slot-count list.
  • Tests that pinned FIFO/Pacing::Off for this cell now pin mailbox/GateClock::Vsync.
  • docs/10 and docs/15 describe the cell and its cost, with the measurements below. docs/15 §1 now names the limiter's real setter (set_app_target_refresh_cycle through the daemon's injector), not debug_set_fps_limit.

Why

#47 dropped the gate from this cell on the assumption that gamescope's FIFO latch holds a self-paced guest to one commit per vblank. It holds a guest that runs a little under the panel (DTD, ~59.3 fps), but not one that runs faster. Retroid Pocket 6, Portal 2 main menu, in-game VSync off, cap 60 on a 60 Hz panel, per 10 s:

census acquires / commits / releases gate_holds daemon publishes fps SurfaceFlinger
master (868ace5 shim) declared=fifo requested=immediate source=cap-rate gate=off 1131-1193 each 0 600 112-120 60.00/s, game frames dropped downstream
this branch declared=mailbox requested=immediate source=cap-rate gate=vsync 600 each 600 597-600 60.0 59.98/s, 0 doubled intervals in 125

Where gamescope lets the second buffer per vblank go is not located: by its source a FIFO commit is admitted once per vblank tick and released by the next admission. The shim's FIFO path uses wl_buffer.release as its only back-pressure, so any early release lets the guest run free. With the gate, the guest never queues more than one commit per period, so the leak no longer matters for capped sessions.

Trade-off. This is the cost #46 measured for mailbox at the display's rate: a guest that paces itself just below the panel (DTD, ~59.3 fps) loses ~1 frame a second in gamescope's mailbox (58.3 fps, 2.8 % doubled intervals, against 59.22 under FIFO). A guest faster than the cap is held on the grid and does not pay it. Every below-rate cell and cap-rate-vsync (#48) already accept it. The known follow-up is the unmerged gamescope hold, A58 on jt/gn-mailbox-hold-under-limiter, which keeps a second non-FIFO commit for the next vblank instead of replacing the first. A container set to MESA_VK_WSI_PRESENT_MODE=fifo still declares FIFO.

How to test

  • Built for aarch64-linux-android (release, NDK 27.3), check-exports PASS, clippy -D warnings clean for adrenotools_gamescope (all targets). Lib tests: 124 passed, run on the Retroid Pocket 6.
  • On device: GNDRM_LOG_VKSHIM=1, FPS limiter 60, panel 60 Hz, a game with in-game VSync off (Portal 2), gamescope route. The census should read declared=mailbox requested=immediate source=cap-rate route=gamescope cap=60 gate=vsync. Per 10 s, acquires ≈ commits ≈ releases ≈ gate_holds ≈ 600, the daemon's vsync: check ... publishes≈600, and the HUD at 60.
  • Regression cells (not re-run here): VSync on at cap 60 (cap-rate-vsync, unchanged), cap 30 @ 60 Hz, cap 60 @ 120 Hz, frame generation x2, and DTD with VSync off (expect the ~2.8 % doubles above).

…gate

On gamescope's override route, a cap at the display's rate and a guest that
asked for mailbox or immediate were declared FIFO with no acquire gate
(`source=cap-rate`, #46/#47), on the assumption that gamescope's FIFO latch
holds the guest to one commit per vblank. It does not hold a guest faster
than the panel. Retroid Pocket 6, Portal 2 main menu, in-game VSync off, cap
60 on a 60 Hz panel, per 10 s:

  before  declared=fifo source=cap-rate gate=off
          acquires/commits/releases 1131-1193, daemon publishes 600, 112-120 fps
  after   declared=mailbox source=cap-rate gate=vsync
          acquires/commits/releases 600, gate_holds 600, gate_late 0,
          slot_waits 0, publishes 597-600, 60.0 fps, SurfaceFlinger 59.98
          presents/s with no doubled interval in 125

The cell now declares the container's mode, so `gamescope_route_pacing` arms
the vblank-grid gate as it does for every other capped cell with a known grid;
nothing capped on gamescope's route leans on its FIFO back-pressure any more.
The census keeps `source=cap-rate`. The swapchain's image count is untouched:
since #59 it follows the swapchain's own mode, not the declaration, so this
cell already had mailbox's floor.

The cost is the one #46 measured: a guest that paces itself just below the
display's rate (DTD, ~59.3 fps) loses ~1 frame a second in gamescope's mailbox
(58.3 fps, 2.8 % doubled intervals). A guest faster than the cap is held on
the grid by the gate and does not pay it. A container set to fifo keeps the
FIFO declaration.

docs/10 and docs/15 describe the cell, and docs/15 §1 names the limiter's
real setter, `set_app_target_refresh_cycle` through the injector.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant