srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/udev/session.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-03-26 00:26:00 +0200
committersrdusr <[email protected]>2025-03-26 00:26:00 +0200
commit0d3c7ab727b321a36ffea66c461221b14bbc48d8 (patch)
treebdbafccf64086d732af38ca37a005c4c4911ac32 /crates/wayland/src/udev/session.rs
parentef4bc112b8507880ddfa53ffce45505762384612 (diff)
downloadsrdwm-0d3c7ab727b321a36ffea66c461221b14bbc48d8.tar.gz
srdwm-0d3c7ab727b321a36ffea66c461221b14bbc48d8.zip
Wire real GBM+EGL+DrmCompositor rendering for one head (GPU Phase 2)
Extends the SRDWM_GPU=1 opt-in path (Phase 1, fa0c7f1) from a capability probe into an actual, working GPU render pipeline for exactly one head, per the plan this was built from the plan file. gpu.rs: probe now goes all the way through EGLContext, GlesRenderer, DrmDevice (real DRM device, separate duped fd from the existing legacy Card), and DrmOutputManager construction, returning both a GpuContext and its DrmDeviceNotifier on success. GpuContext::initialize_output drives one crtc/mode/connector through DrmOutputManager, storing the resulting GpuOutput for the render loop to find. Confirmed while reading smithay's own source directly (not assumed): DrmDevice::new's disable_connectors parameter is not an atomic-vs- legacy switch - DrmDevice::create_internal tries atomic capability first and falls back to a Legacy internal variant automatically, exposed via DrmDevice::is_atomic(), logged here rather than assumed. platform.rs: probes at startup, calls initialize_output for the first head only (Phase 2's deliberate scope - see the plan), registers the DrmDeviceNotifier as its own calloop event source alongside (not replacing) the existing legacy DRM-fd registration. render.rs: render_udev_frame's per-head loop checks, before any of the existing Pixman-specific element-building logic runs, whether this head's crtc matches the GPU context's initialized output; if so, renders a plain clear color through render_frame/queue_frame and continues to the next head, completely bypassing the Pixman path for that head. Every other head, and this same head whenever the GPU context or its output is absent, is entirely unaffected. session.rs: register_gpu_drm_notifier handles DrmEvent::VBlank by calling frame_submitted() on the matching GpuOutput (required per queue_frame's own doc comment, or the swapchain runs out of buffers) and logs DrmEvent::Error without treating it as fatal. Deliberately out of scope for this phase (documented in the plan): window content/decorations/cursor on the GPU head (clear color only), multi-monitor GPU rendering (one head only), and VT-switch pause/ resume for the GPU head specifically (DrmOutputManager's own pause()/ activate() calls are a different API surface from the existing manual set_crtc+DPMS reassertion, and porting that pairing correctly needs its own isolated verification pass). SRDWM_GPU unset (the default) is unaffected: every step above only runs when it's set to "1", and every failure at any step falls back to the existing, untouched Pixman path with a logged reason, same fallback contract Phase 1 already established.
Diffstat (limited to 'crates/wayland/src/udev/session.rs')
-rw-r--r--crates/wayland/src/udev/session.rs45
1 files changed, 45 insertions, 0 deletions
diff --git a/crates/wayland/src/udev/session.rs b/crates/wayland/src/udev/session.rs
index 196740b..a45cccd 100644
--- a/crates/wayland/src/udev/session.rs
+++ b/crates/wayland/src/udev/session.rs
@@ -38,6 +38,51 @@ pub(crate) fn register_drm_fd(handle: &LoopHandle<'static, CompState>, card: &Rc
Ok(())
}
+/// Registers the `DrmDeviceNotifier` [`gpu::probe`](super::gpu::probe)
+/// returns on success as its own calloop event source - a real,
+/// independent `DrmDevice`/fd from the legacy one [`register_drm_fd`]
+/// above already watches, so this is a second, parallel registration, not
+/// a replacement. Only called from `udev/platform.rs`'s startup path when
+/// `SRDWM_GPU=1` and the probe actually succeeded; a no-op (never called
+/// at all) otherwise.
+///
+/// `DrmEvent::VBlank` marks the matching `GpuOutput` (if any - `udev.gpu`
+/// might still be mid-construction, or the crtc might not be this
+/// backend's GPU-driven one) as having had its frame actually scanned
+/// out, via `frame_submitted()` - required by `DrmOutput::queue_frame`'s
+/// own doc comment (see `render_udev_frame`'s GPU branch), or the
+/// underlying swapchain eventually runs out of buffers. `DrmEvent::Error`
+/// is logged, not treated as fatal - matching every other error-handling
+/// choice in this GPU path, which always prefers "log and keep going" over
+/// tearing down the whole session for an experimental, opt-in feature.
+pub(crate) fn register_gpu_drm_notifier(handle: &LoopHandle<'static, CompState>, notifier: smithay::backend::drm::DrmDeviceNotifier) -> PlatformResult<()> {
+ // Fully qualified, not the bare `DrmEvent` this module's own `use
+ // super::*` already brings in - that name is `drm::control::Event`
+ // (the legacy raw drm-rs event type `register_drm_fd` above reads via
+ // `card.receive_events()`, with a `PageFlip` variant), a different
+ // type from smithay's own higher-level `backend::drm::DrmEvent` (with
+ // `Vblank`/`Error` variants) this notifier actually produces.
+ handle
+ .insert_source(notifier, move |event, _metadata, data: &mut CompState| match event {
+ 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:?}");
+ }
+ }
+ }
+ }
+ }
+ }
+ smithay::backend::drm::DrmEvent::Error(e) => log::warn!("udev: SRDWM_GPU=1 DrmDevice error: {e:?}"),
+ })
+ .map_err(|e| PlatformError::Other(format!("failed to register GPU DRM notifier: {e}")))?;
+ Ok(())
+}
+
/// Registers the real libinput event source and hands back a second,
/// reference-counted handle onto the exact same underlying context (`Libinput`
/// wraps a `libinput_ref`/`libinput_unref`-counted C pointer - see its own