diff options
Diffstat (limited to 'src/render_helpers')
| -rw-r--r-- | src/render_helpers/crossfade.rs | 161 | ||||
| -rw-r--r-- | src/render_helpers/mod.rs | 2 | ||||
| -rw-r--r-- | src/render_helpers/primary_gpu_pixel_shader_with_textures.rs | 6 | ||||
| -rw-r--r-- | src/render_helpers/resize.rs | 199 | ||||
| -rw-r--r-- | src/render_helpers/shaders/crossfade.frag | 31 | ||||
| -rw-r--r-- | src/render_helpers/shaders/mod.rs | 75 | ||||
| -rw-r--r-- | src/render_helpers/shaders/resize.frag | 41 |
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; +} + |
