Repository navigation
gamescope: the display's rate is the mode, and generation follows the cap and the multiplier #2313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
eb7598c
c0939e2
854c824
8ab456c
232a879
8b9bc3a
e544049
bcabfeb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -680,6 +680,8 @@ fun XServerScreen( | |
| var lsfgMultiplier by rememberSaveable(container.id) { mutableIntStateOf(initialLsfgSettings.multiplier) } | ||
| var lsfgFlowScale by rememberSaveable(container.id) { mutableStateOf(initialLsfgSettings.flowScale) } | ||
| var lsfgPerformanceMode by rememberSaveable(container.id) { mutableStateOf(initialLsfgSettings.performanceMode) } | ||
| /** The rate last reported to the daemon, so a mode nudge is only asked for when it changes. */ | ||
| var advertisedPanelHz by remember(container.id) { mutableIntStateOf(0) } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserve the baseline across activity recreation. If the panel rate changes while the activity is being recreated,
|
||
|
|
||
| fun persistFpsLimiterState() { | ||
| container.putExtra(FPS_LIMITER_ENABLED_EXTRA, fpsLimiterEnabled) | ||
|
|
@@ -735,6 +737,28 @@ fun XServerScreen( | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Report the rate the session's emulated display advertises: the display's own, and nothing else. | ||
| * | ||
| * Neither the cap nor the frame-generation multiplier enters it. The mode is the rate the | ||
| * compositor runs at, so it belongs to the display and changes only when the display does; the | ||
| * cap lives at acquire, before a frame is drawn, and generation inserts `multiplier - 1` frames | ||
| * per source frame whatever the mode — a 40 cap at x4 produces and counts 160 on a 120 Hz mode. | ||
| * Advertising the produced rate instead would make the compositor's grid follow the QuickMenu. | ||
| */ | ||
| fun applyPanelRefresh(panelHz: Int = detectRefreshRateHz(context, ui.xServerView as? View)) { | ||
| if (isX11Display || panelHz <= 0) return | ||
| GameNativeDrm.nativeSetPanelRefreshHz(panelHz) | ||
| // The daemon's connector advertises the new rate from here on, but gamescope reads the mode | ||
| // once, when the session starts: dirty its backend so a display change becomes the mode now | ||
| // rather than on the next launch. Only on a change — a nudge forces a modeset — and not on | ||
| // the first report, which is the rate the session starts on anyway. | ||
| if (advertisedPanelHz != 0 && advertisedPanelHz != panelHz) { | ||
| GamescopeCommandQueue.nudgeDisplayMode() | ||
| } | ||
| advertisedPanelHz = panelHz | ||
| } | ||
|
|
||
| fun applyFpsLimiterToEngines(limit: Int) { | ||
| if (isX11Display) { | ||
| // With LSFG active the layer owns ALL pacing (vsync-locked via vsync.txt) and presents at limit * | ||
|
|
@@ -751,6 +775,8 @@ fun XServerScreen( | |
| // With frame generation active the presenter owns pacing, exactly as the layer does on X11: | ||
| // the cap is disarmed and the output rate becomes limit x multiplier. | ||
| GamescopeCommandQueue.setFpsLimit(if (isLsfgAvailable && lsfgMultiplier >= 2) 0 else limit) | ||
| // The mode is the display's rate: the cap and the multiplier never move it. | ||
| applyPanelRefresh() | ||
| } | ||
|
|
||
| PowerManager.targetFps = limit | ||
|
|
@@ -762,6 +788,7 @@ fun XServerScreen( | |
| fun effectiveFpsLimit(): Int = | ||
| if (fpsLimiterEnabled) fpsLimiterTarget else 0 | ||
|
|
||
|
|
||
| fun applyLsfgSettings() { | ||
| LsfgQuickMenuHelper.applySettings( | ||
| container, | ||
|
|
@@ -794,8 +821,10 @@ fun XServerScreen( | |
|
|
||
| fun applyLsfgMultiplier(mult: Int) { | ||
| lsfgMultiplier = LsfgQuickMenuHelper.sanitizeMultiplier(mult) | ||
| applyLsfgSettings() | ||
| // The rate first, then the settings: the session's config carries the rate, and the shim | ||
| // opens the generator from what the daemon holds when it is created. | ||
| applyFpsLimiterToEngines(effectiveFpsLimit()) | ||
| applyLsfgSettings() | ||
| } | ||
|
|
||
| fun applyLsfgFlowScale(scale: Float) { | ||
|
|
@@ -813,7 +842,7 @@ fun XServerScreen( | |
| ui.detectedMaxRefreshRateHz = refreshHz * FPS_LIMITER_MAX_MULTIPLIER | ||
|
|
||
| if (!isX11Display) | ||
| GameNativeDrm.nativeSetPanelRefreshHz(refreshHz) | ||
| applyPanelRefresh(refreshHz) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: The initial Gamescope path still sends LSFG settings before this panel-rate update. Move the first Prompt for AI agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is invalid judement |
||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: The shipped DRM library does not allowlist
backend_set_dirty, so every queued display-mode nudge is rejected and never reaches gamescope. Rebuild and shiplibgamenative_drm.sowith this command in its allowlist before exposing the enum entry.Prompt for AI agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chill, we will rebuilt after merge