Report the panel's active refresh rate to the gndrm daemon

Closed
UT
11d ago
+56-33

What this fixes

Under gamescope the daemon measures the panel's latch grid (vsync.rs) against the refresh rate the app reports through GameNativeDrm.nativeSetPanelRefreshHz. The app reported detectMaxRefreshRateHz, the fastest mode the panel supports, so on a panel a user holds at 60 Hz the daemon tracked a 120 Hz lattice and told the shim the latch period was 8.33 ms. The ICD's frame cap now places the game's frames on that grid (GameNative/gamenative-drm#34); with the wrong period it snaps to points that are not latch points, and commits land on the edge of the real window. Measured on the Odin 3 (panel at 60 Hz, maximum 120): the shim logged panel grid period=8333us before this change and period=16666us after.

The change

  • detectActiveRefreshRateHz: the display's current mode (Display.refreshRate), falling back to the maximum only when it cannot be read.
  • The gamescope branch of session setup reports the active rate ahead of nativeStart, and registers a DisplayManager.DisplayListener that reports it again on onDisplayChanged, so a mode switch mid-session reaches the daemon. The listener is unregistered at session exit, just before nativeStop.
  • detectMaxRefreshRateHz stays for the limiter's ceiling.

Verification

  • :app:compileModernDebugKotlin passes on master.
  • Odin 3 debug build: the daemon's grid period went from 8333 µs to 16666 µs with the panel at 60 Hz.

Standalone on master; the earlier copy stacked on the scan-out-size branch (joshuatam/GameNative#22) is closed.


Summary by cubic

Reports the panel's active refresh rate and scan-out size to the gndrm daemon so the latch grid and emulated mode track the real display instead of the fastest supported rate and the window's size.

Previously the daemon measured the latch grid against the panel's maximum rate, so a panel held at 60 Hz was tracked as a 120 Hz lattice and gave the shim an 8.33 ms latch period; with the active rate the period matches the real mode (16666 µs on the Odin 3). Separately, the emulated connector advertised the app window's size, so gamescope's -W/-H never matched a mode and the session always scanned out at the panel's pixel count.

  • One detectRefreshRateHz helper, reading display.refreshRate with a safe fallback, serves both the daemon and the FPS limiter's ceiling.
  • A DisplayManager.DisplayListener re-reports the rate on mode changes and is unregistered at session exit.
  • nativeSetScanoutGeometry sets the daemon's mode from the Upscaling Resolution; the default is now Off (1:1 at the container's screen size), and scanoutSize() feeds gamescope's -W/-H, the shim's seed, and the daemon from one value.
  • Payload bumped to 20261030.2 and the DRM .so rebuilt.

Summary by CodeRabbit

  • Bug Fixes
    • Improved refresh-rate detection to use the display’s current active mode, with a fallback when the rate is unavailable or invalid.
    • Games now receive the active display refresh rate at startup and when the display mode changes, helping keep frame-rate limits aligned with the screen. The display-change listener is also cleaned up when the game exits.