diff options
| -rw-r--r-- | crates/wayland/Cargo.toml | 7 | ||||
| -rw-r--r-- | crates/wayland/src/udev/gpu.rs | 97 | ||||
| -rw-r--r-- | crates/wayland/src/udev/mod.rs | 1 | ||||
| -rw-r--r-- | crates/wayland/src/udev/platform.rs | 5 |
4 files changed, 110 insertions, 0 deletions
diff --git a/crates/wayland/Cargo.toml b/crates/wayland/Cargo.toml index 1ddddc6..ac6f771 100644 --- a/crates/wayland/Cargo.toml +++ b/crates/wayland/Cargo.toml @@ -62,6 +62,13 @@ features = [ "backend_libinput", "backend_udev", "backend_session_libseat", + # `backend_egl`/`backend_gbm`: the udev backend's opt-in (`SRDWM_GPU=1`) + # GPU render path - see `udev/gpu.rs`'s own module doc comment. Additive + # to the existing `renderer_pixman` dumb-buffer path below, not a + # replacement: that path stays the default for portability (a low-spec + # machine or a VM with no GBM/3D support still needs it to work). + "backend_egl", + "backend_gbm", "renderer_gl", "renderer_pixman", "desktop", diff --git a/crates/wayland/src/udev/gpu.rs b/crates/wayland/src/udev/gpu.rs new file mode 100644 index 0000000..5b21171 --- /dev/null +++ b/crates/wayland/src/udev/gpu.rs @@ -0,0 +1,97 @@ +//! Opt-in (`SRDWM_GPU=1`) capability probe for a real GBM+EGL GPU render +//! path on the udev backend - see [`probe`]'s own doc comment for exactly +//! what this does and does not do yet. + +use std::os::fd::{AsFd, OwnedFd}; + +use smithay::backend::egl::{EGLDevice, EGLDisplay}; +use smithay::reexports::gbm::Device as GbmDevice; +use smithay::reexports::rustix; + +use super::Card; + +/// Marker returned by a successful probe. Carries no data yet - see +/// [`probe`]'s own doc comment for why - this exists purely to answer, +/// definitively and safely, "does GBM+EGL actually initialize on this exact +/// machine's DRM device" (logged from inside `probe` itself) as a plain +/// `bool`-shaped `Option` a future caller can match on once there's +/// something to actually do with a `Some`. +pub(crate) struct GpuProbe; + +/// Attempts GBM device creation plus an EGL display/device query against +/// `card`'s DRM fd, gated behind `SRDWM_GPU=1` (unset - the default -- +/// skips this entirely: zero cost, zero risk, identical to every session +/// before this one). Returns `None` on *any* failure at any step, each +/// logged with which step failed and why, so a machine without working +/// KMS+3D driver support (or a VM with only dumb-buffer scanout - this +/// backend's own long-standing default target, see `udev/mod.rs`'s module +/// doc comment) gets one clear, harmless log line instead of anything +/// touching the actual rendering/modesetting this backend already does. +/// +/// Deliberately does **not** yet create an `EGLContext`, a `GlesRenderer`, +/// or touch scanout at all. Reading smithay's own reference compositor +/// (`anvil/src/udev.rs`) confirmed it wires GBM+EGL rendering together with +/// *atomic*-KMS scanout as one unit via `DrmCompositor`, not as a renderer +/// swapped into the existing legacy `set_crtc`/`page_flip` flip loop this +/// backend uses today. Adopting `DrmCompositor` is real, separate, +/// larger-scoped work than "swap the renderer" - it replaces the same +/// `UdevHead` mode-set/flip machinery this session's own VT-switch fixes +/// (`register_session_notifier`'s `ActivateSession` arm, `copy_and_flip`'s +/// retry backoff) live in, and needs its own plan. This probe answers the +/// *first* question - does the hardware even support it at all - safely, +/// before that larger integration is scoped and attempted. +pub(crate) fn probe(card: &Card) -> Option<GpuProbe> { + if std::env::var("SRDWM_GPU").as_deref() != Ok("1") { + return None; + } + // GBM wants its own fd, not the one this backend's KMS control-plane + // ioctls (`set_crtc`, `page_flip`, property gets/sets) already share + // via `Rc<Card>` - duplicated here rather than reusing `card`'s own + // fd directly, both because `gbm::Device`'s `EGLNativeDisplay` impl + // needs `T: Send + 'static` (an `Rc`-shared `Card` is neither) and + // because giving GBM a fd genuinely separate from the control-plane + // one matches real compositor practice, not just this one's + // convenience. + let dup_fd: OwnedFd = match rustix::io::dup(card.as_fd()) { + Ok(fd) => fd, + Err(e) => { + log::warn!("udev: SRDWM_GPU=1 but failed to dup the DRM fd for GBM: {e} - staying on the software (Pixman) render path"); + return None; + } + }; + let gbm = match GbmDevice::new(dup_fd) { + Ok(gbm) => gbm, + Err(e) => { + log::warn!("udev: SRDWM_GPU=1 but GBM device creation failed: {e} - staying on the software (Pixman) render path"); + return None; + } + }; + // Safety: `gbm` owns its own fd (the dup above), stays alive for as + // long as this function needs it, and is a real GBM device - exactly + // what `EGLDisplay::new`'s own safety contract (a native display handle + // that outlives the `EGLDisplay`) requires. + let display = match unsafe { EGLDisplay::new(gbm) } { + Ok(d) => d, + Err(e) => { + log::warn!("udev: SRDWM_GPU=1 but EGL display creation failed: {e} - staying on the software (Pixman) render path"); + return None; + } + }; + let egl_device = match EGLDevice::device_for_display(&display) { + Ok(d) => d, + Err(e) => { + log::warn!("udev: SRDWM_GPU=1 but no EGL device found for this display: {e} - staying on the software (Pixman) render path"); + return None; + } + }; + if egl_device.is_software() { + log::warn!("udev: SRDWM_GPU=1 but the only EGL device found is a software rasterizer - staying on the software (Pixman) render path"); + return None; + } + let render_node = egl_device.try_get_render_node().ok().flatten(); + log::info!( + "udev: SRDWM_GPU=1 - GBM+EGL capability confirmed on this hardware (render node: {render_node:?}). \ + Full GPU rendering isn't wired up yet (see gpu::probe's own doc comment); still rendering via Pixman for now." + ); + Some(GpuProbe) +} diff --git a/crates/wayland/src/udev/mod.rs b/crates/wayland/src/udev/mod.rs index 4762992..b5529c4 100644 --- a/crates/wayland/src/udev/mod.rs +++ b/crates/wayland/src/udev/mod.rs @@ -531,6 +531,7 @@ mod copy_damaged_rows_tests { mod capture; mod drm; +pub(crate) mod gpu; mod outputs; mod platform; mod render; diff --git a/crates/wayland/src/udev/platform.rs b/crates/wayland/src/udev/platform.rs index 96d5cf2..3f25c2e 100644 --- a/crates/wayland/src/udev/platform.rs +++ b/crates/wayland/src/udev/platform.rs @@ -36,6 +36,11 @@ impl UdevPlatform { .open(&gpu_path, rustix::fs::OFlags::RDWR | rustix::fs::OFlags::CLOEXEC) .map_err(err)?; let card = Rc::new(Card(fd)); + // Opt-in only (`SRDWM_GPU=1`, unset by default) - see `gpu::probe`'s + // own doc comment for exactly what this does and does not do yet. + // A no-op unless that variable is set, so this line changes nothing + // about any session that doesn't set it. + let _gpu_probe = super::gpu::probe(&card); // Every connected connector becomes a head, laid out left-to-right. let connected = probe_connected(&card)?; |