aboutsummaryrefslogtreecommitdiff
path: root/src/render_helpers
diff options
context:
space:
mode:
Diffstat (limited to 'src/render_helpers')
-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
7 files changed, 311 insertions, 204 deletions
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;
+}
+
+void main() {
+ vec4 color = crossfade();
+
+ gl_FragColor = color * alpha;
+}
+