diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/render_helpers/gradient_fade_texture.rs | 136 | ||||
| -rw-r--r-- | src/render_helpers/mod.rs | 1 | ||||
| -rw-r--r-- | src/render_helpers/shaders/gradient_fade.frag | 47 | ||||
| -rw-r--r-- | src/render_helpers/shaders/mod.rs | 12 | ||||
| -rw-r--r-- | src/render_helpers/texture.rs | 5 |
5 files changed, 201 insertions, 0 deletions
diff --git a/src/render_helpers/gradient_fade_texture.rs b/src/render_helpers/gradient_fade_texture.rs new file mode 100644 index 00000000..a51ded33 --- /dev/null +++ b/src/render_helpers/gradient_fade_texture.rs @@ -0,0 +1,136 @@ +use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage}; +use smithay::backend::renderer::gles::{ + GlesError, GlesFrame, GlesRenderer, GlesTexProgram, GlesTexture, Uniform, +}; +use smithay::backend::renderer::utils::{CommitCounter, DamageSet, OpaqueRegions}; +use smithay::utils::{Buffer, Physical, Rectangle, Scale, Transform}; + +use super::texture::TextureRenderElement; +use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError}; +use crate::render_helpers::renderer::AsGlesFrame as _; +use crate::render_helpers::shaders::Shaders; + +#[derive(Debug, Clone)] +pub struct GradientFadeTextureRenderElement { + inner: TextureRenderElement<GlesTexture>, + program: GradientFadeShader, + uniforms: Vec<Uniform<'static>>, +} + +#[derive(Debug, Clone)] +pub struct GradientFadeShader(GlesTexProgram); + +impl GradientFadeTextureRenderElement { + pub fn new(texture: TextureRenderElement<GlesTexture>, program: GradientFadeShader) -> Self { + let logical_w = texture.buffer().logical_size().w; + let logical_src_w = texture.logical_src().size.w; + let cutoff = if logical_src_w < logical_w { + // Texture is clipped, add a fade. + let cutoff = 1. - f64::min(18. / logical_src_w, 1.); + let full = logical_src_w / logical_w; + ((cutoff * full) as f32, full as f32) + } else { + // Texture is displayed full-size, no cutoff necessary. + (1., 1.) + }; + let uniforms = vec![Uniform::new("cutoff", cutoff)]; + Self { + inner: texture, + program, + uniforms, + } + } + + pub fn shader(renderer: &mut GlesRenderer) -> Option<GradientFadeShader> { + let program = Shaders::get(renderer).gradient_fade.clone(); + program.map(GradientFadeShader) + } +} + +impl Element for GradientFadeTextureRenderElement { + fn id(&self) -> &Id { + self.inner.id() + } + + fn current_commit(&self) -> CommitCounter { + self.inner.current_commit() + } + + fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> { + self.inner.geometry(scale) + } + + fn transform(&self) -> Transform { + self.inner.transform() + } + + fn src(&self) -> Rectangle<f64, Buffer> { + self.inner.src() + } + + fn damage_since( + &self, + scale: Scale<f64>, + commit: Option<CommitCounter>, + ) -> DamageSet<i32, Physical> { + self.inner.damage_since(scale, commit) + } + + fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> { + self.inner.opaque_regions(scale) + } + + fn alpha(&self) -> f32 { + self.inner.alpha() + } + + fn kind(&self) -> Kind { + self.inner.kind() + } +} + +impl RenderElement<GlesRenderer> for GradientFadeTextureRenderElement { + fn draw( + &self, + frame: &mut GlesFrame<'_, '_>, + src: Rectangle<f64, Buffer>, + dst: Rectangle<i32, Physical>, + damage: &[Rectangle<i32, Physical>], + opaque_regions: &[Rectangle<i32, Physical>], + ) -> Result<(), GlesError> { + frame.override_default_tex_program(self.program.0.clone(), self.uniforms.clone()); + RenderElement::<GlesRenderer>::draw(&self.inner, frame, src, dst, damage, opaque_regions)?; + frame.clear_tex_program_override(); + Ok(()) + } + + fn underlying_storage(&self, _renderer: &mut GlesRenderer) -> Option<UnderlyingStorage<'_>> { + // If scanout for things other than Wayland buffers is implemented, this will need to take + // the target GPU into account. + None + } +} + +impl<'render> RenderElement<TtyRenderer<'render>> for GradientFadeTextureRenderElement { + fn draw( + &self, + frame: &mut TtyFrame<'render, '_, '_>, + src: Rectangle<f64, Buffer>, + dst: Rectangle<i32, Physical>, + damage: &[Rectangle<i32, Physical>], + opaque_regions: &[Rectangle<i32, Physical>], + ) -> Result<(), TtyRendererError<'render>> { + let gles_frame = frame.as_gles_frame(); + RenderElement::<GlesRenderer>::draw(&self, gles_frame, src, dst, damage, opaque_regions)?; + Ok(()) + } + + fn underlying_storage( + &self, + _renderer: &mut TtyRenderer<'render>, + ) -> Option<UnderlyingStorage<'_>> { + // If scanout for things other than Wayland buffers is implemented, this will need to take + // the target GPU into account. + None + } +} diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs index 11c92185..12d6a774 100644 --- a/src/render_helpers/mod.rs +++ b/src/render_helpers/mod.rs @@ -22,6 +22,7 @@ pub mod border; pub mod clipped_surface; pub mod damage; pub mod debug; +pub mod gradient_fade_texture; pub mod memory; pub mod offscreen; pub mod primary_gpu_texture; diff --git a/src/render_helpers/shaders/gradient_fade.frag b/src/render_helpers/shaders/gradient_fade.frag new file mode 100644 index 00000000..eccc7066 --- /dev/null +++ b/src/render_helpers/shaders/gradient_fade.frag @@ -0,0 +1,47 @@ +#version 100 + +//_DEFINES_ + +#if defined(EXTERNAL) +#extension GL_OES_EGL_image_external : require +#endif + +precision highp float; +#if defined(EXTERNAL) +uniform samplerExternalOES tex; +#else +uniform sampler2D tex; +#endif + +uniform float alpha; +varying vec2 v_coords; + +#if defined(DEBUG_FLAGS) +uniform float tint; +#endif + +// x is left edge, y is right edge of the gradient. +uniform vec2 cutoff; + +void main() { + // Sample the texture. + vec4 color = texture2D(tex, v_coords); +#if defined(NO_ALPHA) + color = vec4(color.rgb, 1.0); +#endif + + if (cutoff.x < cutoff.y) { + float fade = clamp((cutoff.y - v_coords.x) / (cutoff.y - cutoff.x), 0.0, 1.0); + color = color * fade; + } + + // Apply final alpha and tint. + color = color * alpha; + +#if defined(DEBUG_FLAGS) + if (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/mod.rs b/src/render_helpers/shaders/mod.rs index 2db00662..6fccce7f 100644 --- a/src/render_helpers/shaders/mod.rs +++ b/src/render_helpers/shaders/mod.rs @@ -14,6 +14,7 @@ pub struct Shaders { pub shadow: Option<ShaderProgram>, pub clipped_surface: Option<GlesTexProgram>, pub resize: Option<ShaderProgram>, + pub gradient_fade: Option<GlesTexProgram>, pub custom_resize: RefCell<Option<ShaderProgram>>, pub custom_close: RefCell<Option<ShaderProgram>>, pub custom_open: RefCell<Option<ShaderProgram>>, @@ -96,11 +97,22 @@ impl Shaders { }) .ok(); + let gradient_fade = renderer + .compile_custom_texture_shader( + include_str!("gradient_fade.frag"), + &[UniformName::new("cutoff", UniformType::_2f)], + ) + .map_err(|err| { + warn!("error compiling gradient fade shader: {err:?}"); + }) + .ok(); + Self { border, shadow, clipped_surface, resize, + gradient_fade, custom_resize: RefCell::new(None), custom_close: RefCell::new(None), custom_open: RefCell::new(None), diff --git a/src/render_helpers/texture.rs b/src/render_helpers/texture.rs index be8b831e..1d653c45 100644 --- a/src/render_helpers/texture.rs +++ b/src/render_helpers/texture.rs @@ -152,6 +152,11 @@ impl<T: Texture> TextureRenderElement<T> { .or_else(|| self.src.map(|src| src.size)) .unwrap_or_else(|| self.buffer.logical_size()) } + + pub fn logical_src(&self) -> Rectangle<f64, Logical> { + self.src + .unwrap_or_else(|| Rectangle::from_size(self.logical_size())) + } } impl<T: Texture> Element for TextureRenderElement<T> { |
