srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/udev/session.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-05-15 20:45:00 +0200
committersrdusr <[email protected]>2025-05-15 20:45:00 +0200
commit54195f079810410eb9456348e7e44d382d3c4d3f (patch)
tree2e7a2a47c66eeec8a3762e8b4a04124e8227f9ab /crates/wayland/src/udev/session.rs
parent317b3b269cc526b410b6d0c0666e16ae84832ef9 (diff)
downloadsrdwm-54195f079810410eb9456348e7e44d382d3c4d3f.tar.gz
srdwm-54195f079810410eb9456348e7e44d382d3c4d3f.zip
Extend GPU rendering to every head, not just the first
Phase 2 of the GPU-rendering plan deliberately targeted a single head (GpuContext::output: Option<(crtc::Handle, GpuOutput)>) as a narrow proof that GBM+EGL+DrmCompositor rendering works at all on this hardware. DrmOutputManager already supports driving several crtcs at once - initialize_output is a per-crtc call on one shared manager, the same way anvil drives multiple outputs - so this was purely an unexercised restriction, not an architectural limit. GpuContext::output is now GpuContext::outputs: Vec<(crtc::Handle, GpuOutput)>, and udev/platform.rs calls initialize_output for every connected head in its own bring-up loop instead of only the first after that loop finishes. A head this fails for individually (already logged, not fatal) still just has no entry and falls back to the existing legacy Pixman path, unchanged from before. session.rs's VBlank handler and its VT-switch resume path (which excludes GPU-driven crtcs from the legacy set_crtc reassert loop, a different device fd that must never issue mode-set commands against a crtc DrmOutputManager already owns) both now look a crtc up in the Vec instead of comparing against a single stored one. render.rs's own render-loop lookup uses direct field access (gpu.outputs.iter_mut().find(...)) rather than an equivalent &mut self method: the borrow checker treats a method call as borrowing all of GpuContext, including gpu.renderer needed a few lines later for the same head, where direct field access lets it see the two borrows are disjoint. Still gated behind SRDWM_GPU=1 (unset by default) and untested on real multi-monitor hardware with the flag on - this machine has one display, so the actual multi-head path itself only gets exercised whenever it's set on hardware that has more than one.
Diffstat (limited to 'crates/wayland/src/udev/session.rs')
-rw-r--r--crates/wayland/src/udev/session.rs40
1 files changed, 20 insertions, 20 deletions
diff --git a/crates/wayland/src/udev/session.rs b/crates/wayland/src/udev/session.rs
index 7423f4a..bf6eb67 100644
--- a/crates/wayland/src/udev/session.rs
+++ b/crates/wayland/src/udev/session.rs
@@ -67,11 +67,9 @@ pub(crate) fn register_gpu_drm_notifier(handle: &LoopHandle<'static, CompState>,
smithay::backend::drm::DrmEvent::VBlank(crtc) => {
if let Some(udev) = data.udev.as_mut() {
if let Some(gpu) = udev.gpu.as_ref() {
- if let Some((gpu_crtc, gpu_output)) = gpu.output.as_ref() {
- if *gpu_crtc == crtc {
- if let Err(e) = gpu_output.frame_submitted() {
- log::warn!("udev: SRDWM_GPU=1 frame_submitted failed for crtc {crtc:?}: {e:?}");
- }
+ if let Some(gpu_output) = gpu.output_for(crtc) {
+ if let Err(e) = gpu_output.frame_submitted() {
+ log::warn!("udev: SRDWM_GPU=1 frame_submitted failed for crtc {crtc:?}: {e:?}");
}
}
}
@@ -217,20 +215,22 @@ pub(crate) fn register_session_notifier(handle: &LoopHandle<'static, CompState>,
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);
+ // Every crtc `SRDWM_GPU=1`'s `DrmOutputManager` is
+ // driving (if any - now possibly several, since it
+ // targets every head it could, not just one) --
+ // 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_crtcs: Vec<crtc::Handle> = udev.gpu.as_ref().map(|g| g.outputs.iter().map(|(c, _)| *c).collect()).unwrap_or_default();
// Some drivers reset mode-setting state across a VT
// switch; reassert every (non-GPU-driven) head before
// rendering again.
@@ -242,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 udev.heads.iter_mut().filter(|h| Some(h.crtc) != gpu_crtc) {
+ for head in udev.heads.iter_mut().filter(|h| !gpu_crtcs.contains(&h.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}");