aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-05-12 09:52:21 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-05-12 09:52:36 +0400
commit9004c8395438038d69f7b479a8a9035663cb4be0 (patch)
tree349acfc1e9ac7df31bb52db66f7f9e8a59d19e79 /src
parent29c7552852874a08f9e70ed52ddfb6be8f55bc69 (diff)
downloadniri-9004c8395438038d69f7b479a8a9035663cb4be0.tar.gz
niri-9004c8395438038d69f7b479a8a9035663cb4be0.tar.bz2
niri-9004c8395438038d69f7b479a8a9035663cb4be0.zip
Implement custom shader for window-close anim
Diffstat (limited to 'src')
-rw-r--r--src/backend/tty.rs3
-rw-r--r--src/backend/winit.rs3
-rw-r--r--src/layout/closing_window.rs60
-rw-r--r--src/layout/workspace.rs4
-rw-r--r--src/niri.rs10
-rw-r--r--src/render_helpers/shaders/close_epilogue.frag16
-rw-r--r--src/render_helpers/shaders/close_prelude.frag21
-rw-r--r--src/render_helpers/shaders/mod.rs54
8 files changed, 163 insertions, 8 deletions
diff --git a/src/backend/tty.rs b/src/backend/tty.rs
index ddf6c54b..d35106eb 100644
--- a/src/backend/tty.rs
+++ b/src/backend/tty.rs
@@ -500,6 +500,9 @@ impl Tty {
if let Some(src) = config.animations.window_resize.custom_shader.as_deref() {
shaders::set_custom_resize_program(gles_renderer, Some(src));
}
+ if let Some(src) = config.animations.window_close.custom_shader.as_deref() {
+ shaders::set_custom_close_program(gles_renderer, Some(src));
+ }
drop(config);
niri.layout.update_shaders();
diff --git a/src/backend/winit.rs b/src/backend/winit.rs
index ab71ea2e..047ebb06 100644
--- a/src/backend/winit.rs
+++ b/src/backend/winit.rs
@@ -140,6 +140,9 @@ impl Winit {
if let Some(src) = config.animations.window_resize.custom_shader.as_deref() {
shaders::set_custom_resize_program(renderer, Some(src));
}
+ if let Some(src) = config.animations.window_close.custom_shader.as_deref() {
+ shaders::set_custom_close_program(renderer, Some(src));
+ }
drop(config);
niri.layout.update_shaders();
diff --git a/src/layout/closing_window.rs b/src/layout/closing_window.rs
index c1f4e599..bdeb73a5 100644
--- a/src/layout/closing_window.rs
+++ b/src/layout/closing_window.rs
@@ -1,6 +1,8 @@
+use std::collections::HashMap;
use std::time::Duration;
use anyhow::Context as _;
+use glam::{Mat3, Vec2};
use niri_config::BlockOutFrom;
use smithay::backend::allocator::Fourcc;
use smithay::backend::renderer::element::texture::TextureRenderElement;
@@ -8,13 +10,15 @@ use smithay::backend::renderer::element::utils::{
Relocate, RelocateRenderElement, RescaleRenderElement,
};
use smithay::backend::renderer::element::{Id, Kind, RenderElement};
-use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
-use smithay::backend::renderer::Renderer as _;
+use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture, Uniform};
+use smithay::backend::renderer::{Renderer as _, Texture};
use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
use crate::animation::Animation;
use crate::niri_render_elements;
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
+use crate::render_helpers::shader_element::ShaderRenderElement;
+use crate::render_helpers::shaders::{mat3_uniform, ProgramType, Shaders};
use crate::render_helpers::snapshot::RenderSnapshot;
use crate::render_helpers::{render_to_encompassing_texture, RenderTarget};
@@ -49,11 +53,15 @@ pub struct ClosingWindow {
/// The closing animation.
anim: Animation,
+
+ /// Random seed for the shader.
+ random_seed: f32,
}
niri_render_elements! {
ClosingWindowRenderElement => {
Texture = RelocateRenderElement<RescaleRenderElement<PrimaryGpuTextureRenderElement>>,
+ Shader = ShaderRenderElement,
}
}
@@ -100,6 +108,7 @@ impl ClosingWindow {
texture_offset,
blocked_out_texture_offset,
anim,
+ random_seed: fastrand::f32(),
})
}
@@ -108,16 +117,18 @@ impl ClosingWindow {
}
pub fn are_animations_ongoing(&self) -> bool {
- !self.anim.is_clamped_done()
+ !self.anim.is_done()
}
pub fn render(
&self,
+ renderer: &mut GlesRenderer,
view_rect: Rectangle<i32, Logical>,
scale: Scale<f64>,
target: RenderTarget,
) -> ClosingWindowRenderElement {
- let val = self.anim.clamped_value();
+ let progress = self.anim.value();
+ let clamped_progress = self.anim.clamped_value().clamp(0., 1.);
let (texture, offset) = if target.should_block_out(self.block_out_from) {
(&self.blocked_out_texture, self.blocked_out_texture_offset)
@@ -125,6 +136,43 @@ impl ClosingWindow {
(&self.texture, self.texture_offset)
};
+ if Shaders::get(renderer).program(ProgramType::Close).is_some() {
+ let area_loc = Vec2::new(view_rect.loc.x as f32, view_rect.loc.y as f32);
+ let area_size = Vec2::new(view_rect.size.w as f32, view_rect.size.h as f32);
+
+ let geo_loc = Vec2::new(self.pos.x as f32, self.pos.y as f32);
+ let geo_size = Vec2::new(self.geo_size.w as f32, self.geo_size.h as f32);
+
+ let input_to_geo = Mat3::from_scale(area_size / geo_size)
+ * Mat3::from_translation((area_loc - geo_loc) / area_size);
+
+ let tex_scale = Vec2::new(self.texture_scale.x as f32, self.texture_scale.y as f32);
+ let tex_loc = Vec2::new(offset.x as f32, offset.y as f32);
+ let tex_size = Vec2::new(texture.width() as f32, texture.height() as f32) / tex_scale;
+
+ let geo_to_tex =
+ Mat3::from_translation(-tex_loc / tex_size) * Mat3::from_scale(geo_size / tex_size);
+
+ return ShaderRenderElement::new(
+ ProgramType::Close,
+ view_rect.size,
+ None,
+ 1.,
+ vec![
+ mat3_uniform("niri_input_to_geo", input_to_geo),
+ Uniform::new("niri_geo_size", geo_size.to_array()),
+ mat3_uniform("niri_geo_to_tex", geo_to_tex),
+ Uniform::new("niri_progress", progress as f32),
+ Uniform::new("niri_clamped_progress", clamped_progress as f32),
+ Uniform::new("niri_random_seed", self.random_seed),
+ ],
+ HashMap::from([(String::from("niri_tex"), texture.clone())]),
+ Kind::Unspecified,
+ )
+ .with_location(Point::from((0, 0)))
+ .into();
+ }
+
let elem = TextureRenderElement::from_static_texture(
Id::new(),
self.texture_renderer_id,
@@ -132,7 +180,7 @@ impl ClosingWindow {
texture.clone(),
self.texture_scale.x as i32,
Transform::Normal,
- Some(val.clamp(0., 1.) as f32),
+ Some(1. - clamped_progress as f32),
None,
None,
None,
@@ -145,7 +193,7 @@ impl ClosingWindow {
let elem = RescaleRenderElement::from_element(
elem,
(center - offset).to_physical_precise_round(scale),
- (val / 5. + 0.8).max(0.),
+ ((1. - clamped_progress) / 5. + 0.8).max(0.),
);
let mut location = self.pos.to_f64() + offset;
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index a2515a76..08f170f8 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -1344,7 +1344,7 @@ impl<W: LayoutElement> Workspace<W> {
tile_pos.x -= offset;
}
- let anim = Animation::new(1., 0., 0., self.options.animations.window_close.0);
+ let anim = Animation::new(0., 1., 0., self.options.animations.window_close.anim);
let res = ClosingWindow::new(
renderer,
@@ -2095,7 +2095,7 @@ impl<W: LayoutElement> Workspace<W> {
// Draw the closing windows on top.
let view_rect = Rectangle::from_loc_and_size((self.view_pos(), 0), self.view_size);
for closing in &self.closing_windows {
- let elem = closing.render(view_rect, output_scale, target);
+ let elem = closing.render(renderer.as_gles_renderer(), view_rect, output_scale, target);
rv.push(elem.into());
}
diff --git a/src/niri.rs b/src/niri.rs
index 6605cc79..7fc94365 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -941,6 +941,16 @@ impl State {
shaders_changed = true;
}
+ if config.animations.window_close.custom_shader
+ != old_config.animations.window_close.custom_shader
+ {
+ let src = config.animations.window_close.custom_shader.as_deref();
+ self.backend.with_primary_renderer(|renderer| {
+ shaders::set_custom_close_program(renderer, src);
+ });
+ shaders_changed = true;
+ }
+
if config.debug != old_config.debug {
debug_config_changed = true;
}
diff --git a/src/render_helpers/shaders/close_epilogue.frag b/src/render_helpers/shaders/close_epilogue.frag
new file mode 100644
index 00000000..ed05c110
--- /dev/null
+++ b/src/render_helpers/shaders/close_epilogue.frag
@@ -0,0 +1,16 @@
+
+void main() {
+ vec3 coords_geo = niri_input_to_geo * vec3(niri_v_coords, 1.0);
+ vec3 size_geo = vec3(niri_geo_size, 1.0);
+
+ vec4 color = close_color(coords_geo, size_geo);
+
+ color = color * niri_alpha;
+
+#if defined(DEBUG_FLAGS)
+ if (niri_tint == 1.0)
+ color = vec4(0.0, 0.2, 0.0, 0.2) + color * 0.8;
+#endif
+
+ gl_FragColor = color;
+}
diff --git a/src/render_helpers/shaders/close_prelude.frag b/src/render_helpers/shaders/close_prelude.frag
new file mode 100644
index 00000000..db42190b
--- /dev/null
+++ b/src/render_helpers/shaders/close_prelude.frag
@@ -0,0 +1,21 @@
+precision mediump float;
+
+#if defined(DEBUG_FLAGS)
+uniform float niri_tint;
+#endif
+
+varying vec2 niri_v_coords;
+uniform vec2 niri_size;
+
+uniform mat3 niri_input_to_geo;
+uniform vec2 niri_geo_size;
+
+uniform sampler2D niri_tex;
+uniform mat3 niri_geo_to_tex;
+
+uniform float niri_progress;
+uniform float niri_clamped_progress;
+uniform float niri_random_seed;
+
+uniform float niri_alpha;
+
diff --git a/src/render_helpers/shaders/mod.rs b/src/render_helpers/shaders/mod.rs
index 034d8db1..21287a55 100644
--- a/src/render_helpers/shaders/mod.rs
+++ b/src/render_helpers/shaders/mod.rs
@@ -14,12 +14,14 @@ pub struct Shaders {
pub clipped_surface: Option<GlesTexProgram>,
pub resize: Option<ShaderProgram>,
pub custom_resize: RefCell<Option<ShaderProgram>>,
+ pub custom_close: RefCell<Option<ShaderProgram>>,
}
#[derive(Debug, Clone, Copy)]
pub enum ProgramType {
Border,
Resize,
+ Close,
}
impl Shaders {
@@ -72,6 +74,7 @@ impl Shaders {
clipped_surface,
resize,
custom_resize: RefCell::new(None),
+ custom_close: RefCell::new(None),
}
}
@@ -95,6 +98,13 @@ impl Shaders {
self.custom_resize.replace(program)
}
+ pub fn replace_custom_close_program(
+ &self,
+ program: Option<ShaderProgram>,
+ ) -> Option<ShaderProgram> {
+ self.custom_close.replace(program)
+ }
+
pub fn program(&self, program: ProgramType) -> Option<ShaderProgram> {
match program {
ProgramType::Border => self.border.clone(),
@@ -103,6 +113,7 @@ impl Shaders {
.borrow()
.clone()
.or_else(|| self.resize.clone()),
+ ProgramType::Close => self.custom_close.borrow().clone(),
}
}
}
@@ -162,6 +173,49 @@ pub fn set_custom_resize_program(renderer: &mut GlesRenderer, src: Option<&str>)
}
}
+fn compile_close_program(
+ renderer: &mut GlesRenderer,
+ src: &str,
+) -> Result<ShaderProgram, GlesError> {
+ let mut program = include_str!("close_prelude.frag").to_string();
+ program.push_str(src);
+ program.push_str(include_str!("close_epilogue.frag"));
+
+ ShaderProgram::compile(
+ renderer,
+ &program,
+ &[
+ UniformName::new("niri_input_to_geo", UniformType::Matrix3x3),
+ UniformName::new("niri_geo_size", UniformType::_2f),
+ UniformName::new("niri_geo_to_tex", UniformType::Matrix3x3),
+ UniformName::new("niri_progress", UniformType::_1f),
+ UniformName::new("niri_clamped_progress", UniformType::_1f),
+ UniformName::new("niri_random_seed", UniformType::_1f),
+ ],
+ &["niri_tex"],
+ )
+}
+
+pub fn set_custom_close_program(renderer: &mut GlesRenderer, src: Option<&str>) {
+ let program = if let Some(src) = src {
+ match compile_close_program(renderer, src) {
+ Ok(program) => Some(program),
+ Err(err) => {
+ warn!("error compiling custom close shader: {err:?}");
+ return;
+ }
+ }
+ } else {
+ None
+ };
+
+ if let Some(prev) = Shaders::get(renderer).replace_custom_close_program(program) {
+ if let Err(err) = prev.destroy(renderer) {
+ warn!("error destroying previous custom close shader: {err:?}");
+ }
+ }
+}
+
pub fn mat3_uniform(name: &str, mat: Mat3) -> Uniform {
Uniform::new(
name,