aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-04-21 20:10:35 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-04-21 20:16:54 +0400
commit49f5402669012be33f8cd111311c3e39fd4751c0 (patch)
treea90eab10775b63cddb0772923d43875ee13ef8b6 /src
parent2ecbb3f6f8ceacdccc66a597e372c70029325dbf (diff)
downloadniri-49f5402669012be33f8cd111311c3e39fd4751c0.tar.gz
niri-49f5402669012be33f8cd111311c3e39fd4751c0.tar.bz2
niri-49f5402669012be33f8cd111311c3e39fd4751c0.zip
Implement window-resize custom-shader
Diffstat (limited to 'src')
-rw-r--r--src/backend/tty.rs11
-rw-r--r--src/backend/winit.rs6
-rw-r--r--src/layout/mod.rs2
-rw-r--r--src/layout/tile.rs31
-rw-r--r--src/layout/workspace.rs8
-rw-r--r--src/main.rs4
-rw-r--r--src/niri.rs13
-rw-r--r--src/render_helpers/crossfade.rs161
-rw-r--r--src/render_helpers/mod.rs2
-rw-r--r--src/render_helpers/primary_gpu_pixel_shader_with_textures.rs6
-rw-r--r--src/render_helpers/resize.rs199
-rw-r--r--src/render_helpers/shaders/crossfade.frag31
-rw-r--r--src/render_helpers/shaders/mod.rs75
-rw-r--r--src/render_helpers/shaders/resize.frag41
14 files changed, 362 insertions, 228 deletions
diff --git a/src/backend/tty.rs b/src/backend/tty.rs
index fd6cf0d6..6a5b3445 100644
--- a/src/backend/tty.rs
+++ b/src/backend/tty.rs
@@ -491,8 +491,15 @@ impl Tty {
warn!("error binding wl-display in EGL: {err:?}");
}
- resources::init(renderer.as_gles_renderer());
- shaders::init(renderer.as_gles_renderer());
+ let gles_renderer = renderer.as_gles_renderer();
+ resources::init(gles_renderer);
+ shaders::init(gles_renderer);
+
+ let config = self.config.borrow();
+ if let Some(src) = config.animations.window_resize.custom_shader.as_deref() {
+ shaders::set_custom_resize_program(gles_renderer, Some(src));
+ }
+ drop(config);
// Create the dmabuf global.
let primary_formats = renderer.dmabuf_formats().collect::<HashSet<_>>();
diff --git a/src/backend/winit.rs b/src/backend/winit.rs
index 177dab85..1d1dbc8a 100644
--- a/src/backend/winit.rs
+++ b/src/backend/winit.rs
@@ -135,6 +135,12 @@ impl Winit {
resources::init(renderer);
shaders::init(renderer);
+ let config = self.config.borrow();
+ if let Some(src) = config.animations.window_resize.custom_shader.as_deref() {
+ shaders::set_custom_resize_program(renderer, Some(src));
+ }
+ drop(config);
+
niri.add_output(self.output.clone(), None, false);
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 68b592db..4c570ef2 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -238,7 +238,7 @@ impl Options {
center_focused_column: layout.center_focused_column,
preset_widths,
default_width,
- animations: config.animations,
+ animations: config.animations.clone(),
}
}
}
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index 1d639828..ed6773da 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -16,10 +16,10 @@ use super::{
};
use crate::animation::Animation;
use crate::niri_render_elements;
-use crate::render_helpers::crossfade::CrossfadeRenderElement;
use crate::render_helpers::offscreen::OffscreenRenderElement;
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
use crate::render_helpers::renderer::NiriRenderer;
+use crate::render_helpers::resize::ResizeRenderElement;
use crate::render_helpers::shaders::Shaders;
use crate::render_helpers::snapshot::RenderSnapshot;
use crate::render_helpers::{render_to_encompassing_texture, RenderTarget, ToRenderElement};
@@ -73,7 +73,7 @@ niri_render_elements! {
FocusRing = FocusRingRenderElement,
SolidColor = SolidColorRenderElement,
Offscreen = RescaleRenderElement<OffscreenRenderElement>,
- Crossfade = CrossfadeRenderElement,
+ Resize = ResizeRenderElement,
}
}
@@ -154,7 +154,7 @@ impl<W: LayoutElement> Tile<W> {
let change = self.window.size().to_point() - size_from.to_point();
let change = max(change.x.abs(), change.y.abs());
if change > RESIZE_ANIMATION_THRESHOLD {
- let anim = Animation::new(0., 1., 0., self.options.animations.window_resize.0);
+ let anim = Animation::new(0., 1., 0., self.options.animations.window_resize.anim);
self.resize_animation = Some(ResizeAnimation {
anim,
size_from,
@@ -527,12 +527,12 @@ impl<W: LayoutElement> Tile<W> {
let gles_renderer = renderer.as_gles_renderer();
- // If we're resizing, try to render a crossfade, or a fallback.
- let mut crossfade = None;
- let mut crossfade_fallback = None;
+ // If we're resizing, try to render a shader, or a fallback.
+ let mut resize_shader = None;
+ let mut resize_fallback = None;
if let Some(resize) = &self.resize_animation {
- if Shaders::get(gles_renderer).crossfade.is_some() {
+ if Shaders::get(gles_renderer).resize().is_some() {
if let Some(texture_from) = resize.snapshot.texture(gles_renderer, scale, target) {
let window_elements =
self.window
@@ -548,7 +548,7 @@ impl<W: LayoutElement> Tile<W> {
.ok();
if let Some((texture_current, _sync_point, texture_current_geo)) = current {
- let elem = CrossfadeRenderElement::new(
+ let elem = ResizeRenderElement::new(
gles_renderer,
area,
scale,
@@ -556,20 +556,21 @@ impl<W: LayoutElement> Tile<W> {
resize.snapshot.size,
(texture_current, texture_current_geo),
window_size,
+ resize.anim.value() as f32,
resize.anim.clamped_value().clamp(0., 1.) as f32,
alpha,
)
- .expect("we checked the crossfade shader above");
+ .expect("we checked the resize shader above");
self.window
.set_offscreen_element_id(Some(elem.id().clone()));
- crossfade = Some(elem.into());
+ resize_shader = Some(elem.into());
}
}
}
- if crossfade.is_none() {
+ if resize_shader.is_none() {
let fallback_buffer = SolidColorBuffer::new(area.size, [1., 0., 0., 1.]);
- crossfade_fallback = Some(
+ resize_fallback = Some(
SolidColorRenderElement::from_buffer(
&fallback_buffer,
area.loc.to_physical_precise_round(scale),
@@ -585,7 +586,7 @@ impl<W: LayoutElement> Tile<W> {
// If we're not resizing, render the window itself.
let mut window = None;
- if crossfade.is_none() && crossfade_fallback.is_none() {
+ if resize_shader.is_none() && resize_fallback.is_none() {
window = Some(
self.window
.render(renderer, window_render_loc, scale, alpha, target)
@@ -594,9 +595,9 @@ impl<W: LayoutElement> Tile<W> {
);
}
- let rv = crossfade
+ let rv = resize_shader
.into_iter()
- .chain(crossfade_fallback)
+ .chain(resize_fallback)
.chain(window.into_iter().flatten());
let elem = self.effective_border_width().map(|width| {
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 116f3759..b6b38285 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -1118,14 +1118,14 @@ impl<W: LayoutElement> Workspace<W> {
for col in &mut self.columns[col_idx + 1..] {
col.animate_move_from_with_config(
offset,
- self.options.animations.window_resize.0,
+ self.options.animations.window_resize.anim,
);
}
} else {
for col in &mut self.columns[..=col_idx] {
col.animate_move_from_with_config(
-offset,
- self.options.animations.window_resize.0,
+ self.options.animations.window_resize.anim,
);
}
}
@@ -1148,7 +1148,7 @@ impl<W: LayoutElement> Workspace<W> {
// Synchronize the horizontal view movement with the resize so that it looks nice. This
// is especially important for always-centered view.
let config = if started_resize_anim {
- self.options.animations.window_resize.0
+ self.options.animations.window_resize.anim
} else {
self.options.animations.horizontal_view_movement.0
};
@@ -2356,7 +2356,7 @@ impl<W: LayoutElement> Column<W> {
for tile in &mut self.tiles[tile_idx + 1..] {
tile.animate_move_y_from_with_config(
offset,
- self.options.animations.window_resize.0,
+ self.options.animations.window_resize.anim,
);
}
}
diff --git a/src/main.rs b/src/main.rs
index 58e2c766..f117769d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -29,6 +29,8 @@ use smithay::reexports::calloop::EventLoop;
use smithay::reexports::wayland_server::Display;
use tracing_subscriber::EnvFilter;
+const DEFAULT_LOG_FILTER: &str = "niri=debug,smithay::backend::renderer::gles=error";
+
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Set backtrace defaults if not set.
if env::var_os("RUST_BACKTRACE").is_none() {
@@ -50,7 +52,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
);
}
- let directives = env::var("RUST_LOG").unwrap_or_else(|_| "niri=debug".to_owned());
+ let directives = env::var("RUST_LOG").unwrap_or_else(|_| DEFAULT_LOG_FILTER.to_owned());
let env_filter = EnvFilter::builder().parse_lossy(directives);
tracing_subscriber::fmt()
.compact()
diff --git a/src/niri.rs b/src/niri.rs
index 145d143e..861e53f1 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -107,7 +107,9 @@ use crate::protocols::gamma_control::GammaControlManagerState;
use crate::protocols::screencopy::{Screencopy, ScreencopyManagerState};
use crate::pw_utils::{Cast, PipeWire};
use crate::render_helpers::renderer::NiriRenderer;
-use crate::render_helpers::{render_to_shm, render_to_texture, render_to_vec, RenderTarget};
+use crate::render_helpers::{
+ render_to_shm, render_to_texture, render_to_vec, shaders, RenderTarget,
+};
use crate::scroll_tracker::ScrollTracker;
use crate::ui::config_error_notification::ConfigErrorNotification;
use crate::ui::exit_confirm_dialog::ExitConfirmDialog;
@@ -895,6 +897,15 @@ impl State {
window_rules_changed = true;
}
+ if config.animations.window_resize.custom_shader
+ != old_config.animations.window_resize.custom_shader
+ {
+ let src = config.animations.window_resize.custom_shader.as_deref();
+ self.backend.with_primary_renderer(|renderer| {
+ shaders::set_custom_resize_program(renderer, src);
+ });
+ }
+
*old_config = config;
// Release the borrow.
diff --git a/src/render_helpers/crossfade.rs b/src/render_helpers/crossfade.rs
deleted file mode 100644
index 78e56ba4..00000000
--- a/src/render_helpers/crossfade.rs
+++ /dev/null
@@ -1,161 +0,0 @@
-use std::collections::HashMap;
-
-use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
-use smithay::backend::renderer::gles::{GlesError, GlesFrame, GlesRenderer, GlesTexture, Uniform};
-use smithay::backend::renderer::utils::{CommitCounter, DamageSet};
-use smithay::utils::{Buffer, Logical, Physical, Rectangle, Scale, Size, Transform};
-
-use super::primary_gpu_pixel_shader_with_textures::PrimaryGpuPixelShaderWithTexturesRenderElement;
-use super::renderer::AsGlesFrame;
-use super::shaders::Shaders;
-use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
-
-#[derive(Debug)]
-pub struct CrossfadeRenderElement(PrimaryGpuPixelShaderWithTexturesRenderElement);
-
-impl CrossfadeRenderElement {
- #[allow(clippy::too_many_arguments)]
- pub fn new(
- renderer: &mut GlesRenderer,
- area: Rectangle<i32, Logical>,
- scale: Scale<f64>,
- texture_from: (GlesTexture, Rectangle<i32, Physical>),
- size_from: Size<i32, Logical>,
- texture_to: (GlesTexture, Rectangle<i32, Physical>),
- size_to: Size<i32, Logical>,
- amount: f32,
- result_alpha: f32,
- ) -> Option<Self> {
- let (texture_from, texture_from_geo) = texture_from;
- let (texture_to, texture_to_geo) = texture_to;
-
- let scale_from = area.size.to_f64() / size_from.to_f64();
- let scale_to = area.size.to_f64() / size_to.to_f64();
-
- let tex_from_geo = texture_from_geo.to_f64().upscale(scale_from);
- let tex_to_geo = texture_to_geo.to_f64().upscale(scale_to);
- let combined_geo = tex_from_geo.merge(tex_to_geo);
-
- let size = combined_geo
- .size
- .to_logical(1.)
- .to_buffer(1., Transform::Normal);
-
- let area = Rectangle::from_loc_and_size(
- area.loc + combined_geo.loc.to_logical(scale).to_i32_round(),
- combined_geo.size.to_logical(scale).to_i32_round(),
- );
-
- let tex_from_loc = (tex_from_geo.loc - combined_geo.loc)
- .downscale((combined_geo.size.w, combined_geo.size.h));
- let tex_to_loc = (tex_to_geo.loc - combined_geo.loc)
- .downscale((combined_geo.size.w, combined_geo.size.h));
- let tex_from_size = tex_from_geo.size / combined_geo.size;
- let tex_to_size = tex_to_geo.size / combined_geo.size;
-
- Shaders::get(renderer).crossfade.clone().map(|shader| {
- Self(PrimaryGpuPixelShaderWithTexturesRenderElement::new(
- shader,
- HashMap::from([
- (String::from("tex_from"), texture_from),
- (String::from("tex_to"), texture_to),
- ]),
- area,
- size,
- None,
- result_alpha,
- vec![
- Uniform::new(
- "tex_from_loc",
- (tex_from_loc.x as f32, tex_from_loc.y as f32),
- ),
- Uniform::new(
- "tex_from_size",
- (tex_from_size.x as f32, tex_from_size.y as f32),
- ),
- Uniform::new("tex_to_loc", (tex_to_loc.x as f32, tex_to_loc.y as f32)),
- Uniform::new("tex_to_size", (tex_to_size.x as f32, tex_to_size.y as f32)),
- Uniform::new("amount", amount),
- ],
- Kind::Unspecified,
- ))
- })
- }
-}
-
-impl Element for CrossfadeRenderElement {
- fn id(&self) -> &Id {
- self.0.id()
- }
-
- fn current_commit(&self) -> CommitCounter {
- self.0.current_commit()
- }
-
- fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
- self.0.geometry(scale)
- }
-
- fn transform(&self) -> Transform {
- self.0.transform()
- }
-
- fn src(&self) -> Rectangle<f64, Buffer> {
- self.0.src()
- }
-
- fn damage_since(
- &self,
- scale: Scale<f64>,
- commit: Option<CommitCounter>,
- ) -> DamageSet<i32, Physical> {
- self.0.damage_since(scale, commit)
- }
-
- fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
- self.0.opaque_regions(scale)
- }
-
- fn alpha(&self) -> f32 {
- self.0.alpha()
- }
-
- fn kind(&self) -> Kind {
- self.0.kind()
- }
-}
-
-impl RenderElement<GlesRenderer> for CrossfadeRenderElement {
- fn draw(
- &self,
- frame: &mut GlesFrame<'_>,
- src: Rectangle<f64, Buffer>,
- dst: Rectangle<i32, Physical>,
- damage: &[Rectangle<i32, Physical>],
- ) -> Result<(), GlesError> {
- RenderElement::<GlesRenderer>::draw(&self.0, frame, src, dst, damage)?;
- Ok(())
- }
-
- fn underlying_storage(&self, renderer: &mut GlesRenderer) -> Option<UnderlyingStorage> {
- self.0.underlying_storage(renderer)
- }
-}
-
-impl<'render> RenderElement<TtyRenderer<'render>> for CrossfadeRenderElement {
- fn draw(
- &self,
- frame: &mut TtyFrame<'_, '_>,
- src: Rectangle<f64, Buffer>,
- dst: Rectangle<i32, Physical>,
- damage: &[Rectangle<i32, Physical>],
- ) -> Result<(), TtyRendererError<'render>> {
- let gles_frame = frame.as_gles_frame();
- RenderElement::<GlesRenderer>::draw(&self.0, gles_frame, src, dst, damage)?;
- Ok(())
- }
-
- fn underlying_storage(&self, renderer: &mut TtyRenderer<'render>) -> Option<UnderlyingStorage> {
- self.0.underlying_storage(renderer)
- }
-}
diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs
index de40c274..0be48bc6 100644
--- a/src/render_helpers/mod.rs
+++ b/src/render_helpers/mod.rs
@@ -16,7 +16,6 @@ use smithay::wayland::shm;
use self::primary_gpu_texture::PrimaryGpuTextureRenderElement;
-pub mod crossfade;
pub mod gradient;
pub mod offscreen;
pub mod primary_gpu_pixel_shader;
@@ -24,6 +23,7 @@ pub mod primary_gpu_pixel_shader_with_textures;
pub mod primary_gpu_texture;
pub mod render_elements;
pub mod renderer;
+pub mod resize;
pub mod resources;
pub mod shaders;
pub mod snapshot;
diff --git a/src/render_helpers/primary_gpu_pixel_shader_with_textures.rs b/src/render_helpers/primary_gpu_pixel_shader_with_textures.rs
index 3037d731..45f93342 100644
--- a/src/render_helpers/primary_gpu_pixel_shader_with_textures.rs
+++ b/src/render_helpers/primary_gpu_pixel_shader_with_textures.rs
@@ -120,6 +120,12 @@ impl PixelWithTexturesProgram {
compile_program(gl, src, additional_uniforms, texture_uniforms)
})?
}
+
+ pub fn destroy(self, renderer: &mut GlesRenderer) -> Result<(), GlesError> {
+ renderer.with_context(move |gl| unsafe {
+ gl.DeleteProgram(self.0.program);
+ })
+ }
}
impl PrimaryGpuPixelShaderWithTexturesRenderElement {
diff --git a/src/render_helpers/resize.rs b/src/render_helpers/resize.rs
new file mode 100644
index 00000000..2242c99e
--- /dev/null
+++ b/src/render_helpers/resize.rs
@@ -0,0 +1,199 @@
+use std::collections::HashMap;
+
+use glam::{Mat3, Vec2};
+use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
+use smithay::backend::renderer::gles::{
+ GlesError, GlesFrame, GlesRenderer, GlesTexture, Uniform, UniformValue,
+};
+use smithay::backend::renderer::utils::{CommitCounter, DamageSet};
+use smithay::utils::{Buffer, Logical, Physical, Rectangle, Scale, Size, Transform};
+
+use super::primary_gpu_pixel_shader_with_textures::PrimaryGpuPixelShaderWithTexturesRenderElement;
+use super::renderer::AsGlesFrame;
+use super::shaders::Shaders;
+use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
+
+#[derive(Debug)]
+pub struct ResizeRenderElement(PrimaryGpuPixelShaderWithTexturesRenderElement);
+
+impl ResizeRenderElement {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ renderer: &mut GlesRenderer,
+ area: Rectangle<i32, Logical>,
+ scale: Scale<f64>,
+ texture_prev: (GlesTexture, Rectangle<i32, Physical>),
+ size_prev: Size<i32, Logical>,
+ texture_next: (GlesTexture, Rectangle<i32, Physical>),
+ size_next: Size<i32, Logical>,
+ progress: f32,
+ clamped_progress: f32,
+ result_alpha: f32,
+ ) -> Option<Self> {
+ let curr_geo = area;
+
+ let (texture_prev, tex_prev_geo) = texture_prev;
+ let (texture_next, tex_next_geo) = texture_next;
+
+ let scale_prev = area.size.to_f64() / size_prev.to_f64();
+ let scale_next = area.size.to_f64() / size_next.to_f64();
+
+ // Compute the area necessary to fit a crossfade.
+ let tex_prev_geo_scaled = tex_prev_geo.to_f64().upscale(scale_prev);
+ let tex_next_geo_scaled = tex_next_geo.to_f64().upscale(scale_next);
+ let combined_geo = tex_prev_geo_scaled.merge(tex_next_geo_scaled);
+
+ let size = combined_geo
+ .size
+ .to_logical(1.)
+ .to_buffer(1., Transform::Normal);
+
+ let area = Rectangle::from_loc_and_size(
+ area.loc + combined_geo.loc.to_logical(scale).to_i32_round(),
+ combined_geo.size.to_logical(scale).to_i32_round(),
+ );
+
+ // Convert Smithay types into glam types.
+ let area_loc = Vec2::new(area.loc.x as f32, area.loc.y as f32);
+ let area_size = Vec2::new(area.size.w as f32, area.size.h as f32);
+
+ let curr_geo_loc = Vec2::new(curr_geo.loc.x as f32, curr_geo.loc.y as f32);
+ let curr_geo_size = Vec2::new(curr_geo.size.w as f32, curr_geo.size.h as f32);
+
+ let tex_prev_geo_loc = Vec2::new(tex_prev_geo.loc.x as f32, tex_prev_geo.loc.y as f32);
+ let tex_prev_geo_size = Vec2::new(tex_prev_geo.size.w as f32, tex_prev_geo.size.h as f32);
+
+ let tex_next_geo_loc = Vec2::new(tex_next_geo.loc.x as f32, tex_next_geo.loc.y as f32);
+ let tex_next_geo_size = Vec2::new(tex_next_geo.size.w as f32, tex_next_geo.size.h as f32);
+
+ let size_prev = Vec2::new(size_prev.w as f32, size_prev.h as f32);
+ let size_next = Vec2::new(size_next.w as f32, size_next.h as f32);
+
+ let scale = Vec2::new(scale.x as f32, scale.y as f32);
+
+ // Compute the transformation matrices.
+ let input_to_curr_geo = Mat3::from_scale(area_size / curr_geo_size)
+ * Mat3::from_translation((area_loc - curr_geo_loc) / area_size);
+ let input_to_prev_geo = Mat3::from_scale(area_size / size_prev)
+ * Mat3::from_translation((area_loc - curr_geo_loc) / area_size);
+ let input_to_next_geo = Mat3::from_scale(area_size / size_next)
+ * Mat3::from_translation((area_loc - curr_geo_loc) / area_size);
+
+ let geo_to_tex_prev = Mat3::from_translation(-tex_prev_geo_loc / tex_prev_geo_size)
+ * Mat3::from_scale(size_prev / tex_prev_geo_size * scale);
+ let geo_to_tex_next = Mat3::from_translation(-tex_next_geo_loc / tex_next_geo_size)
+ * Mat3::from_scale(size_next / tex_next_geo_size * scale);
+
+ // Create the shader.
+ let make_uniform = |name, mat: Mat3| {
+ Uniform::new(
+ name,
+ UniformValue::Matrix3x3 {
+ matrices: vec![mat.to_cols_array()],
+ transpose: false,
+ },
+ )
+ };
+
+ Shaders::get(renderer).resize().map(|shader| {
+ Self(PrimaryGpuPixelShaderWithTexturesRenderElement::new(
+ shader,
+ HashMap::from([
+ (String::from("tex_prev"), texture_prev),
+ (String::from("tex_next"), texture_next),
+ ]),
+ area,
+ size,
+ None,
+ result_alpha,
+ vec![
+ make_uniform("input_to_curr_geo", input_to_curr_geo),
+ make_uniform("input_to_prev_geo", input_to_prev_geo),
+ make_uniform("input_to_next_geo", input_to_next_geo),
+ make_uniform("geo_to_tex_prev", geo_to_tex_prev),
+ make_uniform("geo_to_tex_next", geo_to_tex_next),
+ Uniform::new("progress", progress),
+ Uniform::new("clamped_progress", clamped_progress),
+ ],
+ Kind::Unspecified,
+ ))
+ })
+ }
+}
+
+impl Element for ResizeRenderElement {
+ fn id(&self) -> &Id {
+ self.0.id()
+ }
+
+ fn current_commit(&self) -> CommitCounter {
+ self.0.current_commit()
+ }
+
+ fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
+ self.0.geometry(scale)
+ }
+
+ fn transform(&self) -> Transform {
+ self.0.transform()
+ }
+
+ fn src(&self) -> Rectangle<f64, Buffer> {
+ self.0.src()
+ }
+
+ fn damage_since(
+ &self,
+ scale: Scale<f64>,
+ commit: Option<CommitCounter>,
+ ) -> DamageSet<i32, Physical> {
+ self.0.damage_since(scale, commit)
+ }
+
+ fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
+ self.0.opaque_regions(scale)
+ }
+
+ fn alpha(&self) -> f32 {
+ self.0.alpha()
+ }
+
+ fn kind(&self) -> Kind {
+ self.0.kind()
+ }
+}
+
+impl RenderElement<GlesRenderer> for ResizeRenderElement {
+ fn draw(
+ &self,
+ frame: &mut GlesFrame<'_>,
+ src: Rectangle<f64, Buffer>,
+ dst: Rectangle<i32, Physical>,
+ damage: &[Rectangle<i32, Physical>],
+ ) -> Result<(), GlesError> {
+ RenderElement::<GlesRenderer>::draw(&self.0, frame, src, dst, damage)?;
+ Ok(())
+ }
+
+ fn underlying_storage(&self, renderer: &mut GlesRenderer) -> Option<UnderlyingStorage> {
+ self.0.underlying_storage(renderer)
+ }
+}
+
+impl<'render> RenderElement<TtyRenderer<'render>> for ResizeRenderElement {
+ fn draw(
+ &self,
+ frame: &mut TtyFrame<'_, '_>,
+ src: Rectangle<f64, Buffer>,
+ dst: Rectangle<i32, Physical>,
+ damage: &[Rectangle<i32, Physical>],
+ ) -> Result<(), TtyRendererError<'render>> {
+ let gles_frame = frame.as_gles_frame();
+ RenderElement::<GlesRenderer>::draw(&self.0, gles_frame, src, dst, damage)?;
+ Ok(())
+ }
+
+ fn underlying_storage(&self, renderer: &mut TtyRenderer<'render>) -> Option<UnderlyingStorage> {
+ self.0.underlying_storage(renderer)
+ }
+}
diff --git a/src/render_helpers/shaders/crossfade.frag b/src/render_helpers/shaders/crossfade.frag
deleted file mode 100644
index 56280ad2..00000000
--- a/src/render_helpers/shaders/crossfade.frag
+++ /dev/null
@@ -1,31 +0,0 @@
-#version 100
-
-precision mediump float;
-
-uniform sampler2D tex_from;
-uniform vec2 tex_from_loc;
-uniform vec2 tex_from_size;
-
-uniform sampler2D tex_to;
-uniform vec2 tex_to_loc;
-uniform vec2 tex_to_size;
-
-uniform float alpha;
-uniform float amount;
-
-uniform vec2 size;
-varying vec2 v_coords;
-
-void main() {
- vec2 coords_from = (v_coords - tex_from_loc) / tex_from_size;
- vec2 coords_to = (v_coords - tex_to_loc) / tex_to_size;
-
- vec4 color_from = texture2D(tex_from, coords_from);
- vec4 color_to = texture2D(tex_to, coords_to);
-
- vec4 color = mix(color_from, color_to, amount);
- color = color * alpha;
-
- gl_FragColor = color;
-}
-
diff --git a/src/render_helpers/shaders/mod.rs b/src/render_helpers/shaders/mod.rs
index ebe0d08c..040cf503 100644
--- a/src/render_helpers/shaders/mod.rs
+++ b/src/render_helpers/shaders/mod.rs
@@ -1,3 +1,5 @@
+use std::cell::RefCell;
+
use smithay::backend::renderer::gles::{GlesPixelProgram, GlesRenderer, UniformName, UniformType};
use super::primary_gpu_pixel_shader_with_textures::PixelWithTexturesProgram;
@@ -5,7 +7,8 @@ use super::renderer::NiriRenderer;
pub struct Shaders {
pub gradient_border: Option<GlesPixelProgram>,
- pub crossfade: Option<PixelWithTexturesProgram>,
+ pub resize: Option<PixelWithTexturesProgram>,
+ pub custom_resize: RefCell<Option<PixelWithTexturesProgram>>,
}
impl Shaders {
@@ -28,26 +31,29 @@ impl Shaders {
})
.ok();
- let crossfade = PixelWithTexturesProgram::compile(
+ let resize = PixelWithTexturesProgram::compile(
renderer,
- include_str!("crossfade.frag"),
+ include_str!("resize.frag"),
&[
- UniformName::new("tex_from_loc", UniformType::_2f),
- UniformName::new("tex_from_size", UniformType::_2f),
- UniformName::new("tex_to_loc", UniformType::_2f),
- UniformName::new("tex_to_size", UniformType::_2f),
- UniformName::new("amount", UniformType::_1f),
+ UniformName::new("input_to_curr_geo", UniformType::Matrix3x3),
+ UniformName::new("input_to_prev_geo", UniformType::Matrix3x3),
+ UniformName::new("input_to_next_geo", UniformType::Matrix3x3),
+ UniformName::new("geo_to_tex_prev", UniformType::Matrix3x3),
+ UniformName::new("geo_to_tex_next", UniformType::Matrix3x3),
+ UniformName::new("progress", UniformType::_1f),
+ UniformName::new("clamped_progress", UniformType::_1f),
],
- &["tex_from", "tex_to"],
+ &["tex_prev", "tex_next"],
)
.map_err(|err| {
- warn!("error compiling crossfade shader: {err:?}");
+ warn!("error compiling resize shader: {err:?}");
})
.ok();
Self {
gradient_border,
- crossfade,
+ resize,
+ custom_resize: RefCell::new(None),
}
}
@@ -57,6 +63,20 @@ impl Shaders {
data.get()
.expect("shaders::init() must be called when creating the renderer")
}
+
+ pub fn replace_custom_resize_program(
+ &self,
+ program: Option<PixelWithTexturesProgram>,
+ ) -> Option<PixelWithTexturesProgram> {
+ self.custom_resize.replace(program)
+ }
+
+ pub fn resize(&self) -> Option<PixelWithTexturesProgram> {
+ self.custom_resize
+ .borrow()
+ .clone()
+ .or_else(|| self.resize.clone())
+ }
}
pub fn init(renderer: &mut GlesRenderer) {
@@ -66,3 +86,36 @@ pub fn init(renderer: &mut GlesRenderer) {
error!("shaders were already compiled");
}
}
+
+pub fn set_custom_resize_program(renderer: &mut GlesRenderer, src: Option<&str>) {
+ let program = if let Some(src) = src {
+ match PixelWithTexturesProgram::compile(
+ renderer,
+ src,
+ &[
+ UniformName::new("input_to_curr_geo", UniformType::Matrix3x3),
+ UniformName::new("input_to_prev_geo", UniformType::Matrix3x3),
+ UniformName::new("input_to_next_geo", UniformType::Matrix3x3),
+ UniformName::new("geo_to_tex_prev", UniformType::Matrix3x3),
+ UniformName::new("geo_to_tex_next", UniformType::Matrix3x3),
+ UniformName::new("progress", UniformType::_1f),
+ UniformName::new("clamped_progress", UniformType::_1f),
+ ],
+ &["tex_prev", "tex_next"],
+ ) {
+ Ok(program) => Some(program),
+ Err(err) => {
+ warn!("error compiling custom resize shader: {err:?}");
+ return;
+ }
+ }
+ } else {
+ None
+ };
+
+ if let Some(prev) = Shaders::get(renderer).replace_custom_resize_program(program) {
+ if let Err(err) = prev.destroy(renderer) {
+ warn!("error destroying previous custom resize shader: {err:?}");
+ }
+ }
+}
diff --git a/src/render_helpers/shaders/resize.frag b/src/render_helpers/shaders/resize.frag
new file mode 100644
index 00000000..d77b9163
--- /dev/null
+++ b/src/render_helpers/shaders/resize.frag
@@ -0,0 +1,41 @@
+#version 100
+
+precision mediump float;
+
+varying vec2 v_coords;
+uniform vec2 size;
+
+uniform mat3 input_to_curr_geo;
+uniform mat3 input_to_prev_geo;
+uniform mat3 input_to_next_geo;
+
+uniform sampler2D tex_prev;
+uniform mat3 geo_to_tex_prev;
+
+uniform sampler2D tex_next;
+uniform mat3 geo_to_tex_next;
+
+uniform float progress;
+uniform float clamped_progress;
+
+uniform float alpha;
+
+vec4 crossfade() {
+ vec3 coords_curr_geo = input_to_curr_geo * vec3(v_coords, 1.0);
+
+ vec3 coords_tex_prev = geo_to_tex_prev * coords_curr_geo;
+ vec4 color_prev = texture2D(tex_prev, vec2(coords_tex_prev));
+
+ vec3 coords_tex_next = geo_to_tex_next * coords_curr_geo;
+ vec4 color_next = texture2D(tex_next, vec2(coords_tex_next));
+
+ vec4 color = mix(color_prev, color_next, clamped_progress);
+ return color;
+}
+