From 2f42f8ac75f459cba16482bebcbb58df265971cb Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Thu, 2 May 2024 08:14:21 +0400 Subject: Damage window on corner radius changes --- src/layout/tile.rs | 23 ++++++++++- src/render_helpers/clipped_surface.rs | 29 +++++++++++++- src/render_helpers/damage.rs | 75 +++++++++++++++++++++++++++++++++++ src/render_helpers/mod.rs | 1 + 4 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 src/render_helpers/damage.rs diff --git a/src/layout/tile.rs b/src/layout/tile.rs index f0e770f4..a5ba6c6c 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -19,7 +19,8 @@ use super::{ use crate::animation::Animation; use crate::niri_render_elements; use crate::render_helpers::border::BorderRenderElement; -use crate::render_helpers::clipped_surface::ClippedSurfaceRenderElement; +use crate::render_helpers::clipped_surface::{ClippedSurfaceRenderElement, RoundedCornerDamage}; +use crate::render_helpers::damage::ExtraDamage; use crate::render_helpers::offscreen::OffscreenRenderElement; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::resize::ResizeRenderElement; @@ -68,6 +69,9 @@ pub struct Tile { /// Snapshot of the last render for use in the close animation. unmap_snapshot: RefCell>, + /// Extra damage for clipped surface corner radius changes. + rounded_corner_damage: RoundedCornerDamage, + /// Configurable properties of the layout. pub options: Rc, } @@ -81,6 +85,7 @@ niri_render_elements! { Resize = ResizeRenderElement, Border = BorderRenderElement, ClippedSurface = ClippedSurfaceRenderElement, + ExtraDamage = ExtraDamage, } } @@ -118,6 +123,7 @@ impl Tile { move_x_animation: None, move_y_animation: None, unmap_snapshot: RefCell::new(None), + rounded_corner_damage: Default::default(), options, } } @@ -180,6 +186,14 @@ impl Tile { .focus_ring .resolve_against(self.options.focus_ring.into()); self.focus_ring.update_config(focus_ring_config.into()); + + let window_size = self.window_size(); + let radius = rules + .geometry_corner_radius + .unwrap_or_default() + .fit_to(window_size.w as f32, window_size.h as f32); + self.rounded_corner_damage.set_corner_radius(radius); + self.rounded_corner_damage.set_size(window_size); } pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) { @@ -650,6 +664,7 @@ impl Tile { // If we're not resizing, render the window itself. let mut window_surface = None; let mut window_popups = None; + let mut rounded_corner_damage = None; if resize_shader.is_none() && resize_fallback.is_none() { let window = self .window @@ -667,6 +682,11 @@ impl Tile { let clip_shader = ClippedSurfaceRenderElement::shader(renderer).cloned(); let border_shader = BorderRenderElement::shader(renderer).cloned(); + if clip_to_geometry && clip_shader.is_some() { + let damage = self.rounded_corner_damage.element(); + rounded_corner_damage = Some(damage.with_location(window_render_loc).into()); + } + window_surface = Some(window.normal.into_iter().map(move |elem| match elem { LayoutElementRenderElement::Wayland(elem) => { // If we should clip to geometry, render a clipped window. @@ -727,6 +747,7 @@ impl Tile { .chain(resize_shader) .chain(resize_fallback) .chain(window_popups.into_iter().flatten()) + .chain(rounded_corner_damage) .chain(window_surface.into_iter().flatten()); let elem = self.is_fullscreen.then(|| { diff --git a/src/render_helpers/clipped_surface.rs b/src/render_helpers/clipped_surface.rs index 69c2a012..43ba8594 100644 --- a/src/render_helpers/clipped_surface.rs +++ b/src/render_helpers/clipped_surface.rs @@ -6,8 +6,9 @@ use smithay::backend::renderer::gles::{ GlesError, GlesFrame, GlesRenderer, GlesTexProgram, Uniform, }; use smithay::backend::renderer::utils::{CommitCounter, DamageSet}; -use smithay::utils::{Buffer, Logical, Physical, Rectangle, Scale, Transform}; +use smithay::utils::{Buffer, Logical, Physical, Rectangle, Scale, Size, Transform}; +use super::damage::ExtraDamage; use super::renderer::{AsGlesFrame as _, NiriRenderer}; use super::shaders::{mat3_uniform, Shaders}; use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError}; @@ -21,6 +22,12 @@ pub struct ClippedSurfaceRenderElement { input_to_geo: Mat3, } +#[derive(Debug, Default, Clone)] +pub struct RoundedCornerDamage { + damage: ExtraDamage, + corner_radius: CornerRadius, +} + impl ClippedSurfaceRenderElement { pub fn new( elem: WaylandSurfaceRenderElement, @@ -267,3 +274,23 @@ impl<'render> RenderElement> None } } + +impl RoundedCornerDamage { + pub fn set_size(&mut self, size: Size) { + self.damage.set_size(size); + } + + pub fn set_corner_radius(&mut self, corner_radius: CornerRadius) { + if self.corner_radius == corner_radius { + return; + } + + // FIXME: make the damage granular. + self.corner_radius = corner_radius; + self.damage.damage_all(); + } + + pub fn element(&self) -> ExtraDamage { + self.damage.clone() + } +} diff --git a/src/render_helpers/damage.rs b/src/render_helpers/damage.rs new file mode 100644 index 00000000..ef7b125f --- /dev/null +++ b/src/render_helpers/damage.rs @@ -0,0 +1,75 @@ +use smithay::backend::renderer::element::{Element, Id, RenderElement}; +use smithay::backend::renderer::utils::CommitCounter; +use smithay::backend::renderer::Renderer; +use smithay::utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Size}; + +#[derive(Debug, Clone)] +pub struct ExtraDamage { + id: Id, + commit: CommitCounter, + geometry: Rectangle, +} + +impl ExtraDamage { + pub fn new() -> Self { + Self { + id: Id::new(), + commit: Default::default(), + geometry: Default::default(), + } + } + + pub fn set_size(&mut self, size: Size) { + if self.geometry.size == size { + return; + } + + self.geometry.size = size; + self.commit.increment(); + } + + pub fn damage_all(&mut self) { + self.commit.increment(); + } + + pub fn with_location(mut self, location: Point) -> Self { + self.geometry.loc = location; + self + } +} + +impl Default for ExtraDamage { + fn default() -> Self { + Self::new() + } +} + +impl Element for ExtraDamage { + fn id(&self) -> &Id { + &self.id + } + + fn current_commit(&self) -> CommitCounter { + self.commit + } + + fn src(&self) -> Rectangle { + Rectangle::from_loc_and_size((0., 0.), (1., 1.)) + } + + fn geometry(&self, scale: Scale) -> Rectangle { + self.geometry.to_physical_precise_round(scale) + } +} + +impl RenderElement for ExtraDamage { + fn draw( + &self, + _frame: &mut ::Frame<'_>, + _src: Rectangle, + _dst: Rectangle, + _damage: &[Rectangle], + ) -> Result<(), R::Error> { + Ok(()) + } +} diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs index ebc4b49e..b1f8fd03 100644 --- a/src/render_helpers/mod.rs +++ b/src/render_helpers/mod.rs @@ -18,6 +18,7 @@ use self::primary_gpu_texture::PrimaryGpuTextureRenderElement; pub mod border; pub mod clipped_surface; +pub mod damage; pub mod offscreen; pub mod primary_gpu_texture; pub mod render_elements; -- cgit