aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-05-03 13:46:33 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-05-03 13:46:33 +0400
commit85680a57dac965973644e9e96159716c0608bb57 (patch)
tree83f1f1c84a1140e194284a7d881aa3b42e1f2a0f /src
parent1a8d6b1f1df80009795ed23e9ce0298fac65d766 (diff)
downloadniri-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.rs57
-rw-r--r--src/render_helpers/border.rs176
-rw-r--r--src/render_helpers/resize.rs8
-rw-r--r--src/render_helpers/shader_element.rs34
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 {