srdusr
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-04-02 23:40:00 +0200
committersrdusr <[email protected]>2025-04-02 23:40:00 +0200
commit4d61d76b1b73f56fc14ed977806e4d4ad313fd51 (patch)
treeb6fd51ef7287deb99ddfb907cac35cb48c61750a
parent0d3c7ab727b321a36ffea66c461221b14bbc48d8 (diff)
downloadsrdwm-4d61d76b1b73f56fc14ed977806e4d4ad313fd51.tar.gz
srdwm-4d61d76b1b73f56fc14ed977806e4d4ad313fd51.zip
Wire VT-switch pause/activate for the GPU render path
Phase 2 (0274273) deliberately shipped without VT-switch support for the GPU-driven head, documented as an explicit gap rather than a silent risk. Before testing it live, wire the real fix instead of finding out empirically - this already burned three real reboots getting the *legacy* VT-switch path right, and DrmOutputManager uses a genuinely different API surface (pause()/activate(), calling through to DrmDevice's own master-lock acquire/release) than the manual set_crtc+DPMS reassertion register_session_notifier already does for legacy heads. PauseSession now also calls DrmOutputManager::pause() when SRDWM_GPU=1 and a GPU context exists - a separate device/fd from the legacy Card, so purely additive. ActivateSession calls DrmOutputManager::activate (false), then deliberately does *not* also force a fresh render for that head specifically: DrmCompositor::render_frame always issues a full state commit (atomic or legacy, whichever this device negotiated - see DrmDevice::is_atomic()), not just a buffer swap, so the existing data.render_udev_frame() call at the end of this handler already reasserts mode-set and CRTC-active state together for the GPU head via render.rs's own GPU branch, the same way it always does. Also fixed a real conflict Phase 2 introduced: the existing legacy crtc-reassert loop (explicit set_crtc through the legacy Card/fd) used to run for every head unconditionally, including one now driven by the GPU path through a completely different DrmDeviceFd - two separate fds issuing mode-set commands against the same physical CRTC, exactly the kind of conflict that produced the worst VT-switch incidents (EBUSY loops) when it was really one fd racing itself. The GPU-owned crtc (if any) is now excluded from that loop.
-rw-r--r--crates/wayland/src/udev/session.rs55
1 files changed, 53 insertions, 2 deletions
diff --git a/crates/wayland/src/udev/session.rs b/crates/wayland/src/udev/session.rs
index a45cccd..7423f4a 100644
--- a/crates/wayland/src/udev/session.rs
+++ b/crates/wayland/src/udev/session.rs
@@ -129,6 +129,16 @@ pub(crate) fn register_session_notifier(handle: &LoopHandle<'static, CompState>,
// doc comment below for why the other half of this pair
// is not optional at all.
libinput.suspend();
+ // `SRDWM_GPU=1` only - see `gpu::probe`'s own doc
+ // comment. `DrmOutputManager::pause` (-> `DrmDevice::
+ // pause`) drops this device's own DRM master lock and
+ // marks it inactive, the same pairing `anvil` itself
+ // uses around a VT switch - a separate device/fd from
+ // the legacy `Card` above, so this is additive, not a
+ // substitute for anything already happening here.
+ if let Some(gpu) = udev.gpu.as_mut() {
+ gpu.output_manager.pause();
+ }
}
SessionEvent::ActivateSession => {
log::info!("udev: session resumed (VT switch back)");
@@ -181,8 +191,49 @@ pub(crate) fn register_session_notifier(handle: &LoopHandle<'static, CompState>,
Err(e) => log::debug!("udev: no pending flip events to drain on resume: {e}"),
}
+ // `SRDWM_GPU=1` only. `DrmOutputManager::activate` (->
+ // `DrmDevice::activate`) re-acquires this device's own
+ // DRM master lock - a separate device/fd from the
+ // legacy `Card` below, so this can run regardless of
+ // whether any legacy head also needs reasserting.
+ // Deliberately does *not* also force a fresh render
+ // here: `data.render_udev_frame()` at the end of this
+ // arm already reaches the GPU head unconditionally
+ // (`render.rs`'s GPU branch), and `DrmCompositor::
+ // render_frame` always issues a full state commit --
+ // atomic or legacy, whichever this specific device
+ // negotiated (see `gpu::probe`'s own doc comment) --
+ // not just a buffer swap, so that one call already
+ // reasserts mode-set and CRTC-active state together,
+ // unlike the legacy heads below, which need `set_crtc`
+ // called explicitly first because their own flip path
+ // (`copy_and_flip`) only ever swaps the buffer.
+ // `disable_connectors: false` - matches this
+ // compositor's own control over which connectors are
+ // actually driven (`disabled_connectors`), not
+ // something this resume path should reset.
+ if let Some(gpu) = udev.gpu.as_mut() {
+ if let Err(e) = gpu.output_manager.activate(false) {
+ log::warn!("udev: SRDWM_GPU=1 failed to reactivate DrmOutputManager on resume: {e}");
+ }
+ }
+ // The crtc `SRDWM_GPU=1`'s `DrmOutputManager` is driving
+ // (if any) - excluded from the legacy reassert loop
+ // below, since that loop's `set_crtc` runs through the
+ // *legacy* `Card`/fd, a completely different device
+ // handle than the GPU path's own `DrmDeviceFd`. Two
+ // separate fds issuing mode-set commands against the
+ // same physical CRTC is exactly the kind of conflict
+ // that produced this session's own worst VT-switch
+ // incidents when it was really one fd racing itself
+ // (`EBUSY` loops - see `UdevHead::flip_retry_after`'s
+ // own doc comment) - not a risk worth re-introducing
+ // here for a head this resume path already just
+ // reactivated correctly through its own, real API.
+ let gpu_crtc = udev.gpu.as_ref().and_then(|g| g.output.as_ref()).map(|(crtc, _)| *crtc);
// Some drivers reset mode-setting state across a VT
- // switch; reassert every head before rendering again.
+ // switch; reassert every (non-GPU-driven) head before
+ // rendering again.
//
// The real connector and mode, not an empty connector
// list and no mode - that shape is DRM/KMS's own way
@@ -191,7 +242,7 @@ pub(crate) fn register_session_notifier(handle: &LoopHandle<'static, CompState>,
// switching back with no further VT switch, either
// direction, able to recover it. See `UdevHead::mode`'s
// own doc comment.
- for head in &mut udev.heads {
+ for head in udev.heads.iter_mut().filter(|h| Some(h.crtc) != gpu_crtc) {
let fb = head.buffers[head.front].fb;
if let Err(e) = card.set_crtc(head.crtc, Some(fb), (0, 0), &[head.connector], Some(head.mode)) {
log::warn!("udev: failed to reassert crtc on resume: {e}");