mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
render_helpers: Add GradientFadeTexture
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user