feat(vdisplay/mutter): pin the client's refresh by default; drop PUNKTFUNK_MUTTER_VIRTUAL_REFRESH
The >60 Hz virtual-monitor path (RecordVirtual "modes" with the client's exact WxH@Hz) was gated behind PUNKTFUNK_MUTTER_VIRTUAL_REFRESH, default OFF, after a high-refresh virtual CRTC SIGSEGV'd gnome-shell on session teardown. That crash was since fixed by stopping the screencast before any monitor reconfig, so the gate is dead weight — and a silent footgun: every non-headless GNOME client was capped at Mutter's PipeWire-derived 60 Hz unless they knew the hidden flag. Make it the default: the custom-mode path now runs whenever mode.refresh_hz > 60 (≤60 Hz stays byte-identical to before — Mutter's 60 Hz default is already correct), and the virtual_refresh_enabled() env read is removed. Docs updated (configuration.md env table, vrr-plan.md reference). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -285,15 +285,16 @@ async fn connect(mode: Mode) -> Result<MutterSession> {
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 3. The virtual monitor. By DEFAULT we let Mutter derive the refresh from the PipeWire
|
||||
// framerate (it defaults the virtual monitor to 60 Hz) — universally safe.
|
||||
// PUNKTFUNK_MUTTER_VIRTUAL_REFRESH=1 pins the client's exact WxH@Hz via RecordVirtual's "modes"
|
||||
// (explicit size + refresh-rate; Mutter ≥ 47) for true >60 Hz — validated at 5120×1440@240 on
|
||||
// Mutter 50 + NVIDIA. (A high-refresh virtual CRTC used to SIGSEGV gnome-shell on teardown; the
|
||||
// stop-screencast-before-any-monitor-reconfig teardown below avoids that.)
|
||||
// 3. The virtual monitor. For >60 Hz we pin the client's exact WxH@Hz via RecordVirtual's
|
||||
// "modes" (explicit size + refresh-rate; Mutter ≥ 47) — validated at 5120×1440@240 on Mutter 50
|
||||
// + NVIDIA. At ≤60 Hz we let Mutter derive the refresh from the PipeWire framerate (its 60 Hz
|
||||
// default is already correct), so the custom-mode path only runs when it buys something.
|
||||
// (A high-refresh virtual CRTC used to SIGSEGV gnome-shell on teardown, which is why this was
|
||||
// once gated behind PUNKTFUNK_MUTTER_VIRTUAL_REFRESH; the stop-screencast-before-any-monitor-
|
||||
// reconfig teardown below fixed the crash, so pinning the client's refresh is now the default.)
|
||||
let mut rec: HashMap<&str, Value> = HashMap::new();
|
||||
rec.insert("cursor-mode", Value::from(CURSOR_EMBEDDED));
|
||||
if virtual_refresh_enabled() && mode.refresh_hz > 60 {
|
||||
if mode.refresh_hz > 60 {
|
||||
let mut vmode: HashMap<&str, Value> = HashMap::new();
|
||||
vmode.insert("size", Value::from((mode.width, mode.height)));
|
||||
vmode.insert("refresh-rate", Value::from(mode.refresh_hz as f64));
|
||||
@@ -382,22 +383,6 @@ type CurrentState = (
|
||||
type ApplyMon = (String, String, HashMap<String, Value<'static>>); // connector, mode_id, props
|
||||
type ApplyLogical = (i32, i32, f64, u32, bool, Vec<ApplyMon>);
|
||||
|
||||
/// Opt-in: pin the virtual output to the client's exact refresh via RecordVirtual "modes" (true
|
||||
/// above-60 Hz). Off by default — Mutter-derived 60 Hz is safe on every host; high-refresh virtual
|
||||
/// CRTCs are validated on Mutter 50 + NVIDIA but behaviour can vary, so it stays opt-in. (The
|
||||
/// teardown SIGSEGV that first motivated this gate is fixed by stopping the screencast before any
|
||||
/// monitor-config change.)
|
||||
fn virtual_refresh_enabled() -> bool {
|
||||
std::env::var("PUNKTFUNK_MUTTER_VIRTUAL_REFRESH")
|
||||
.map(|v| {
|
||||
matches!(
|
||||
v.trim().to_ascii_lowercase().as_str(),
|
||||
"1" | "true" | "yes" | "on"
|
||||
)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// A DisplayConfig proxy on its own session-bus connection (owned, so it stays alive for the
|
||||
/// session — independent of the RemoteDesktop/ScreenCast connection).
|
||||
async fn display_config() -> Result<zbus::Proxy<'static>> {
|
||||
|
||||
Reference in New Issue
Block a user