kms: Refactor out postprocessing helpers

This commit is contained in:
Victoria Brekenfeld 2025-03-19 14:15:47 +01:00 committed by Victoria Brekenfeld
parent a748ea885e
commit 18335c6758
4 changed files with 236 additions and 118 deletions

View file

@ -1,15 +1,16 @@
use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement};
#[cfg(feature = "debug")]
use smithay::backend::renderer::{element::texture::TextureRenderElement, gles::GlesTexture};
use smithay::{
backend::renderer::{
element::{
memory::MemoryRenderBufferRenderElement,
surface::WaylandSurfaceRenderElement,
texture::TextureRenderElement,
utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement},
Element, Id, Kind, RenderElement, UnderlyingStorage,
},
gles::{GlesError, GlesTexture},
gles::{element::TextureShaderElement, GlesError},
glow::{GlowFrame, GlowRenderer},
utils::{CommitCounter, DamageSet, OpaqueRegions},
ImportAll, ImportMem, Renderer,
@ -32,10 +33,8 @@ where
Dnd(WaylandSurfaceRenderElement<R>),
MoveGrab(RescaleRenderElement<CosmicMappedRenderElement<R>>),
AdditionalDamage(DamageElement),
Mirror(
CropRenderElement<
RelocateRenderElement<RescaleRenderElement<TextureRenderElement<GlesTexture>>>,
>,
Postprocess(
CropRenderElement<RelocateRenderElement<RescaleRenderElement<TextureShaderElement>>>,
),
Zoom(MemoryRenderBufferRenderElement<R>),
#[cfg(feature = "debug")]
@ -55,7 +54,7 @@ where
CosmicElement::Dnd(elem) => elem.id(),
CosmicElement::MoveGrab(elem) => elem.id(),
CosmicElement::AdditionalDamage(elem) => elem.id(),
CosmicElement::Mirror(elem) => elem.id(),
CosmicElement::Postprocess(elem) => elem.id(),
CosmicElement::Zoom(elem) => elem.id(),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.id(),
@ -69,7 +68,7 @@ where
CosmicElement::Dnd(elem) => elem.current_commit(),
CosmicElement::MoveGrab(elem) => elem.current_commit(),
CosmicElement::AdditionalDamage(elem) => elem.current_commit(),
CosmicElement::Mirror(elem) => elem.current_commit(),
CosmicElement::Postprocess(elem) => elem.current_commit(),
CosmicElement::Zoom(elem) => elem.current_commit(),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.current_commit(),
@ -83,7 +82,7 @@ where
CosmicElement::Dnd(elem) => elem.src(),
CosmicElement::MoveGrab(elem) => elem.src(),
CosmicElement::AdditionalDamage(elem) => elem.src(),
CosmicElement::Mirror(elem) => elem.src(),
CosmicElement::Postprocess(elem) => elem.src(),
CosmicElement::Zoom(elem) => elem.src(),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.src(),
@ -97,7 +96,7 @@ where
CosmicElement::Dnd(elem) => elem.geometry(scale),
CosmicElement::MoveGrab(elem) => elem.geometry(scale),
CosmicElement::AdditionalDamage(elem) => elem.geometry(scale),
CosmicElement::Mirror(elem) => elem.geometry(scale),
CosmicElement::Postprocess(elem) => elem.geometry(scale),
CosmicElement::Zoom(elem) => elem.geometry(scale),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.geometry(scale),
@ -111,7 +110,7 @@ where
CosmicElement::Dnd(elem) => elem.location(scale),
CosmicElement::MoveGrab(elem) => elem.location(scale),
CosmicElement::AdditionalDamage(elem) => elem.location(scale),
CosmicElement::Mirror(elem) => elem.location(scale),
CosmicElement::Postprocess(elem) => elem.location(scale),
CosmicElement::Zoom(elem) => elem.location(scale),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.location(scale),
@ -125,7 +124,7 @@ where
CosmicElement::Dnd(elem) => elem.transform(),
CosmicElement::MoveGrab(elem) => elem.transform(),
CosmicElement::AdditionalDamage(elem) => elem.transform(),
CosmicElement::Mirror(elem) => elem.transform(),
CosmicElement::Postprocess(elem) => elem.transform(),
CosmicElement::Zoom(elem) => elem.transform(),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.transform(),
@ -143,7 +142,7 @@ where
CosmicElement::Dnd(elem) => elem.damage_since(scale, commit),
CosmicElement::MoveGrab(elem) => elem.damage_since(scale, commit),
CosmicElement::AdditionalDamage(elem) => elem.damage_since(scale, commit),
CosmicElement::Mirror(elem) => elem.damage_since(scale, commit),
CosmicElement::Postprocess(elem) => elem.damage_since(scale, commit),
CosmicElement::Zoom(elem) => elem.damage_since(scale, commit),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.damage_since(scale, commit),
@ -157,7 +156,7 @@ where
CosmicElement::Dnd(elem) => elem.opaque_regions(scale),
CosmicElement::MoveGrab(elem) => elem.opaque_regions(scale),
CosmicElement::AdditionalDamage(elem) => elem.opaque_regions(scale),
CosmicElement::Mirror(elem) => elem.opaque_regions(scale),
CosmicElement::Postprocess(elem) => elem.opaque_regions(scale),
CosmicElement::Zoom(elem) => elem.opaque_regions(scale),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.opaque_regions(scale),
@ -171,7 +170,7 @@ where
CosmicElement::Dnd(elem) => elem.alpha(),
CosmicElement::MoveGrab(elem) => elem.alpha(),
CosmicElement::AdditionalDamage(elem) => elem.alpha(),
CosmicElement::Mirror(elem) => elem.alpha(),
CosmicElement::Postprocess(elem) => elem.alpha(),
CosmicElement::Zoom(elem) => elem.alpha(),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.alpha(),
@ -185,7 +184,7 @@ where
CosmicElement::Dnd(elem) => elem.kind(),
CosmicElement::MoveGrab(elem) => elem.kind(),
CosmicElement::AdditionalDamage(elem) => elem.kind(),
CosmicElement::Mirror(elem) => elem.kind(),
CosmicElement::Postprocess(elem) => elem.kind(),
CosmicElement::Zoom(elem) => elem.kind(),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.kind(),
@ -216,7 +215,7 @@ where
CosmicElement::AdditionalDamage(elem) => {
RenderElement::<R>::draw(elem, frame, src, dst, damage, opaque_regions)
}
CosmicElement::Mirror(elem) => {
CosmicElement::Postprocess(elem) => {
let glow_frame = R::glow_frame_mut(frame);
RenderElement::<GlowRenderer>::draw(
elem,
@ -252,7 +251,7 @@ where
CosmicElement::Dnd(elem) => elem.underlying_storage(renderer),
CosmicElement::MoveGrab(elem) => elem.underlying_storage(renderer),
CosmicElement::AdditionalDamage(elem) => elem.underlying_storage(renderer),
CosmicElement::Mirror(elem) => {
CosmicElement::Postprocess(elem) => {
let glow_renderer = renderer.glow_renderer_mut();
elem.underlying_storage(glow_renderer)
}

View file

@ -13,6 +13,7 @@ use std::{
use crate::debug::fps_ui;
use crate::{
backend::{kms::render::gles::GbmGlowBackend, render::element::DamageElement},
config::ScreenFilter,
shell::{
element::CosmicMappedKey,
focus::{render_input_order, target::WindowGroup, Stage},
@ -36,7 +37,7 @@ use cosmic::Theme;
use element::FromGlesError;
use smithay::{
backend::{
allocator::dmabuf::Dmabuf,
allocator::{dmabuf::Dmabuf, Fourcc},
drm::{DrmDeviceFd, DrmNode},
renderer::{
damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult},
@ -52,13 +53,15 @@ use smithay::{
glow::GlowRenderer,
multigpu::{Error as MultiError, MultiFrame, MultiRenderer},
sync::SyncPoint,
Bind, Blit, Color32F, ExportMem, ImportAll, ImportMem, Offscreen, Renderer,
Bind, Blit, Color32F, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, Texture,
TextureFilter,
},
},
input::Seat,
output::{Output, OutputNoMode},
utils::{IsAlive, Logical, Monotonic, Point, Rectangle, Scale, Time, Transform},
utils::{
IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Size, Time, Transform,
},
wayland::{dmabuf::get_dmabuf, session_lock::LockSurface},
};
@ -105,6 +108,7 @@ impl<'a> AsMut<GlowRenderer> for RendererRef<'a> {
pub static CLEAR_COLOR: Color32F = Color32F::new(0.153, 0.161, 0.165, 1.0);
pub static OUTLINE_SHADER: &str = include_str!("./shaders/rounded_outline.frag");
pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag");
pub static POSTPROCESS_SHADER: &str = include_str!("./shaders/offscreen.frag");
pub static GROUP_COLOR: [f32; 3] = [0.788, 0.788, 0.788];
pub static ACTIVE_GROUP_COLOR: [f32; 3] = [0.58, 0.922, 0.922];
@ -346,11 +350,14 @@ impl BackdropShader {
}
}
pub struct PostprocessShader(pub GlesTexProgram);
pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> {
{
let egl_context = renderer.egl_context();
if egl_context.user_data().get::<IndicatorShader>().is_some()
&& egl_context.user_data().get::<BackdropShader>().is_some()
&& egl_context.user_data().get::<PostprocessShader>().is_some()
{
return Ok(());
}
@ -371,6 +378,13 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> {
UniformName::new("radius", UniformType::_1f),
],
)?;
let postprocess_shader = renderer.compile_custom_texture_shader(
POSTPROCESS_SHADER,
&[
UniformName::new("invert", UniformType::_1f),
UniformName::new("color_mode", UniformType::_1f),
],
)?;
let egl_context = renderer.egl_context();
egl_context
@ -379,6 +393,9 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> {
egl_context
.user_data()
.insert_if_missing(|| BackdropShader(rectangle_shader));
egl_context
.user_data()
.insert_if_missing(|| PostprocessShader(postprocess_shader));
Ok(())
}
@ -976,6 +993,83 @@ where
}
}
// Used for mirroring and postprocessing
#[derive(Debug)]
pub struct PostprocessState {
pub texture: TextureRenderBuffer<GlesTexture>,
pub damage_tracker: OutputDamageTracker,
pub output_config: PostprocessOutputConfig,
}
impl PostprocessState {
pub fn new_with_renderer<R: Renderer + Offscreen<GlesTexture>>(
renderer: &mut R,
format: Fourcc,
output_config: PostprocessOutputConfig,
) -> Result<Self, R::Error> {
let size = output_config.size;
let buffer_size = size.to_logical(1).to_buffer(1, Transform::Normal);
let opaque_regions = vec![Rectangle::from_size(buffer_size)];
let texture = Offscreen::<GlesTexture>::create_buffer(renderer, format, buffer_size)?;
let texture_buffer = TextureRenderBuffer::from_texture(
renderer,
texture,
1,
Transform::Normal,
Some(opaque_regions),
);
// Don't use `from_output` to avoid applying output transform
let damage_tracker =
OutputDamageTracker::new(size, output_config.fractional_scale, Transform::Normal);
Ok(PostprocessState {
texture: texture_buffer,
damage_tracker,
output_config,
})
}
}
#[derive(Debug, PartialEq)]
pub struct PostprocessOutputConfig {
pub size: Size<i32, Physical>,
pub fractional_scale: f64,
}
impl PostprocessOutputConfig {
pub fn for_output_untransformed(output: &Output) -> Self {
Self {
// Apply inverse of output transform to mode size to get correct size
// for an untransformed render.
size: output.current_transform().invert().transform_size(
output
.current_mode()
.map(|mode| mode.size)
.unwrap_or_default(),
),
fractional_scale: output.current_scale().fractional_scale(),
}
}
pub fn for_output(output: &Output) -> Self {
Self {
size: output
.current_mode()
.map(|mode| mode.size)
.unwrap_or_default(),
fractional_scale: output.current_scale().fractional_scale(),
}
}
}
#[derive(Debug, Default)]
pub struct ScreenFilterStorage {
pub filter: ScreenFilter,
pub state: Option<PostprocessState>,
}
#[profiling::function]
pub fn render_output<'d, R, OffTarget>(
gpu: Option<&DrmNode>,

View file

@ -0,0 +1,90 @@
#version 100
//_DEFINES_
#if defined(EXTERNAL)
#extension GL_OES_EGL_image_external : require
#endif
precision mediump 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
uniform float invert;
uniform float color_mode;
void main() {
vec4 color = texture2D(tex, v_coords);
#if defined(NO_ALPHA)
color = vec4(color.rgb, 1.0) * alpha;
#else
color = color * alpha;
#endif
// un-multiply
color.rgb /= color.a;
// First invert then filter
if (invert == 1.0) {
color.rgb = 1.0 - color.rgb;
}
if (color_mode == 1.0) { // greyscale
float value = (color.r + color.g + color.b) / 3.0;
color = vec4(value, value, value, color.a);
} else if (color_mode >= 2.0) {
float L = (17.8824 * color.r) + (43.5161 * color.g) + (4.11935 * color.b);
float M = (3.45565 * color.r) + (27.1554 * color.g) + (3.86714 * color.b);
float S = (0.0299566 * color.r) + (0.184309 * color.g) + (1.46709 * color.b);
float l, m, s;
if (color_mode == 2.0) { // Protanopia
l = 0.0 * L + 2.02344 * M + -2.52581 * S;
m = 0.0 * L + 1.0 * M + 0.0 * S;
s = 0.0 * L + 0.0 * M + 1.0 * S;
} else if (color_mode == 3.0) { // Deuteranopia
l = 1.0 * L + 0.0 * M + 0.0 * S;
m = 0.494207 * L + 0.0 * M + 1.24827 * S;
s = 0.0 * L + 0.0 * M + 1.0 * S;
} else if (color_mode == 4.0) { // Tritanopia
l = 1.0 * L + 0.0 * M + 0.0 * S;
m = 0.0 * L + 1.0 * M + 0.0 * S;
s = -0.395913 * L + 0.801109 * M + 0.0 * S;
} else {
// unknown
l = L;
m = M;
s = S;
}
vec3 error;
error.r = (0.0809444479 * l) + (-0.130504409 * m) + (0.116721066 * s);
error.g = (-0.0102485335 * l) + (0.0540193266 * m) + (-0.113614708 * s);
error.b = (-0.000365296938 * l) + (-0.00412161469 * m) + (0.693511405 * s);
vec3 diff = color.rgb - error;
vec3 correction;
correction.r = 0.0;
correction.g = (diff.r * 0.7) + (diff.g * 1.0);
correction.b = (diff.r * 0.7) + (diff.b * 1.0);
color.rgb += correction;
}
// re-multiply
color.rgb *= color.a;
gl_FragColor = color;
}