srdusr
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-08-08 23:28:00 +0200
committersrdusr <[email protected]>2025-08-08 23:28:00 +0200
commit9e811d2f2f1037ba4ec08ab0e05b350e6cf69e66 (patch)
tree2fa3f095b5f67769eca0eb9115faaf93fa37c0ae
parent5f26a48fbb772ccc9c9ffb1209ff00d3c11d88c7 (diff)
downloadsrdwm-9e811d2f2f1037ba4ec08ab0e05b350e6cf69e66.tar.gz
srdwm-9e811d2f2f1037ba4ec08ab0e05b350e6cf69e66.zip
Render real window content on the GPU render path
Past clear-color + cursor: a GPU-driven head now renders every visible window's real content too, via surface_content_elements (the same generic-over-renderer helper the Pixman path uses, unmodified against gpu.renderer instead of udev.renderer). Content pushed after the cursor (so the cursor stays on top), in the same front-to-back `ids` order the Pixman path's own custom_elements already relies on for correct occlusion between windows - plain painter's-algorithm draw order, no separate clip needed since content is window-shaped. Deliberately the *unrounded* path: no corner masking (that's built against PixmanRenderer specifically on this backend) and no decorations (border, titlebar) - a GPU-driven head now shows real window content, square corners, no chrome. Decorations are the remaining real gap before this path has parity with the software one. Per-window geometry/position math (geom from window_anims or w.geometry, band for a decorated window's titlebar reservation, content_offset clamped non-negative) mirrors the Pixman path's own content push exactly, including an earlier double- subtraction and negative-margin fixes - so a CSD client with a real shadow margin positions the same way on either render path. Untested on real GPU-enabled hardware as of this writing: builds, passes clippy, full test suite green, and matches the existing Pixman path's geometry logic by inspection, but SRDWM_GPU/general.gpu were both unset on the machine this was built on - noted honestly in gpu.rs's own module doc comment, DEFAULTS.md, and IMPLEMENTATION_STATUS.md.
-rw-r--r--crates/wayland/src/udev/gpu.rs17
-rw-r--r--crates/wayland/src/udev/render.rs45
-rw-r--r--docs/DEFAULTS.md13
-rw-r--r--docs/IMPLEMENTATION_STATUS.md9
4 files changed, 56 insertions, 28 deletions
diff --git a/crates/wayland/src/udev/gpu.rs b/crates/wayland/src/udev/gpu.rs
index 8617af1..7b06ae3 100644
--- a/crates/wayland/src/udev/gpu.rs
+++ b/crates/wayland/src/udev/gpu.rs
@@ -6,10 +6,19 @@
//! percolating-boole.md`, for that phase's own scoping): every head
//! `initialize_output` succeeds for gets driven, not just the first
//! (`GpuContext::outputs`), VT-switch pause/activate is wired
-//! (`udev/session.rs`'s `SessionEvent` handlers), and the real cursor
-//! renders on top of the clear color (`udev/render.rs`'s own GPU branch).
-//! Window content and decorations are the remaining gap - a GPU-driven
-//! head still shows no windows, just its own clear color and cursor.
+//! (`udev/session.rs`'s `SessionEvent` handlers), and the real cursor and
+//! real window content both render on top of the clear color
+//! (`udev/render.rs`'s own GPU branch). Window content is plain
+//! `surface_content_elements` - square corners, no border or titlebar --
+//! not yet the masked/rounded path the Pixman branch uses (built against
+//! `PixmanRenderer` specifically) or the GLES shader `winit/render.rs`
+//! already has for its own single-output case; decorations (border,
+//! titlebar) are the remaining real gap. Untested on real GPU-enabled
+//! hardware as of this writing - `SRDWM_GPU`/`general.gpu` were both
+//! unset on the machine this was built on, so this compiles, passes the
+//! full test suite, and matches the existing Pixman path's own per-
+//! window geometry logic by inspection, but has not been visually
+//! confirmed against a real compositor session with the flag on.
use std::os::fd::{AsFd, OwnedFd};
diff --git a/crates/wayland/src/udev/render.rs b/crates/wayland/src/udev/render.rs
index 4d51fab..0250c8a 100644
--- a/crates/wayland/src/udev/render.rs
+++ b/crates/wayland/src/udev/render.rs
@@ -232,21 +232,36 @@ impl CompState {
// field access, not a method call, even one that (like
// this one) only actually touches `self.outputs`.
if let Some(gpu_output) = gpu.outputs.iter_mut().find(|(c, _)| *c == head_crtc).map(|(_, o)| o) {
- // The one real element this phase pushes: the same
- // `cursor::render_elements` the Pixman path already
- // uses, generic over the renderer (`R: Renderer +
- // ImportAll + ImportMem`), so it works unmodified
- // against `gpu.renderer` (`GlesRenderer`) instead of
- // `udev.renderer` (`PixmanRenderer`). Window content
- // and decorations are real, separate scope past this
- // (they need either a GLES-side version of the
- // border/titlebar bitmap upload path, or the rounded-
- // corner GLES shader `winit/render.rs` already has
- // wired for its own single-output case) - not
- // attempted here, so a GPU-driven head still shows a
- // plain clear color under its own real, moving cursor,
- // not yet any windows.
- let elements = crate::cursor::render_elements(&cursor_status, &cursor_buffers, &mut gpu.renderer, udev.pointer_pos, origin, udev.heads[index].size);
+ // Cursor first (topmost - `render_frame` draws
+ // earliest-pushed on top, same convention the Pixman
+ // path's own `custom_elements` uses), content after.
+ // `ids` is already front-to-back (topmost window
+ // first), and pushing in that same order is what
+ // makes plain painter's-algorithm draw order occlude
+ // correctly between windows, same as the Pixman
+ // path's own `custom_elements` relies on (see its own
+ // comment on `occluders` above). Plain
+ // `surface_content_elements` - unrounded, no
+ // decorations - not the masked/rounded path the
+ // Pixman branch uses (that's built against
+ // `PixmanRenderer` specifically) or the GLES shader
+ // `winit/render.rs` has (real, separate scope to wire
+ // in here too). A GPU-driven head shows real window
+ // content now, square corners and no border/titlebar,
+ // rather than none at all.
+ let mut elements: Vec<crate::elements::OverlayElement<smithay::backend::renderer::gles::GlesRenderer>> =
+ crate::cursor::render_elements(&cursor_status, &cursor_buffers, &mut gpu.renderer, udev.pointer_pos, origin, udev.heads[index].size);
+ for &id in &ids {
+ let Some(w) = self.wm.borrow().window(id).cloned() else { continue };
+ let Some(dwindow) = self.id_to_window.get(&id) else { continue };
+ let Some(surface) = crate::elements::window_wl_surface(dwindow) else { continue };
+ let geom = self.window_anims.get(&id).map(crate::state::WindowAnim::current_rect).unwrap_or(w.geometry);
+ let band = if w.decorated { srdwm_core::TITLEBAR_HEIGHT as i32 } else { 0 };
+ let raw_offset = dwindow.geometry().loc;
+ let content_offset = Point::<i32, Logical>::from((raw_offset.x.max(0), raw_offset.y.max(0)));
+ let pos = (geom.x - origin.x - content_offset.x, geom.y + band - origin.y - content_offset.y);
+ elements.extend(crate::elements::surface_content_elements(&mut gpu.renderer, &surface, pos, w.opacity));
+ }
let clear_color = [0.05, 0.05, 0.08, 1.0];
match gpu_output.render_frame(&mut gpu.renderer, &elements, clear_color, smithay::backend::drm::compositor::FrameFlags::DEFAULT) {
Ok(res) if !res.is_empty => match gpu_output.queue_frame(None) {
diff --git a/docs/DEFAULTS.md b/docs/DEFAULTS.md
index ac18f7c..7e712c5 100644
--- a/docs/DEFAULTS.md
+++ b/docs/DEFAULTS.md
@@ -45,12 +45,13 @@ Read once at startup, not live-settable via `srd set` - the render
backend is wired into the DRM pipeline when the compositor connects to
its GPU, not something that can be swapped while running.
-Still missing real window content and decorations as of this writing:
-a GPU-driven head renders its own clear color and the real cursor, not
-yet any windows - see `crates/wayland/src/udev/gpu.rs`'s own module
-doc comment for the current state. `SRDWM_GPU=1` (an environment
-variable) remains a separate, lower-level override for testing without
-touching config - either it or `general.gpu` being set is enough to
+Still missing decorations (border, titlebar) as of this writing: a
+GPU-driven head renders its own clear color, the real cursor, and real
+window content (plain, square-cornered, no border/titlebar) - see
+`crates/wayland/src/udev/gpu.rs`'s own module doc comment for the
+current state. `SRDWM_GPU=1` (an environment variable) remains a
+separate, lower-level override for testing without touching config --
+either it or `general.gpu` being set is enough to
attempt GPU rendering.
### Monitor Settings (`monitor.*`)
diff --git a/docs/IMPLEMENTATION_STATUS.md b/docs/IMPLEMENTATION_STATUS.md
index 3365831..6fe207b 100644
--- a/docs/IMPLEMENTATION_STATUS.md
+++ b/docs/IMPLEMENTATION_STATUS.md
@@ -159,9 +159,12 @@ once, so splitting it across three files would have hidden it.
otherwise), falling back to the software path unchanged on any
failure at any step. Every connected head it successfully initializes
gets driven through it, VT-switch pause/activate is wired, and the
- real cursor renders on top of its own clear color - window content
- and decorations are the remaining gap: a GPU-driven head shows no
- windows yet, only its clear color and cursor.
+ real cursor and real window content (plain, square-cornered, no
+ border/titlebar yet) both render on top of its own clear color --
+ decorations are the remaining gap. Untested on real GPU-enabled
+ hardware as of this writing - builds and passes the full test suite,
+ but `SRDWM_GPU`/`general.gpu` were both unset on the machine this was
+ built on.
`WaylandPlatform::connect` (winit) picks this backend
automatically when no `WAYLAND_DISPLAY`/`DISPLAY` is set, falling back to
nested winit if udev init fails for any reason.