diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-05-03 13:46:33 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-05-03 13:46:33 +0400 |
| commit | 85680a57dac965973644e9e96159716c0608bb57 (patch) | |
| tree | 83f1f1c84a1140e194284a7d881aa3b42e1f2a0f /src | |
| parent | 1a8d6b1f1df80009795ed23e9ce0298fac65d766 (diff) | |
| download | niri-85680a57dac965973644e9e96159716c0608bb57.tar.gz niri-85680a57dac965973644e9e96159716c0608bb57.tar.bz2 niri-85680a57dac965973644e9e96159716c0608bb57.zip | |
Reduce unnecessary damage to borders
Diffstat (limited to 'src')
| -rw-r--r-- | src/layout/focus_ring.rs | 57 | ||||
| -rw-r--r-- | src/render_helpers/border.rs | 176 | ||||
| -rw-r--r-- | src/render_helpers/resize.rs | 8 | ||||
| -rw-r--r-- | src/render_helpers/shader_element.rs | 34 |
4 files changed, 230 insertions, 45 deletions
diff --git a/src/layout/focus_ring.rs b/src/layout/focus_ring.rs index d52bb08e..38e4a7ab 100644 --- a/src/layout/focus_ring.rs +++ b/src/layout/focus_ring.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::cmp::{max, min}; use std::iter::zip; @@ -16,6 +17,7 @@ pub struct FocusRing { buffers: [SolidColorBuffer; 8], locations: [Point<i32, Logical>; 8], sizes: [Size<i32, Logical>; 8], + borders: RefCell<Option<[BorderRenderElement; 8]>>, full_size: Size<i32, Logical>, is_active: bool, is_border: bool, @@ -36,6 +38,7 @@ impl FocusRing { buffers: Default::default(), locations: Default::default(), sizes: Default::default(), + borders: Default::default(), full_size: Default::default(), is_active: false, is_border: false, @@ -179,15 +182,40 @@ impl FocusRing { }; let shader = BorderRenderElement::shader(renderer); - let mut push = |buffer, location: Point<i32, Logical>, size: Size<i32, Logical>| { + let mut borders = self.borders.borrow_mut(); + + // Initialize the border render elements. + if let Some(shader) = shader { + if let Some(borders) = &mut *borders { + for elem in borders { + elem.update_shader(shader); + } + } else { + *borders = Some([(); 8].map(|()| BorderRenderElement::empty(shader.clone()))); + } + } + + let mut borders = if let Some(borders) = &mut *borders { + let a = Some(borders.iter_mut().map(Some)); + let b = None; + a.into_iter().flatten().chain(b.into_iter().flatten()) + } else { + let a = None; + let b = Some([None, None, None, None, None, None, None, None].into_iter()); + a.into_iter().flatten().chain(b.into_iter().flatten()) + }; + + let mut push = |buffer, + border: Option<&mut BorderRenderElement>, + location: Point<i32, Logical>, + size: Size<i32, Logical>| { let elem = if let Some(gradient) = gradient { let gradient_area = match gradient.relative_to { GradientRelativeTo::Window => full_rect, GradientRelativeTo::WorkspaceView => view_rect, }; - shader.cloned().map(|shader| { - BorderRenderElement::new( - shader, + border.map(|border| { + border.update( scale, Rectangle::from_loc_and_size(location, size), gradient_area, @@ -197,13 +225,12 @@ impl FocusRing { full_rect, border_width, self.radius, - ) - .into() + ); + border.clone().into() }) } else if self.radius != CornerRadius::default() { - shader.cloned().map(|shader| { - BorderRenderElement::new( - shader, + border.map(|border| { + border.update( scale, Rectangle::from_loc_and_size(location, size), full_rect, @@ -213,8 +240,8 @@ impl FocusRing { full_rect, border_width, self.radius, - ) - .into() + ); + border.clone().into() }) } else { None @@ -234,12 +261,16 @@ impl FocusRing { }; if self.is_border { - for (buf, (loc, size)) in zip(&self.buffers, zip(self.locations, self.sizes)) { - push(buf, location + loc, size); + for ((buf, border), (loc, size)) in zip( + zip(&self.buffers, &mut borders), + zip(self.locations, self.sizes), + ) { + push(buf, border, location + loc, size); } } else { push( &self.buffers[0], + borders.next().unwrap(), location + self.locations[0], self.sizes[0], ); diff --git a/src/render_helpers/border.rs b/src/render_helpers/border.rs index bf72a370..3f2e69dd 100644 --- a/src/render_helpers/border.rs +++ b/src/render_helpers/border.rs @@ -18,8 +18,25 @@ use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError}; /// * sub- or super-rect of an angled linear gradient like CSS linear-gradient(angle, a, b). /// * corner rounding. /// * as a background rectangle and as parts of a border line. -#[derive(Debug)] -pub struct BorderRenderElement(ShaderRenderElement); +#[derive(Debug, Clone)] +pub struct BorderRenderElement { + inner: ShaderRenderElement, + shader: ShaderProgram, + params: Parameters, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +struct Parameters { + scale: Scale<f64>, + area: Rectangle<i32, Logical>, + gradient_area: Rectangle<i32, Logical>, + color_from: [f32; 4], + color_to: [f32; 4], + angle: f32, + geometry: Rectangle<i32, Logical>, + border_width: f32, + corner_radius: CornerRadius, +} impl BorderRenderElement { #[allow(clippy::too_many_arguments)] @@ -35,6 +52,127 @@ impl BorderRenderElement { border_width: f32, corner_radius: CornerRadius, ) -> Self { + let inner = ShaderRenderElement::new( + shader.clone(), + Default::default(), + Default::default(), + None, + 1., + vec![], + HashMap::new(), + Kind::Unspecified, + ); + let mut rv = Self { + inner, + shader, + params: Parameters { + scale, + area, + gradient_area, + color_from, + color_to, + angle, + geometry, + border_width, + corner_radius, + }, + }; + rv.update_inner(); + rv + } + + pub fn empty(shader: ShaderProgram) -> Self { + let inner = ShaderRenderElement::new( + shader.clone(), + Default::default(), + Default::default(), + None, + 1., + vec![], + HashMap::new(), + Kind::Unspecified, + ); + Self { + inner, + shader, + params: Parameters { + scale: Scale::from(1.), + area: Default::default(), + gradient_area: Default::default(), + color_from: Default::default(), + color_to: Default::default(), + angle: 0., + geometry: Default::default(), + border_width: 0., + corner_radius: Default::default(), + }, + } + } + + pub fn update_shader(&mut self, shader: &ShaderProgram) { + if &self.shader == shader { + return; + } + + self.inner = ShaderRenderElement::new( + shader.clone(), + Default::default(), + Default::default(), + None, + 1., + vec![], + HashMap::new(), + Kind::Unspecified, + ); + self.update_inner(); + self.shader = shader.clone(); + } + + #[allow(clippy::too_many_arguments)] + pub fn update( + &mut self, + scale: Scale<f64>, + area: Rectangle<i32, Logical>, + gradient_area: Rectangle<i32, Logical>, + color_from: [f32; 4], + color_to: [f32; 4], + angle: f32, + geometry: Rectangle<i32, Logical>, + border_width: f32, + corner_radius: CornerRadius, + ) { + let params = Parameters { + scale, + area, + gradient_area, + color_from, + color_to, + angle, + geometry, + border_width, + corner_radius, + }; + if self.params == params { + return; + } + + self.params = params; + self.update_inner(); + } + + fn update_inner(&mut self) { + let Parameters { + scale, + area, + gradient_area, + color_from, + color_to, + angle, + geometry, + border_width, + corner_radius, + } = self.params; + let grad_offset = (area.loc - gradient_area.loc).to_f64().to_physical(scale); let grad_dir = Vec2::from_angle(angle); @@ -65,13 +203,10 @@ impl BorderRenderElement { let corner_radius = corner_radius.scaled_by(scale.x as f32); let border_width = border_width * scale.x as f32; - let elem = ShaderRenderElement::new( - shader, - HashMap::new(), + self.inner.update( area, area.size.to_f64().to_buffer(scale, Transform::Normal), None, - 1., vec![ Uniform::new("color_from", color_from), Uniform::new("color_to", color_to), @@ -83,9 +218,8 @@ impl BorderRenderElement { Uniform::new("outer_radius", <[f32; 4]>::from(corner_radius)), Uniform::new("border_width", border_width), ], - Kind::Unspecified, + HashMap::new(), ); - Self(elem) } pub fn shader(renderer: &mut impl NiriRenderer) -> Option<&ShaderProgram> { @@ -95,23 +229,23 @@ impl BorderRenderElement { impl Element for BorderRenderElement { fn id(&self) -> &Id { - self.0.id() + self.inner.id() } fn current_commit(&self) -> CommitCounter { - self.0.current_commit() + self.inner.current_commit() } fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> { - self.0.geometry(scale) + self.inner.geometry(scale) } fn transform(&self) -> Transform { - self.0.transform() + self.inner.transform() } fn src(&self) -> Rectangle<f64, Buffer> { - self.0.src() + self.inner.src() } fn damage_since( @@ -119,19 +253,19 @@ impl Element for BorderRenderElement { scale: Scale<f64>, commit: Option<CommitCounter>, ) -> DamageSet<i32, Physical> { - self.0.damage_since(scale, commit) + self.inner.damage_since(scale, commit) } fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> { - self.0.opaque_regions(scale) + self.inner.opaque_regions(scale) } fn alpha(&self) -> f32 { - self.0.alpha() + self.inner.alpha() } fn kind(&self) -> Kind { - self.0.kind() + self.inner.kind() } } @@ -143,11 +277,11 @@ impl RenderElement<GlesRenderer> for BorderRenderElement { dst: Rectangle<i32, Physical>, damage: &[Rectangle<i32, Physical>], ) -> Result<(), GlesError> { - RenderElement::<GlesRenderer>::draw(&self.0, frame, src, dst, damage) + RenderElement::<GlesRenderer>::draw(&self.inner, frame, src, dst, damage) } fn underlying_storage(&self, renderer: &mut GlesRenderer) -> Option<UnderlyingStorage> { - self.0.underlying_storage(renderer) + self.inner.underlying_storage(renderer) } } @@ -159,10 +293,10 @@ impl<'render> RenderElement<TtyRenderer<'render>> for BorderRenderElement { dst: Rectangle<i32, Physical>, damage: &[Rectangle<i32, Physical>], ) -> Result<(), TtyRendererError<'render>> { - RenderElement::<TtyRenderer<'_>>::draw(&self.0, frame, src, dst, damage) + RenderElement::<TtyRenderer<'_>>::draw(&self.inner, frame, src, dst, damage) } fn underlying_storage(&self, renderer: &mut TtyRenderer<'render>) -> Option<UnderlyingStorage> { - self.0.underlying_storage(renderer) + self.inner.underlying_storage(renderer) } } diff --git a/src/render_helpers/resize.rs b/src/render_helpers/resize.rs index 8ba897ef..d01e4eb9 100644 --- a/src/render_helpers/resize.rs +++ b/src/render_helpers/resize.rs @@ -93,10 +93,6 @@ impl ResizeRenderElement { // Create the shader. Self(ShaderRenderElement::new( shader, - HashMap::from([ - (String::from("niri_tex_prev"), texture_prev), - (String::from("niri_tex_next"), texture_next), - ]), area, size, None, @@ -113,6 +109,10 @@ impl ResizeRenderElement { Uniform::new("niri_corner_radius", <[f32; 4]>::from(corner_radius)), Uniform::new("niri_clip_to_geometry", clip_to_geometry), ], + HashMap::from([ + (String::from("niri_tex_prev"), texture_prev), + (String::from("niri_tex_next"), texture_next), + ]), Kind::Unspecified, )) } diff --git a/src/render_helpers/shader_element.rs b/src/render_helpers/shader_element.rs index c17764ee..4e313fe3 100644 --- a/src/render_helpers/shader_element.rs +++ b/src/render_helpers/shader_element.rs @@ -17,7 +17,7 @@ use super::resources::Resources; use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError}; /// Renders a shader with optional texture input, on the primary GPU. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ShaderRenderElement { shader: ShaderProgram, textures: HashMap<String, GlesTexture>, @@ -54,6 +54,12 @@ struct ShaderProgramInternal { texture_uniforms: HashMap<String, ffi::types::GLint>, } +impl PartialEq for ShaderProgram { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.0, &other.0) + } +} + unsafe fn compile_program( gl: &ffi::Gles2, src: &str, @@ -192,12 +198,12 @@ impl ShaderRenderElement { #[allow(clippy::too_many_arguments)] pub fn new( shader: ShaderProgram, - textures: HashMap<String, GlesTexture>, area: Rectangle<i32, Logical>, size: Size<f64, Buffer>, opaque_regions: Option<Vec<Rectangle<i32, Logical>>>, alpha: f32, - additional_uniforms: Vec<Uniform<'_>>, + uniforms: Vec<Uniform<'_>>, + textures: HashMap<String, GlesTexture>, kind: Kind, ) -> Self { Self { @@ -209,13 +215,27 @@ impl ShaderRenderElement { size, opaque_regions: opaque_regions.unwrap_or_default(), alpha, - additional_uniforms: additional_uniforms - .into_iter() - .map(|u| u.into_owned()) - .collect(), + additional_uniforms: uniforms.into_iter().map(|u| u.into_owned()).collect(), kind, } } + + pub fn update( + &mut self, + area: Rectangle<i32, Logical>, + size: Size<f64, Buffer>, + opaque_regions: Option<Vec<Rectangle<i32, Logical>>>, + uniforms: Vec<Uniform<'_>>, + textures: HashMap<String, GlesTexture>, + ) { + self.area = area; + self.size = size; + self.opaque_regions = opaque_regions.unwrap_or_default(); + self.additional_uniforms = uniforms.into_iter().map(|u| u.into_owned()).collect(); + self.textures = textures; + + self.commit_counter.increment(); + } } impl Element for ShaderRenderElement { |
