diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 5a656e52..c76b163b 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -2,7 +2,7 @@ use cosmic_config::{cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry}; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::{collections::HashMap, path::PathBuf}; pub mod input; pub mod workspace; @@ -31,6 +31,8 @@ pub struct CosmicCompConfig { pub focus_follows_cursor_delay: u64, /// Let X11 applications scale themselves pub descale_xwayland: bool, + /// Path to postprocess shader applied to whole screen + pub postprocess_shader_path: Option, } impl Default for CosmicCompConfig { @@ -60,6 +62,7 @@ impl Default for CosmicCompConfig { cursor_follows_focus: false, focus_follows_cursor_delay: 250, descale_xwayland: false, + postprocess_shader_path: None, } } } diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index aa932230..d5fcb258 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -266,6 +266,7 @@ impl State { { for (conn, maybe_crtc) in connectors { + let postprocess_shader = self.backend.kms().postprocess_shader.clone(); match device.connector_added( self.backend.kms().primary_node.as_ref(), conn, @@ -274,6 +275,7 @@ impl State { &self.common.event_loop_handle, self.common.shell.clone(), self.common.startup_done.clone(), + postprocess_shader, ) { Ok((output, should_expose)) => { if should_expose { @@ -359,6 +361,7 @@ impl State { } for (conn, maybe_crtc) in changes.added { + let postprocess_shader = backend.postprocess_shader.clone(); match device.connector_added( backend.primary_node.as_ref(), conn, @@ -367,6 +370,7 @@ impl State { &self.common.event_loop_handle, self.common.shell.clone(), self.common.startup_done.clone(), + postprocess_shader, ) { Ok((output, should_expose)) => { if should_expose { @@ -518,6 +522,7 @@ impl Device { evlh: &LoopHandle<'static, State>, shell: Arc>, startup_done: Arc, + postprocess_shader: Option, ) -> Result<(Output, bool)> { let output = self .outputs @@ -582,7 +587,8 @@ impl Device { shell, startup_done, ) { - Ok(data) => { + Ok(mut data) => { + data.set_postprocess_shader(postprocess_shader); self.surfaces.insert(crtc, data); true } diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index ce467ece..c970632a 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -72,6 +72,8 @@ pub struct KmsState { pub software_renderer: Option, pub api: GpuManager>, + postprocess_shader: Option, + session: LibSeatSession, libinput: Libinput, @@ -140,6 +142,8 @@ pub fn init_backend( software_renderer, api: GpuManager::new(GbmGlowBackend::new()).context("Failed to initialize gpu backend")?, + postprocess_shader: None, + session, libinput: libinput_context, @@ -660,6 +664,7 @@ impl KmsState { loop_handle, shell.clone(), startup_done.clone(), + self.postprocess_shader.clone(), )?; if output.mirroring().is_none() { w += output.geometry().size.w as u32; @@ -926,4 +931,13 @@ impl KmsState { Ok(all_outputs) } + + pub fn update_postprocess_shader(&mut self, shader: Option<&str>) { + self.postprocess_shader = shader.map(|x| x.to_owned()); + for device in self.drm_devices.values_mut() { + for surface in device.surfaces.values_mut() { + surface.set_postprocess_shader(self.postprocess_shader.clone()); + } + } + } } diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index 0f361bc1..08e1d1a5 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -3,7 +3,8 @@ use crate::{ backend::render::{ element::{CosmicElement, DamageElement}, - init_shaders, output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR, + init_shaders, output_elements, update_postprocess_shader, CursorMode, GlMultiRenderer, + PostprocessShader, CLEAR_COLOR, }, config::AdaptiveSync, shell::Shell, @@ -40,9 +41,9 @@ use smithay::{ utils::{constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior}, Element, Kind, RenderElementStates, }, - gles::{GlesRenderbuffer, GlesTexture}, + gles::{element::TextureShaderElement, GlesRenderbuffer, GlesRenderer, GlesTexture}, glow::GlowRenderer, - multigpu::{Error as MultiError, GpuManager}, + multigpu::{ApiDevice, Error as MultiError, GpuManager}, sync::SyncPoint, utils::with_renderer_surface_state, Bind, ImportDma, Offscreen, Renderer, Texture, @@ -74,7 +75,7 @@ use smithay::{ use tracing::{error, trace, warn}; use std::{ - borrow::BorrowMut, + borrow::{Borrow, BorrowMut}, collections::{HashMap, HashSet}, mem, sync::{ @@ -136,7 +137,8 @@ pub struct SurfaceThreadState { output: Output, mirroring: Option, - mirroring_textures: HashMap, + offscreen_textures: HashMap, + postprocess_shader: Option, shell: Arc>, @@ -147,13 +149,14 @@ pub struct SurfaceThreadState { egui: EguiState, } +// Used for mirroring and postprocessing #[derive(Debug)] -struct MirroringState { +struct OffscreenState { texture: TextureRenderBuffer, damage_tracker: OutputDamageTracker, } -impl MirroringState { +impl OffscreenState { fn new_with_renderer( renderer: &mut GlMultiRenderer, format: Fourcc, @@ -179,7 +182,7 @@ impl MirroringState { let damage_tracker = OutputDamageTracker::from_output(output); - Ok(MirroringState { + Ok(OffscreenState { texture: texture_buffer, damage_tracker, }) @@ -236,6 +239,7 @@ pub enum ThreadCommand { node: DrmNode, }, UpdateMirroring(Option), + UpdatePostprocessShader(Option), VBlank(Option), ScheduleRender, AdaptiveSyncAvailable(SyncSender>), @@ -400,6 +404,12 @@ impl Surface { .send(ThreadCommand::UpdateMirroring(output)); } + pub fn set_postprocess_shader(&mut self, shader: Option) { + let _ = self + .thread_command + .send(ThreadCommand::UpdatePostprocessShader(shader)); + } + pub fn adaptive_sync_support(&self) -> Result { let (tx, rx) = std::sync::mpsc::sync_channel(1); let _ = self @@ -536,7 +546,8 @@ fn surface_thread( output, mirroring: None, - mirroring_textures: HashMap::new(), + offscreen_textures: HashMap::new(), + postprocess_shader: None, shell, loop_handle: event_loop.handle(), @@ -574,6 +585,9 @@ fn surface_thread( Event::Msg(ThreadCommand::UpdateMirroring(mirroring_output)) => { state.update_mirroring(mirroring_output); } + Event::Msg(ThreadCommand::UpdatePostprocessShader(shader)) => { + state.update_postprocess_shader(shader); + } Event::Msg(ThreadCommand::AdaptiveSyncAvailable(result)) => { if let Some(compositor) = state.compositor.as_mut() { let _ = result.send( @@ -708,6 +722,7 @@ impl SurfaceThreadState { let mut renderer = unsafe { GlowRenderer::new(egl) }.context("Failed to create renderer")?; init_shaders(renderer.borrow_mut()).context("Failed to initialize shaders")?; + update_postprocess_shader(renderer.borrow_mut(), self.postprocess_shader.as_deref()); #[cfg(feature = "debug")] { @@ -1044,34 +1059,47 @@ impl SurfaceThreadState { .collect() }).unwrap_or_default(); + let postprocess_shader = Borrow::::borrow(renderer.as_mut()) + .egl_context() + .user_data() + .get::() + .and_then(|x| x.0.lock().unwrap().clone()); + // actual rendering - let res = if let Some(mirrored_output) = self.mirroring.as_ref().filter(|mirrored_output| { - mirrored_output.current_mode().is_some_and(|mirror_mode| { - self.output - .current_mode() - .is_some_and(|mode| mode != mirror_mode) - }) || mirrored_output.current_scale().fractional_scale() - != self.output.current_scale().fractional_scale() - }) { - let mirroring_state = { - let entry = self.mirroring_textures.entry(self.target_node); + // Render offscreen first if postprocessing, or mirroring with different size + let source_output = self + .mirroring + .as_ref() + .filter(|mirrored_output| { + mirrored_output.current_mode().is_some_and(|mirror_mode| { + self.output + .current_mode() + .is_some_and(|mode| mode != mirror_mode) + }) || mirrored_output.current_scale().fractional_scale() + != self.output.current_scale().fractional_scale() + }) + .or(postprocess_shader.as_ref().map(|_| &self.output)); + let mut postproc_states = None; // TODO better way? + let res = if let Some(source_output) = source_output { + let offscreen_state = { + let entry = self.offscreen_textures.entry(self.target_node); let mut new_state = None; if matches!(entry, std::collections::hash_map::Entry::Vacant(_)) { - new_state = Some(MirroringState::new_with_renderer( + new_state = Some(OffscreenState::new_with_renderer( &mut renderer, compositor.format(), - mirrored_output, + source_output, )?); } // I really want a failable initializer... entry.or_insert_with(|| new_state.unwrap()) }; - mirroring_state + offscreen_state .texture .render() .draw::<_, ::Error>(|tex| { - let res = match mirroring_state.damage_tracker.render_output_with( + let res = match offscreen_state.damage_tracker.render_output_with( &mut renderer, tex.clone(), 1, @@ -1083,9 +1111,13 @@ impl SurfaceThreadState { Err(RenderError::OutputNoMode(_)) => unreachable!(), }; + if self.mirroring.is_none() { + postproc_states = Some(res.states); + } + renderer.wait(&res.sync)?; - let transform = mirrored_output.current_transform(); + let transform = source_output.current_transform(); let area = tex.size().to_logical(1, transform); Ok(res @@ -1102,32 +1134,57 @@ impl SurfaceThreadState { let texture_elem = TextureRenderElement::from_texture_render_buffer( (0., 0.), - &mirroring_state.texture, + &offscreen_state.texture, Some(1.0), None, None, Kind::Unspecified, ); + let texture_geometry = texture_elem.geometry(1.0.into()); - elements = constrain_render_elements( - std::iter::once(texture_elem), - (0, 0), - Rectangle::from_size( - self.output - .geometry() - .size - .as_logical() - .to_f64() - .to_physical(self.output.current_scale().fractional_scale()) - .to_i32_round(), - ), - texture_geometry, - ConstrainScaleBehavior::Fit, - ConstrainAlign::CENTER, - 1.0, - ) - .map(CosmicElement::Mirror) - .collect::>(); + elements = if let Some(shader) = &postprocess_shader { + let texture_elem = + TextureShaderElement::new(texture_elem, shader.clone(), Vec::new()); + constrain_render_elements( + std::iter::once(texture_elem), + (0, 0), + Rectangle::from_size( + self.output + .geometry() + .size + .as_logical() + .to_f64() + .to_physical(self.output.current_scale().fractional_scale()) + .to_i32_round(), + ), + texture_geometry, + ConstrainScaleBehavior::Fit, + ConstrainAlign::CENTER, + 1.0, + ) + .map(CosmicElement::Postprocess) + .collect::>() + } else { + constrain_render_elements( + std::iter::once(texture_elem), + (0, 0), + Rectangle::from_size( + self.output + .geometry() + .size + .as_logical() + .to_f64() + .to_physical(self.output.current_scale().fractional_scale()) + .to_i32_round(), + ), + texture_geometry, + ConstrainScaleBehavior::Fit, + ConstrainAlign::CENTER, + 1.0, + ) + .map(CosmicElement::Mirror) + .collect::>() + }; renderer = self.api.single_renderer(&self.target_node).unwrap(); if let Err(err) = compositor.with_compositor(|c| c.use_vrr(vrr)) { @@ -1324,7 +1381,8 @@ impl SurfaceThreadState { } if self.mirroring.is_none() { - let states = frame_result.states; + // If postprocessing, use states from first render + let states = postproc_states.unwrap_or(frame_result.states); self.send_dmabuf_feedback(states); } @@ -1421,7 +1479,16 @@ impl SurfaceThreadState { fn update_mirroring(&mut self, mirroring_output: Option) { self.mirroring = mirroring_output; - self.mirroring_textures.clear(); + self.offscreen_textures.clear(); + } + + fn update_postprocess_shader(&mut self, shader: Option) { + // XXX unwrap + for device in self.api.devices_mut().unwrap() { + update_postprocess_shader(device.renderer_mut().borrow_mut(), shader.as_deref()); + } + self.postprocess_shader = shader; + self.offscreen_textures.clear(); } fn send_frame_callbacks(&mut self) { diff --git a/src/backend/mod.rs b/src/backend/mod.rs index c4f3335f..86601c34 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -66,6 +66,24 @@ pub fn init_backend_auto( .seats .add_seat(initial_seat); + // TODO + if let Some(shader_path) = state + .common + .config + .cosmic_conf + .postprocess_shader_path + .as_ref() + { + match std::fs::read_to_string(shader_path) { + Ok(shader) => { + state.backend.update_postprocess_shader(Some(&shader)); + } + Err(_) => { + tracing::error!("failed to read shader at path: {}", shader_path.display()); + } + } + } + { { state diff --git a/src/backend/render/element.rs b/src/backend/render/element.rs index 87b86225..4e926805 100644 --- a/src/backend/render/element.rs +++ b/src/backend/render/element.rs @@ -8,7 +8,7 @@ use smithay::{ utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement}, Element, Id, Kind, RenderElement, UnderlyingStorage, }, - gles::{GlesError, GlesTexture}, + gles::{element::TextureShaderElement, GlesError, GlesTexture}, glow::{GlowFrame, GlowRenderer}, utils::{CommitCounter, DamageSet, OpaqueRegions}, ImportAll, ImportMem, Renderer, @@ -34,6 +34,9 @@ where RelocateRenderElement>>, >, ), + Postprocess( + CropRenderElement>>, + ), #[cfg(feature = "debug")] Egui(TextureRenderElement), } @@ -52,6 +55,7 @@ where CosmicElement::MoveGrab(elem) => elem.id(), CosmicElement::AdditionalDamage(elem) => elem.id(), CosmicElement::Mirror(elem) => elem.id(), + CosmicElement::Postprocess(elem) => elem.id(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.id(), } @@ -65,6 +69,7 @@ where CosmicElement::MoveGrab(elem) => elem.current_commit(), CosmicElement::AdditionalDamage(elem) => elem.current_commit(), CosmicElement::Mirror(elem) => elem.current_commit(), + CosmicElement::Postprocess(elem) => elem.current_commit(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.current_commit(), } @@ -78,6 +83,7 @@ where CosmicElement::MoveGrab(elem) => elem.src(), CosmicElement::AdditionalDamage(elem) => elem.src(), CosmicElement::Mirror(elem) => elem.src(), + CosmicElement::Postprocess(elem) => elem.src(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.src(), } @@ -91,6 +97,7 @@ where CosmicElement::MoveGrab(elem) => elem.geometry(scale), CosmicElement::AdditionalDamage(elem) => elem.geometry(scale), CosmicElement::Mirror(elem) => elem.geometry(scale), + CosmicElement::Postprocess(elem) => elem.geometry(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.geometry(scale), } @@ -104,6 +111,7 @@ where CosmicElement::MoveGrab(elem) => elem.location(scale), CosmicElement::AdditionalDamage(elem) => elem.location(scale), CosmicElement::Mirror(elem) => elem.location(scale), + CosmicElement::Postprocess(elem) => elem.location(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.location(scale), } @@ -117,6 +125,7 @@ where CosmicElement::MoveGrab(elem) => elem.transform(), CosmicElement::AdditionalDamage(elem) => elem.transform(), CosmicElement::Mirror(elem) => elem.transform(), + CosmicElement::Postprocess(elem) => elem.transform(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.transform(), } @@ -134,6 +143,7 @@ where 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), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.damage_since(scale, commit), } @@ -147,6 +157,7 @@ where 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), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.opaque_regions(scale), } @@ -160,6 +171,7 @@ where CosmicElement::MoveGrab(elem) => elem.alpha(), CosmicElement::AdditionalDamage(elem) => elem.alpha(), CosmicElement::Mirror(elem) => elem.alpha(), + CosmicElement::Postprocess(elem) => elem.alpha(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.alpha(), } @@ -173,6 +185,7 @@ where CosmicElement::MoveGrab(elem) => elem.kind(), CosmicElement::AdditionalDamage(elem) => elem.kind(), CosmicElement::Mirror(elem) => elem.kind(), + CosmicElement::Postprocess(elem) => elem.kind(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.kind(), } @@ -203,35 +216,41 @@ where RenderElement::::draw(elem, frame, src, dst, damage, opaque_regions) } CosmicElement::Mirror(elem) => { - let elem = { - let glow_frame = R::glow_frame_mut(frame); - RenderElement::::draw( - elem, - glow_frame, - src, - dst, - damage, - opaque_regions, - ) - .map_err(FromGlesError::from_gles_error) - }; - elem + let glow_frame = R::glow_frame_mut(frame); + RenderElement::::draw( + elem, + glow_frame, + src, + dst, + damage, + opaque_regions, + ) + .map_err(FromGlesError::from_gles_error) + } + CosmicElement::Postprocess(elem) => { + let glow_frame = R::glow_frame_mut(frame); + RenderElement::::draw( + elem, + glow_frame, + src, + dst, + damage, + opaque_regions, + ) + .map_err(FromGlesError::from_gles_error) } #[cfg(feature = "debug")] CosmicElement::Egui(elem) => { - let elem = { - let glow_frame = R::glow_frame_mut(frame); - RenderElement::::draw( - elem, - glow_frame, - src, - dst, - damage, - opaque_regions, - ) - .map_err(FromGlesError::from_gles_error) - }; - elem + let glow_frame = R::glow_frame_mut(frame); + RenderElement::::draw( + elem, + glow_frame, + src, + dst, + damage, + opaque_regions, + ) + .map_err(FromGlesError::from_gles_error) } } } @@ -245,22 +264,16 @@ where CosmicElement::AdditionalDamage(elem) => elem.underlying_storage(renderer), CosmicElement::Mirror(elem) => { let glow_renderer = renderer.glow_renderer_mut(); - match elem.underlying_storage(glow_renderer) { - Some(UnderlyingStorage::Wayland(buffer)) => { - Some(UnderlyingStorage::Wayland(buffer)) - } - _ => None, - } + elem.underlying_storage(glow_renderer) + } + CosmicElement::Postprocess(elem) => { + let glow_renderer = renderer.glow_renderer_mut(); + elem.underlying_storage(glow_renderer) } #[cfg(feature = "debug")] CosmicElement::Egui(elem) => { let glow_renderer = renderer.glow_renderer_mut(); - match elem.underlying_storage(glow_renderer) { - Some(UnderlyingStorage::Wayland(buffer)) => { - Some(UnderlyingStorage::Wayland(buffer)) - } - _ => None, - } + elem.underlying_storage(glow_renderer) } } } diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index d296020a..10f17509 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -5,7 +5,7 @@ use std::{ cell::RefCell, collections::HashMap, ops::ControlFlow, - sync::{Arc, RwLock, Weak}, + sync::{Arc, Mutex, RwLock, Weak}, time::Instant, }; @@ -46,8 +46,8 @@ use smithay::{ AsRenderElements, Element, Id, Kind, RenderElement, }, gles::{ - element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform, - UniformName, UniformType, + element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, + GlesTexProgram, Uniform, UniformName, UniformType, }, glow::GlowRenderer, multigpu::{Error as MultiError, MultiFrame, MultiRenderer}, @@ -65,6 +65,7 @@ use smithay::{ shm::{shm_format_to_fourcc, with_buffer_contents}, }, }; +use tracing::error; #[cfg(feature = "debug")] use smithay_egui::EguiState; @@ -392,6 +393,30 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> { Ok(()) } +pub struct PostprocessShader(pub Mutex>); + +pub fn update_postprocess_shader(renderer: &mut GlesRenderer, shader_text: Option<&str>) { + let shader = if let Some(shader_text) = shader_text { + match renderer.compile_custom_texture_shader(shader_text, &[]) { + Ok(shader) => Some(shader), + Err(err) => { + error!("failed to compile postprocess shader: {}", err); + None + } + } + } else { + None + }; + + let egl_context = renderer.egl_context(); + *egl_context + .user_data() + .get_or_insert(|| PostprocessShader(Mutex::new(None))) + .0 + .lock() + .unwrap() = shader; +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CursorMode { None, diff --git a/src/backend/winit.rs b/src/backend/winit.rs index f293341c..6ebffb2d 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -34,7 +34,7 @@ use smithay::{ use std::{borrow::BorrowMut, cell::RefCell, time::Duration}; use tracing::{error, info, warn}; -use super::render::{init_shaders, CursorMode}; +use super::render::{init_shaders, update_postprocess_shader, CursorMode}; #[derive(Debug)] pub struct WinitState { @@ -125,6 +125,10 @@ impl WinitState { Ok(vec![self.output.clone()]) } } + + pub fn update_postprocess_shader(&mut self, shader: Option<&str>) { + update_postprocess_shader(self.backend.renderer().borrow_mut(), shader) + } } pub fn init_backend( diff --git a/src/backend/x11.rs b/src/backend/x11.rs index a18bcaf5..4651e419 100644 --- a/src/backend/x11.rs +++ b/src/backend/x11.rs @@ -41,7 +41,7 @@ use smithay::{ use std::{borrow::BorrowMut, cell::RefCell, os::unix::io::OwnedFd, time::Duration}; use tracing::{debug, error, info, warn}; -use super::render::init_shaders; +use super::render::{init_shaders, update_postprocess_shader}; #[derive(Debug)] enum Allocator { @@ -187,6 +187,10 @@ impl X11State { Ok(vec![surface.output.clone()]) } } + + pub fn update_postprocess_shader(&mut self, shader: Option<&str>) { + update_postprocess_shader(self.renderer.borrow_mut(), shader) + } } #[derive(Debug)] diff --git a/src/config/mod.rs b/src/config/mod.rs index bfd4e73f..e06a41ae 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -756,6 +756,22 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut state.common.config.cosmic_conf.focus_follows_cursor_delay = new; } } + "postprocess_shader_path" => { + let new = get_config::>(&config, "postprocess_shader_path"); + if new != state.common.config.cosmic_conf.postprocess_shader_path { + let shader = + new.as_ref() + .and_then(|path| match std::fs::read_to_string(path) { + Ok(shader) => Some(shader), + Err(_) => { + error!("failed to read shader at path: {}", path.display()); + None + } + }); + state.backend.update_postprocess_shader(shader.as_deref()); + state.common.config.cosmic_conf.postprocess_shader_path = new; + } + } _ => {} } } diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index e3da4d5e..65a2845c 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -1373,12 +1373,7 @@ where #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_renderer = renderer.glow_renderer_mut(); - match elem.underlying_storage(glow_renderer) { - Some(UnderlyingStorage::Wayland(buffer)) => { - Some(UnderlyingStorage::Wayland(buffer)) - } - _ => None, - } + elem.underlying_storage(glow_renderer) } } } diff --git a/src/state.rs b/src/state.rs index c64ce05f..d115877d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -441,6 +441,16 @@ impl BackendData { _ => unreachable!("No backend set when getting offscreen renderer"), } } + + /// Set the GLES texture shader used for postprocessing + pub fn update_postprocess_shader(&mut self, shader: Option<&str>) { + match self { + BackendData::Kms(kms) => kms.update_postprocess_shader(shader), + BackendData::Winit(winit) => winit.update_postprocess_shader(shader), + BackendData::X11(x11) => x11.update_postprocess_shader(shader), + _ => unreachable!("No backend was initialized"), + } + } } pub struct KmsNodes {