aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/render_helpers/gradient_fade_texture.rs136
-rw-r--r--src/render_helpers/mod.rs1
-rw-r--r--src/render_helpers/shaders/gradient_fade.frag47
-rw-r--r--src/render_helpers/shaders/mod.rs12
-rw-r--r--src/render_helpers/texture.rs5
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> {