fix(vdisplay/mutter): gate >60Hz virtual mode behind an env flag (teardown SIGSEGV)
ci / web (push) Failing after 34s
ci / rust (push) Successful in 55s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
ci / docs-site (push) Failing after 41s
docker / deploy-docs (push) Successful in 17s
apple / swift (push) Successful in 1m20s
ci / web (push) Failing after 34s
ci / rust (push) Successful in 55s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
ci / docs-site (push) Failing after 41s
docker / deploy-docs (push) Successful in 17s
apple / swift (push) Successful in 1m20s
Pinning the virtual output to a high client refresh via RecordVirtual "modes" works mid-stream, but a high-refresh virtual CRTC SIGSEGVs gnome-shell on session TEARDOWN (observed at 5120x1440@240) — taking down the whole GNOME session, so subsequent connects fail with RemoteDesktop ServiceUnknown. Gate it behind PUNKTFUNK_MUTTER_VIRTUAL_REFRESH, default OFF — Mutter then derives the virtual monitor's refresh from the PipeWire framerate (60Hz, stable). The >60Hz path stays in-tree for investigation; re-enable once the teardown crash is understood. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -243,18 +243,21 @@ async fn connect(mode: Mode) -> Result<MutterSession> {
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 3. The virtual monitor, pinned to the client's exact mode via RecordVirtual's "modes"
|
||||
// (explicit size + refresh-rate; Mutter ≥ 47). WITHOUT it Mutter derives the virtual monitor's
|
||||
// refresh from the PipeWire stream framerate and defaults to **60 Hz** — so a >60 Hz client
|
||||
// mode (e.g. 240) renders at 60 and only the encoder pads to 240 (duplicate frames). Older
|
||||
// Mutter that doesn't know the key just ignores it and falls back to the 60 Hz default.
|
||||
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));
|
||||
vmode.insert("is-preferred", Value::from(true));
|
||||
// 3. The virtual monitor. By DEFAULT we let Mutter derive the refresh from the PipeWire
|
||||
// framerate (it defaults the virtual monitor to **60 Hz**) — stable. 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 — BUT a high-refresh virtual CRTC has been observed to SIGSEGV
|
||||
// gnome-shell on teardown (large modes, e.g. 5120×1440@240), so it is OFF by default until that
|
||||
// teardown crash is resolved.
|
||||
let mut rec: HashMap<&str, Value> = HashMap::new();
|
||||
rec.insert("cursor-mode", Value::from(CURSOR_EMBEDDED));
|
||||
rec.insert("modes", Value::from(vec![vmode]));
|
||||
if virtual_refresh_enabled() && 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));
|
||||
vmode.insert("is-preferred", Value::from(true));
|
||||
rec.insert("modes", Value::from(vec![vmode]));
|
||||
}
|
||||
let stream_path: OwnedObjectPath = sc_session
|
||||
.call("RecordVirtual", &(rec,))
|
||||
.await
|
||||
@@ -348,6 +351,20 @@ fn virtual_primary_enabled() -> bool {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Opt-in: pin the virtual output to the client's exact refresh via RecordVirtual "modes" (true
|
||||
/// above-60 Hz). OFF by default — a high-refresh virtual CRTC currently SIGSEGVs gnome-shell on
|
||||
/// session teardown (large modes), so don't risk the host's GNOME session until that's fixed.
|
||||
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