From 2cc10b0704d7352198374597075ef184253026be Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Mon, 24 Jun 2024 01:47:00 +0200 Subject: Real rounded corners on client content (GLES/winit backend), via a custom shader decoration.rs's round_top_corners only ever clipped the compositor's own titlebar/border bitmap - its own doc comment already said why nothing more had been done: clipping arbitrary client content needs a real per-pixel mask, "a much bigger change than this cosmetic pass". That's this change, for the one backend that can do it cheaply: the udev backend's PixmanRenderer is software-only with no shader stage at all, but GlesRenderer (winit) has a real custom-shader path (`compile_custom_texture_shader`, `TextureShaderElement`) that a first look at smithay's higher-level convenience APIs missed entirely. crates/wayland/src/rounded_corners.rs: a GLSL fragment shader masking a window's texture against a rounded-rect signed-distance field while sampling it (the same technique cosmic-comp/niri use for GPU-side rounded corners) - built by hand from the surface's own committed texture/view/ damage state (`RendererSurfaceState`'s public accessors), since no smithay convenience wrapper builds a masked element at all (`CropRenderElement` only crops to a rectangle). A decorated window rounds only its bottom two corners - the top two are already rounded, on the titlebar's own CPU bitmap, by decoration.rs, at the exact same `CORNER_RADIUS` (now `pub(crate)`, shared between the two so the curve reads as one continuous radius, not two different ones meeting at a seam) - an undecorated/CSD window rounds all four, since its content is the window's whole visible extent. Falls back to plain unrounded content on any failure (shader didn't compile, no committed buffer yet, a single-pixel-buffer surface), same "always show something over a prettier maybe-nothing" reasoning cursor.rs's built-in-arrow fallback already uses. Deliberately scoped to a window's *main* surface only, not subsurfaces - documented as a real, if narrow, follow-up rather than attempted here. `TextureShaderElement` only implements `RenderElement`, not the generic `RenderElement` every `OverlayElement` variant needs, so it can't be added to that shared enum without breaking `OverlayElement< PixmanRenderer>` (used identically by udev.rs) the moment a GLES-only variant showed up in it. `WinitElement<=GlesRenderer>` (new, winit.rs-only) wraps the existing enum as one variant instead of touching it - this is the same lesson as the fullscreen-hiding investigation earlier this session, just resolved cleanly this time: nesting a *foreign* generic type inside your own hits real bound-resolution walls; wrapping your own already-working type inside a new concrete-renderer enum doesn't, because smithay's own `render_elements!` macro documents exactly this `<=ConcreteRenderer>` form. Config: `general.rounded_corners` (default `true`), `srd.window` unaffected - this is a `general.*` compositor-behavior knob, not a per-window rule action like `opacity`. Verified live: shader compiles without error on this machine's real Mesa/ llvmpipe GL driver, and a decorated wezterm window's bottom-left and bottom-right corners both show a real, smoothly anti-aliased curve on the actual client-rendered pixels (not a compositor bitmap) in a host-session screenshot - qualitatively sharper than `round_top_corners`' deliberate hard cutoff, since a GPU shader can afford a ~2px smoothstep a CPU bitmap pass isn't worth adding for. cargo build --workspace (all 9 crates), cargo clippy --workspace (0 new warnings), cargo test --workspace (197 tests, 0 failed). --- crates/wayland/src/decoration.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'crates/wayland/src/decoration.rs') diff --git a/crates/wayland/src/decoration.rs b/crates/wayland/src/decoration.rs index 8d300aa..4aa0b2d 100644 --- a/crates/wayland/src/decoration.rs +++ b/crates/wayland/src/decoration.rs @@ -354,7 +354,14 @@ pub fn render_titlebar(width: u32, height: u32, title: &str, background: (u8, u8 /// cosmetic nicety, not a feature surface worth a `srd.theme` knob, and a /// value this small barely reads as "rounded" if it gets any larger at the /// titlebar heights this compositor actually uses. -const CORNER_RADIUS: u32 = 6; +/// +/// `pub(crate)`, not private: `rounded_corners.rs` reuses the exact same +/// value for a decorated window's own content (its bottom two corners, +/// where the GLES backend can round the client's actual pixels, unlike +/// the CPU bitmap clip this file does for the titlebar/border), so a +/// bordered window's curve reads as one continuous radius from titlebar +/// to content rather than two different ones meeting at a seam. +pub(crate) const CORNER_RADIUS: u32 = 6; /// Clips the top-left and top-right corners of a titlebar buffer to a /// quarter-circle by making the pixels outside it fully transparent, so -- cgit v1.2.3