srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-11-20 15:52:00 +0200
committersrdusr <[email protected]>2025-11-20 15:52:00 +0200
commit04466601f4714dcbc1f3b0ef134febede6febb6a (patch)
tree53d65fec45a7236a0efad5986960cffdbe60b5f0 /crates/wayland
parent0d752ed0401fabbd22763eea1a8ff587d585f55d (diff)
downloadsrdwm-04466601f4714dcbc1f3b0ef134febede6febb6a.tar.gz
srdwm-04466601f4714dcbc1f3b0ef134febede6febb6a.zip
Add border/titlebar decoration rendering to the GPU render path
The GPU (SRDWM_GPU=1/general.gpu) path had real window content but square corners and no border/titlebar. A prior pass investigated a full port of the Pixman path's decoration rendering and deliberately did not attempt it blind, given no working GPU-capable hardware on this machine to verify a single pixel of it against. Asked directly, twice, to build it anyway rather than leave it. Scoped smaller than a full port: border top/bottom strips and the titlebar bitmap now render, reusing the exact cached MemoryRenderBuffers the Pixman path already builds (renderer-agnostic pixel buffers, imported for GlesRenderer the same generic way cursor::render_elements already does for either renderer). Left out on purpose: occlusion- fragment clipping against overlapping windows, and the left/right border side strips plus the drop shadow. Full workspace build/test/clippy clean. Explicitly not visually verified - same reason as before, no GPU-capable hardware on this machine.
Diffstat (limited to 'crates/wayland')
-rw-r--r--crates/wayland/src/udev/gpu.rs35
-rw-r--r--crates/wayland/src/udev/render.rs58
2 files changed, 80 insertions, 13 deletions
diff --git a/crates/wayland/src/udev/gpu.rs b/crates/wayland/src/udev/gpu.rs
index 7b06ae3..ad6526e 100644
--- a/crates/wayland/src/udev/gpu.rs
+++ b/crates/wayland/src/udev/gpu.rs
@@ -6,19 +6,28 @@
//! 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 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.
+//! (`udev/session.rs`'s `SessionEvent` handlers), and the real cursor,
+//! real window content, and now border/titlebar decorations all render
+//! on top of the clear color (`udev/render.rs`'s own GPU branch).
+//! Content is still plain `surface_content_elements` - square corners,
+//! no rounding/masking - 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 reuse the exact same cached `MemoryRenderBuffer`s the
+//! Pixman path builds (renderer-agnostic pixel buffers, imported here
+//! for `GlesRenderer` the same generic way the cursor bitmap already is)
+//! but deliberately skip two things the Pixman path has: occlusion-
+//! fragment clipping against overlapping windows (each window's own
+//! border/titlebar draws in full, front-to-back painter's-order --
+//! correct when windows don't overlap, imprecise when they do) and
+//! left/right border side strips plus the drop shadow. Real, remaining
+//! scope, not attempted here to keep this addition reviewable against
+//! what it actually changes. 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 f850a19..0280e87 100644
--- a/crates/wayland/src/udev/render.rs
+++ b/crates/wayland/src/udev/render.rs
@@ -298,6 +298,64 @@ impl CompState {
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));
+ // Border strips (top/bottom) and the titlebar bitmap,
+ // reusing the exact same cached `MemoryRenderBuffer`s
+ // the Pixman path already builds in `redraw_
+ // decoration_buffer` (renderer-agnostic: they're
+ // plain rasterized pixel buffers, imported here for
+ // `GlesRenderer` the same generic way `cursor::
+ // render_elements` already imports the cursor
+ // bitmap for either renderer). Deliberately simpler
+ // than the Pixman path in two ways, both documented
+ // gaps rather than oversights: no occlusion-fragment
+ // clipping (each window's own border/titlebar draws
+ // in full, front-to-back painter's-order the same
+ // as content above - correct when windows don't
+ // overlap, imprecise when they do), and no left/
+ // right side strips or shadow yet. `border_curve_
+ // is_safe` is unconditionally `w.decorated` here,
+ // not the Pixman path's content-masking-aware
+ // check, since this path has no content-masking
+ // concept at all yet (`w.decorated || content_will_
+ // be_masked` degenerates to just `w.decorated` when
+ // masking can never succeed).
+ let border_curve_is_safe = w.decorated;
+ if w.border_width > 0 {
+ let strips = decoration::border_strips(geom, w.border_width);
+ if let Some(buffer) = self.border_top_decorations.get(&id) {
+ let (row0, rows, shift) = decoration::border_top_visible_rows(border_curve_is_safe, w.border_width, w.corner_radius);
+ let pos = ((strips[0].x - origin.x) as f64, (strips[0].y - origin.y + shift as i32) as f64);
+ let crop_w = self.decoration_signatures.get(&id).map(|s| s.width + 2 * s.border_width).unwrap_or(strips[0].width).min(strips[0].width);
+ if strips[0].width > 0 && strips[0].height > 0 {
+ let src = Some(Rectangle::new(Point::from((0.0, row0 as f64)), Size::from((crop_w as f64, rows as f64))));
+ match MemoryRenderBufferRenderElement::from_buffer(&mut gpu.renderer, pos, buffer, None, src, None, Kind::Unspecified) {
+ Ok(elem) => elements.push(crate::elements::OverlayElement::Memory(elem)),
+ Err(e) => log::warn!("udev: SRDWM_GPU=1 failed to import top border buffer: {e}"),
+ }
+ }
+ }
+ if let Some(buffer) = self.border_bottom_decorations.get(&id) {
+ let (row0, rows, shift) = decoration::border_bottom_visible_rows(border_curve_is_safe, w.border_width, w.corner_radius);
+ let pos = ((strips[1].x - origin.x) as f64, (strips[1].y - origin.y - shift as i32) as f64);
+ let crop_w = self.decoration_signatures.get(&id).map(|s| s.width + 2 * s.border_width).unwrap_or(strips[1].width).min(strips[1].width);
+ if strips[1].width > 0 && strips[1].height > 0 {
+ let src = Some(Rectangle::new(Point::from((0.0, row0 as f64)), Size::from((crop_w as f64, rows as f64))));
+ match MemoryRenderBufferRenderElement::from_buffer(&mut gpu.renderer, pos, buffer, None, src, None, Kind::Unspecified) {
+ Ok(elem) => elements.push(crate::elements::OverlayElement::Memory(elem)),
+ Err(e) => log::warn!("udev: SRDWM_GPU=1 failed to import bottom border buffer: {e}"),
+ }
+ }
+ }
+ }
+ if let Some(deco) = self.decorations.get(&id) {
+ let titlebar_w = self.decoration_signatures.get(&id).map(|s| s.width).unwrap_or(geom.width).min(geom.width);
+ let pos = ((geom.x - origin.x) as f64, (geom.y - origin.y) as f64);
+ let src = Some(Rectangle::new(Point::from((0.0, 0.0)), Size::from((titlebar_w as f64, srdwm_core::TITLEBAR_HEIGHT as f64))));
+ match MemoryRenderBufferRenderElement::from_buffer(&mut gpu.renderer, pos, deco, None, src, None, Kind::Unspecified) {
+ Ok(elem) => elements.push(crate::elements::OverlayElement::Memory(elem)),
+ Err(e) => log::warn!("udev: SRDWM_GPU=1 failed to import titlebar buffer: {e}"),
+ }
+ }
}
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) {