diff --git a/Cargo.lock b/Cargo.lock index 66cffb298..3a80c1106 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -896,6 +896,7 @@ dependencies = [ "sendfd", "serde", "serde_json", + "smallvec", "smithay", "smithay-egui", "thiserror 2.0.18", @@ -5102,7 +5103,7 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay" version = "0.7.0" -source = "git+https://github.com/smithay/smithay.git?rev=da42569#da42569e7a0e1669acb1e15d96cbb500a27cb266" +source = "git+https://github.com/smithay/smithay.git?rev=f6d1070#f6d10709db2bb68c46b9c128a4163d035356572c" dependencies = [ "aliasable", "appendlist", diff --git a/Cargo.toml b/Cargo.toml index 0a35babed..c6dcfab56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,6 +89,7 @@ logind-zbus = { version = "5.3.2", optional = true } futures-executor = { version = "0.3.32", features = ["thread-pool"] } futures-util = "0.3.32" cgmath = "0.18.0" +smallvec = "1.15.1" [dependencies.id_tree] branch = "feature/copy_clone" @@ -148,4 +149,4 @@ cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch cosmic-client-toolkit = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" } [patch.crates-io] -smithay = { git = "https://github.com/smithay/smithay.git", rev = "da42569" } +smithay = { git = "https://github.com/smithay/smithay.git", rev = "f6d1070" } diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 6063d4764..2c36658a6 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -54,6 +54,7 @@ pub struct AppearanceConfig { pub clip_floating_windows: bool, pub clip_tiled_windows: bool, pub shadow_tiled_windows: bool, + pub blur_strength: u8, } impl Default for AppearanceConfig { @@ -62,6 +63,7 @@ impl Default for AppearanceConfig { clip_floating_windows: true, clip_tiled_windows: true, shadow_tiled_windows: false, + blur_strength: 9, } } } diff --git a/src/backend/kms/render/gles.rs b/src/backend/kms/render/gles.rs index 5d79b1eef..a68269a86 100644 --- a/src/backend/kms/render/gles.rs +++ b/src/backend/kms/render/gles.rs @@ -9,10 +9,9 @@ use smithay::backend::{ }, drm::{CreateDrmNodeError, DrmNode}, renderer::{ - RendererSuper, gles::{GlesError, GlesRenderer}, glow::GlowRenderer, - multigpu::{ApiDevice, Error as MultiError, GraphicsApi}, + multigpu::{ApiDevice, GraphicsApi}, }, }; use std::{borrow::Borrow, cell::Cell}; @@ -23,8 +22,6 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; -use crate::backend::render::element::FromGlesError; - /// Errors raised by the [`GbmGlesBackend`] #[derive(Debug, thiserror::Error)] pub enum Error { @@ -181,14 +178,3 @@ impl ApiDevice for GbmGlowDevice { !Borrow::::borrow(&self.renderer).is_software() } } - -impl FromGlesError for MultiError, T> -where - T::Error: 'static, - <::Renderer as RendererSuper>::Error: 'static, -{ - #[inline] - fn from_gles_error(err: GlesError) -> MultiError, T> { - MultiError::Render(err) - } -} diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 76426c5ec..c219e1473 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -1,6 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::{utils::prelude::*, wayland::handlers::compositor::FRAME_TIME_FILTER}; +use crate::{ + backend::render::{ + element::AsGlowRenderer, + wayland::{SurfaceRenderElement, push_render_elements_from_surface_tree}, + }, + utils::prelude::*, + wayland::handlers::compositor::FRAME_TIME_FILTER, +}; use smithay::{ backend::{ allocator::Fourcc, @@ -9,10 +16,10 @@ use smithay::{ element::{ Kind, memory::{MemoryRenderBuffer, MemoryRenderBufferRenderElement}, - surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree}, }, }, }, + desktop::utils::bbox_from_surface_tree, input::{ Seat, pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus}, @@ -118,9 +125,9 @@ fn load_icon(theme: &CursorTheme, shape: CursorIcon) -> Result, Error } render_elements! { - pub CursorRenderElement where R: ImportAll + ImportMem; + pub CursorRenderElement where R: ImportAll + ImportMem + AsGlowRenderer; Static=MemoryRenderBufferRenderElement, - Surface=WaylandSurfaceRenderElement, + Surface=SurfaceRenderElement, } pub fn draw_surface_cursor( @@ -128,9 +135,10 @@ pub fn draw_surface_cursor( surface: &wl_surface::WlSurface, location: Point, scale: impl Into>, -) -> Vec<(CursorRenderElement, Point)> -where - R: Renderer + ImportAll, + blur_strength: usize, + push: &mut dyn FnMut(CursorRenderElement, Point), +) where + R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, { let scale = scale.into(); @@ -145,17 +153,20 @@ where .to_physical_precise_round(scale) }); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface, location.to_physical(scale).to_i32_round(), + bbox_from_surface_tree(surface, location.to_i32_round()).to_f64(), scale, 1.0, + false, + [0; 4], + blur_strength, Kind::Cursor, - ) - .into_iter() - .map(|elem| (elem, h)) - .collect() + &mut |elem| push(elem.into(), h), + None, + ); } #[profiling::function] @@ -164,9 +175,10 @@ pub fn draw_dnd_icon( surface: &wl_surface::WlSurface, location: Point, scale: impl Into>, -) -> Vec> -where - R: Renderer + ImportAll, + blur_strength: usize, + push: &mut dyn FnMut(SurfaceRenderElement), +) where + R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, { if get_role(surface) != Some("dnd_icon") { @@ -176,14 +188,20 @@ where ); } let scale = scale.into(); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface, location.to_physical(scale).to_i32_round(), + bbox_from_surface_tree(surface, location.to_i32_round()).to_f64(), scale, 1.0, + false, + [0; 4], + blur_strength, FRAME_TIME_FILTER, - ) + push, + None, + ); } pub type CursorState = Mutex; @@ -258,10 +276,11 @@ pub fn draw_cursor( scale: Scale, buffer_scale: f64, time: Time, + blur_strength: usize, draw_default: bool, -) -> Vec<(CursorRenderElement, Point)> -where - R: Renderer + ImportMem + ImportAll, + push: &mut dyn FnMut(CursorRenderElement, Point), +) where + R: Renderer + ImportMem + ImportAll + AsGlowRenderer, R::TextureId: Send + Clone + 'static, { // draw the cursor as relevant @@ -277,7 +296,7 @@ where }); if let Some(current_cursor) = named_cursor { if !draw_default && current_cursor == CursorIcon::Default { - return Vec::new(); + return; } let integer_scale = (scale.x.max(scale.y) * buffer_scale).ceil() as u32; @@ -314,7 +333,7 @@ where ); state.current_image = Some(frame); - return vec![( + push( CursorRenderElement::Static( MemoryRenderBufferRenderElement::from_buffer( renderer, @@ -328,10 +347,8 @@ where .expect("Failed to import cursor bitmap"), ), hotspot.to_physical_precise_round(scale), - )]; + ); } else if let CursorImageStatus::Surface(ref wl_surface) = cursor_status { - return draw_surface_cursor(renderer, wl_surface, location, scale); - } else { - Vec::new() + draw_surface_cursor(renderer, wl_surface, location, scale, blur_strength, push); } } diff --git a/src/backend/render/element.rs b/src/backend/render/element.rs index 7897da65d..3a961444e 100644 --- a/src/backend/render/element.rs +++ b/src/backend/render/element.rs @@ -1,4 +1,7 @@ -use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement}; +use crate::{ + backend::render::{GlMultiError, wayland::SurfaceRenderElement}, + shell::{CosmicMappedRenderElement, WorkspaceRenderElement}, +}; #[cfg(feature = "debug")] use smithay::backend::renderer::{element::texture::TextureRenderElement, gles::GlesTexture}; @@ -8,14 +11,15 @@ use smithay::{ element::{ Element, Id, Kind, RenderElement, UnderlyingStorage, memory::MemoryRenderBufferRenderElement, - surface::WaylandSurfaceRenderElement, utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement}, }, gles::{GlesError, element::TextureShaderElement}, glow::{GlowFrame, GlowRenderer}, utils::{CommitCounter, DamageSet, OpaqueRegions}, }, - utils::{Buffer as BufferCoords, Logical, Physical, Point, Rectangle, Scale}, + utils::{ + Buffer as BufferCoords, Logical, Physical, Point, Rectangle, Scale, user_data::UserDataMap, + }, }; use super::{GlMultiRenderer, cursor::CursorRenderElement}; @@ -30,12 +34,13 @@ where RelocateRenderElement>>>, ), Cursor(RescaleRenderElement>>), - Dnd(WaylandSurfaceRenderElement), + Dnd(SurfaceRenderElement), MoveGrab(RescaleRenderElement>), Postprocess( CropRenderElement>>, ), Zoom(MemoryRenderBufferRenderElement), + Damage(DamageElement), #[cfg(feature = "debug")] Egui(TextureRenderElement), } @@ -54,6 +59,7 @@ where CosmicElement::MoveGrab(elem) => elem.id(), CosmicElement::Postprocess(elem) => elem.id(), CosmicElement::Zoom(elem) => elem.id(), + CosmicElement::Damage(elem) => elem.id(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.id(), } @@ -67,6 +73,7 @@ where CosmicElement::MoveGrab(elem) => elem.current_commit(), CosmicElement::Postprocess(elem) => elem.current_commit(), CosmicElement::Zoom(elem) => elem.current_commit(), + CosmicElement::Damage(elem) => elem.current_commit(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.current_commit(), } @@ -80,6 +87,7 @@ where CosmicElement::MoveGrab(elem) => elem.src(), CosmicElement::Postprocess(elem) => elem.src(), CosmicElement::Zoom(elem) => elem.src(), + CosmicElement::Damage(elem) => elem.src(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.src(), } @@ -93,6 +101,7 @@ where CosmicElement::MoveGrab(elem) => elem.geometry(scale), CosmicElement::Postprocess(elem) => elem.geometry(scale), CosmicElement::Zoom(elem) => elem.geometry(scale), + CosmicElement::Damage(elem) => elem.geometry(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.geometry(scale), } @@ -106,6 +115,7 @@ where CosmicElement::MoveGrab(elem) => elem.location(scale), CosmicElement::Postprocess(elem) => elem.location(scale), CosmicElement::Zoom(elem) => elem.location(scale), + CosmicElement::Damage(elem) => elem.location(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.location(scale), } @@ -119,6 +129,7 @@ where CosmicElement::MoveGrab(elem) => elem.transform(), CosmicElement::Postprocess(elem) => elem.transform(), CosmicElement::Zoom(elem) => elem.transform(), + CosmicElement::Damage(elem) => elem.transform(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.transform(), } @@ -136,6 +147,7 @@ where CosmicElement::MoveGrab(elem) => elem.damage_since(scale, commit), CosmicElement::Postprocess(elem) => elem.damage_since(scale, commit), CosmicElement::Zoom(elem) => elem.damage_since(scale, commit), + CosmicElement::Damage(elem) => elem.damage_since(scale, commit), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.damage_since(scale, commit), } @@ -149,6 +161,7 @@ where CosmicElement::MoveGrab(elem) => elem.opaque_regions(scale), CosmicElement::Postprocess(elem) => elem.opaque_regions(scale), CosmicElement::Zoom(elem) => elem.opaque_regions(scale), + CosmicElement::Damage(elem) => elem.opaque_regions(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.opaque_regions(scale), } @@ -162,6 +175,7 @@ where CosmicElement::MoveGrab(elem) => elem.alpha(), CosmicElement::Postprocess(elem) => elem.alpha(), CosmicElement::Zoom(elem) => elem.alpha(), + CosmicElement::Damage(elem) => elem.alpha(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.alpha(), } @@ -175,17 +189,31 @@ where CosmicElement::MoveGrab(elem) => elem.kind(), CosmicElement::Postprocess(elem) => elem.kind(), CosmicElement::Zoom(elem) => elem.kind(), + CosmicElement::Damage(elem) => elem.kind(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.kind(), } } + + fn is_framebuffer_effect(&self) -> bool { + match self { + CosmicElement::Workspace(elem) => elem.is_framebuffer_effect(), + CosmicElement::Cursor(elem) => elem.is_framebuffer_effect(), + CosmicElement::Dnd(elem) => elem.is_framebuffer_effect(), + CosmicElement::MoveGrab(elem) => elem.is_framebuffer_effect(), + CosmicElement::Postprocess(elem) => elem.is_framebuffer_effect(), + CosmicElement::Zoom(elem) => elem.is_framebuffer_effect(), + CosmicElement::Damage(elem) => elem.is_framebuffer_effect(), + #[cfg(feature = "debug")] + CosmicElement::Egui(elem) => elem.is_framebuffer_effect(), + } + } } impl RenderElement for CosmicElement where R: AsGlowRenderer + Renderer + ImportAll + ImportMem, R::TextureId: 'static, - R::Error: FromGlesError, CosmicMappedRenderElement: RenderElement, { fn draw( @@ -195,12 +223,19 @@ where dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + cache: Option<&UserDataMap>, ) -> Result<(), R::Error> { match self { - CosmicElement::Workspace(elem) => elem.draw(frame, src, dst, damage, opaque_regions), - CosmicElement::Cursor(elem) => elem.draw(frame, src, dst, damage, opaque_regions), - CosmicElement::Dnd(elem) => elem.draw(frame, src, dst, damage, opaque_regions), - CosmicElement::MoveGrab(elem) => elem.draw(frame, src, dst, damage, opaque_regions), + CosmicElement::Workspace(elem) => { + elem.draw(frame, src, dst, damage, opaque_regions, cache) + } + CosmicElement::Cursor(elem) => { + elem.draw(frame, src, dst, damage, opaque_regions, cache) + } + CosmicElement::Dnd(elem) => elem.draw(frame, src, dst, damage, opaque_regions, cache), + CosmicElement::MoveGrab(elem) => { + elem.draw(frame, src, dst, damage, opaque_regions, cache) + } CosmicElement::Postprocess(elem) => { let glow_frame = R::glow_frame_mut(frame); RenderElement::::draw( @@ -210,10 +245,14 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error) + .map_err(R::from_gles_error) + } + CosmicElement::Zoom(elem) => elem.draw(frame, src, dst, damage, opaque_regions, cache), + CosmicElement::Damage(elem) => { + RenderElement::::draw(elem, frame, src, dst, damage, opaque_regions, cache) } - CosmicElement::Zoom(elem) => elem.draw(frame, src, dst, damage, opaque_regions), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => { let glow_frame = R::glow_frame_mut(frame); @@ -224,8 +263,9 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error) + .map_err(R::from_gles_error) } } } @@ -241,6 +281,7 @@ where elem.underlying_storage(glow_renderer) } CosmicElement::Zoom(elem) => elem.underlying_storage(renderer), + CosmicElement::Damage(elem) => elem.underlying_storage(renderer), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => { let glow_renderer = renderer.glow_renderer_mut(); @@ -248,6 +289,40 @@ where } } } + + fn capture_framebuffer( + &self, + frame: &mut ::Frame<'_, '_>, + src: Rectangle, + dst: Rectangle, + cache: &UserDataMap, + ) -> Result<(), ::Error> { + match self { + CosmicElement::Workspace(elem) => elem.capture_framebuffer(frame, src, dst, cache), + CosmicElement::Cursor(elem) => elem.capture_framebuffer(frame, src, dst, cache), + CosmicElement::Dnd(elem) => elem.capture_framebuffer(frame, src, dst, cache), + CosmicElement::MoveGrab(elem) => elem.capture_framebuffer(frame, src, dst, cache), + CosmicElement::Postprocess(elem) => { + let glow_frame = R::glow_frame_mut(frame); + RenderElement::::capture_framebuffer( + elem, glow_frame, src, dst, cache, + ) + .map_err(R::from_gles_error) + } + CosmicElement::Zoom(elem) => elem.capture_framebuffer(frame, src, dst, cache), + CosmicElement::Damage(elem) => { + RenderElement::::capture_framebuffer(elem, frame, src, dst, cache) + } + #[cfg(feature = "debug")] + CosmicElement::Egui(elem) => { + let glow_frame = R::glow_frame_mut(frame); + RenderElement::::capture_framebuffer( + elem, glow_frame, src, dst, cache, + ) + .map_err(R::from_gles_error) + } + } + } } impl From>>> @@ -277,6 +352,17 @@ where } } +impl From for CosmicElement +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + R::TextureId: 'static, + CosmicMappedRenderElement: RenderElement, +{ + fn from(value: DamageElement) -> Self { + Self::Damage(value) + } +} + #[cfg(feature = "debug")] impl From> for CosmicElement where @@ -301,6 +387,7 @@ where fn glow_frame_mut<'a, 'frame, 'buffer>( frame: &'a mut Self::Frame<'frame, 'buffer>, ) -> &'a mut GlowFrame<'frame, 'buffer>; + fn from_gles_error(err: GlesError) -> Self::Error; } impl AsGlowRenderer for GlowRenderer { @@ -320,6 +407,9 @@ impl AsGlowRenderer for GlowRenderer { ) -> &'a mut GlowFrame<'frame, 'buffer> { frame } + fn from_gles_error(err: GlesError) -> Self::Error { + err + } } impl AsGlowRenderer for GlMultiRenderer<'_> { @@ -339,6 +429,9 @@ impl AsGlowRenderer for GlMultiRenderer<'_> { ) -> &'b mut GlowFrame<'frame, 'buffer> { frame.as_mut() } + fn from_gles_error(err: GlesError) -> Self::Error { + GlMultiError::Render(err) + } } pub struct DamageElement { @@ -389,17 +482,8 @@ impl RenderElement for DamageElement { _dst: Rectangle, _damage: &[Rectangle], _opaque_regions: &[Rectangle], + _cache: Option<&UserDataMap>, ) -> Result<(), R::Error> { Ok(()) } } - -pub trait FromGlesError { - fn from_gles_error(err: GlesError) -> Self; -} - -impl FromGlesError for GlesError { - fn from_gles_error(err: GlesError) -> Self { - err - } -} diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 0e22c8ea9..fb6af1a95 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -15,9 +15,14 @@ use crate::{ backend::{ kms::render::gles::GbmGlowBackend, render::{ - clipped_surface::{CLIPPING_SHADER, ClippingShader}, element::DamageElement, shadow::{SHADOW_SHADER, ShadowShader}, + wayland::{ + SurfaceRenderElement, + blur_effect::BlurShaders, + clipped_surface::{CLIPPING_SHADER, ClippingShader}, + push_render_elements_from_surface_tree, + }, }, }, config::ScreenFilter, @@ -42,7 +47,6 @@ use crate::{ }; use cosmic::Theme; -use element::FromGlesError; use smithay::{ backend::{ allocator::{Fourcc, dmabuf::Dmabuf}, @@ -52,8 +56,7 @@ use smithay::{ TextureFilter, damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult}, element::{ - Element, Id, Kind, RenderElement, WeakId, - surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree}, + Element, Id, Kind, NamespacedElement, RenderElement, WeakId, texture::{TextureRenderBuffer, TextureRenderElement}, utils::{ ConstrainAlign, ConstrainScaleBehavior, CropRenderElement, Relocate, @@ -70,6 +73,7 @@ use smithay::{ sync::SyncPoint, }, }, + desktop::utils::bbox_from_surface_tree, input::Seat, output::{Output, OutputModeSource, OutputNoMode}, utils::{ @@ -82,10 +86,10 @@ use smithay::{ use smithay_egui::EguiState; pub mod animations; -pub mod clipped_surface; pub mod cursor; pub mod element; pub mod shadow; +pub mod wayland; use self::element::{AsGlowRenderer, CosmicElement}; use super::kms::Timings; @@ -423,6 +427,7 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> { UniformName::new("geo_size", UniformType::_2f), UniformName::new("corner_radius", UniformType::_4f), UniformName::new("input_to_geo", UniformType::Matrix3x3), + UniformName::new("noise", UniformType::_1f), ], )?; let shadow_shader = renderer.compile_custom_pixel_shader( @@ -438,6 +443,7 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> { UniformName::new("window_corner_radius", UniformType::_4f), ], )?; + let blur_shaders = BlurShaders::compile(renderer)?; let egl_context = renderer.egl_context(); egl_context @@ -455,6 +461,7 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> { egl_context .user_data() .insert_if_missing(|| ShadowShader(shadow_shader)); + egl_context.user_data().insert_if_missing(|| blur_shaders); Ok(()) } @@ -472,12 +479,13 @@ pub fn cursor_elements<'a, 'frame, R>( seats: impl Iterator>, zoom_state: Option<&ZoomState>, theme: &Theme, + blur_strength: usize, now: Time, output: &Output, mode: CursorMode, exclude_dnd_icon: bool, -) -> Vec> -where + push: &mut dyn FnMut(CosmicElement), +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -491,7 +499,6 @@ where ) }) .unwrap_or_else(|| ((0., 0.).into(), 1.)); - let mut elements = Vec::new(); for seat in seats { let pointer = match seat.get_pointer() { @@ -501,19 +508,17 @@ where let location = pointer.current_location() - output.current_location().to_f64(); if mode != CursorMode::None { - elements.extend( - cursor::draw_cursor( - renderer, - seat, - location, - scale.into(), - zoom_scale, - now, - mode != CursorMode::NotDefault, - ) - .into_iter() - .map(|(elem, hotspot)| { - CosmicElement::Cursor(RescaleRenderElement::from_element( + cursor::draw_cursor( + renderer, + seat, + location, + scale.into(), + zoom_scale, + now, + blur_strength, + mode != CursorMode::NotDefault, + &mut |elem, hotspot| { + push(CosmicElement::Cursor(RescaleRenderElement::from_element( RelocateRenderElement::from_element( elem, Point::from((-hotspot.x, -hotspot.y)), @@ -524,65 +529,57 @@ where .to_physical(output.current_scale().fractional_scale()) .to_i32_round(), zoom_scale, - )) - }), + ))) + }, ); } if !exclude_dnd_icon { if let Some(dnd_icon) = get_dnd_icon(seat) { - elements.extend( - cursor::draw_dnd_icon( - renderer, - &dnd_icon.surface, - (location + dnd_icon.offset.to_f64()).to_i32_round(), - scale, - ) - .into_iter() - .map(CosmicElement::Dnd), + cursor::draw_dnd_icon( + renderer, + &dnd_icon.surface, + (location + dnd_icon.offset.to_f64()).to_i32_round(), + scale, + blur_strength, + &mut |elem| push(CosmicElement::Dnd(elem)), ); } } let theme = theme.cosmic(); - if let Some(grab_elements) = seat + if let Some(grab_state) = seat .user_data() .get::() .unwrap() .lock() .unwrap() .as_ref() - .map(|state| state.render::, R>(renderer, output, theme)) { - elements.extend(grab_elements.into_iter().map(|elem| { - CosmicElement::MoveGrab(RescaleRenderElement::from_element( + grab_state.render(renderer, output, theme, &mut |elem| { + push(CosmicElement::MoveGrab(RescaleRenderElement::from_element( elem, focal_point .as_logical() .to_physical(output.current_scale().fractional_scale()) .to_i32_round(), zoom_scale, - )) - })); + ))); + }) } - if let Some((grab_elements, should_scale)) = seat + if let Some(grab_state) = seat .user_data() .get::() .unwrap() .lock() .unwrap() .as_ref() - .map(|state| { - ( - state.render::, R>(renderer, output), - !state.is_in_screen_space(), - ) - }) { - elements.extend(grab_elements.into_iter().map(|elem| { - CosmicElement::MoveGrab(RescaleRenderElement::from_element( - elem, + let should_scale = !grab_state.is_in_screen_space(); + grab_state.render(renderer, output, &mut |elem| { + push(CosmicElement::MoveGrab(RescaleRenderElement::from_element( + elem.into(), if should_scale { focal_point .as_logical() @@ -592,12 +589,10 @@ where Point::from((0, 0)) }, if should_scale { zoom_scale } else { 1.0 }, - )) - })); + ))); + }) } } - - elements } #[cfg(not(feature = "debug"))] @@ -622,7 +617,6 @@ pub fn output_elements( where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - R::Error: FromGlesError, CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { @@ -649,7 +643,7 @@ where ), scale, ) - .map_err(FromGlesError::from_gles_error) + .map_err(R::from_gles_error) .map_err(RenderError::Rendering)? .into(), ] @@ -720,11 +714,10 @@ pub fn workspace_elements( where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - R::Error: FromGlesError, CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = Vec::new(); + let mut elements = Vec::>::new(); let shell_ref = shell.read(); let seats = shell_ref.seats.iter().cloned().collect::>(); @@ -732,21 +725,24 @@ where return Ok(Vec::new()); } let theme = shell_ref.theme().clone(); + let blur_strength = shell_ref.appearance_config().blur_strength as usize; let scale = output.current_scale().fractional_scale(); // we don't want to hold a shell lock across `cursor_elements`, // that is prone to deadlock with the main-thread on some grabs. std::mem::drop(shell_ref); - elements.extend(cursor_elements( + cursor_elements( renderer, seats.iter(), zoom_level, &theme, + blur_strength, now, output, cursor_mode, element_filter == ElementFilter::ExcludeWorkspaceOverview, - )); + &mut |elem| elements.push(elem.into()), + ); let shell = shell.read(); let overview = shell.overview_mode(); @@ -822,72 +818,101 @@ where render_input_order::<()>(&shell, output, previous, current, element_filter, |stage| { match stage { Stage::ZoomUI => { - elements.extend(ZoomState::render(renderer, output)); + ZoomState::render(renderer, output, &mut |elem| { + elements.push(CosmicElement::Zoom(elem)) + }); } Stage::SessionLock(lock_surface) => { - elements.extend( - session_lock_elements(renderer, output, lock_surface) - .into_iter() - .map(Into::into) - .flat_map(crop_to_output) - .map(Into::into), - ); + session_lock_elements(renderer, output, lock_surface, &mut |elem| { + elements.extend(crop_to_output(elem.into()).map(Into::into)) + }) } Stage::LayerPopup { - popup, location, .. + popup, + location, + workspace_idx, + .. } => { - elements.extend( - render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( - renderer, - popup.wl_surface(), - location - .to_local(output) - .as_logical() - .to_physical_precise_round(scale), - Scale::from(scale), - 1.0, - FRAME_TIME_FILTER, - ) - .into_iter() - .flat_map(crop_to_output) - .map(Into::into), - ); + let mut geometry = popup.geometry().as_global(); + geometry.loc += location; + + push_render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + location + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + geometry.to_local(output).as_logical().to_f64(), + Scale::from(scale), + 1.0, + false, + [0; 4], + blur_strength, + FRAME_TIME_FILTER, + &mut |elem| { + elements.extend( + crop_to_output(NamespacedElement::new(elem, workspace_idx).into()) + .map(Into::into), + ) + }, + None, + ) } - Stage::LayerSurface { layer, location } => { - elements.extend( - render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( - renderer, - layer.wl_surface(), - location - .to_local(output) - .as_logical() - .to_physical_precise_round(scale), - Scale::from(scale), - 1.0, - FRAME_TIME_FILTER, - ) - .into_iter() - .flat_map(crop_to_output) - .map(Into::into), + Stage::LayerSurface { + layer, + location, + workspace_idx, + } => { + let mut geometry = layer.geometry().as_global(); + geometry.loc += location; + + push_render_elements_from_surface_tree( + renderer, + layer.wl_surface(), + location + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + geometry.to_local(output).as_logical().to_f64(), + Scale::from(scale), + 1.0, + false, + [0; 4], + blur_strength, + FRAME_TIME_FILTER, + &mut |elem| { + elements.extend( + crop_to_output(NamespacedElement::new(elem, workspace_idx).into()) + .map(Into::into), + ) + }, + None, ); } Stage::OverrideRedirect { surface, location } => { - elements.extend(surface.wl_surface().into_iter().flat_map(|surface| { - render_elements_from_surface_tree::<_, WorkspaceRenderElement<_>>( + if let Some(wl_surface) = surface.wl_surface() { + let mut geometry = surface.geometry().as_global(); + geometry.loc += location; + + push_render_elements_from_surface_tree( renderer, - &surface, + &wl_surface, location .to_local(output) .as_logical() .to_physical_precise_round(scale), + geometry.to_local(output).as_logical().to_f64(), Scale::from(scale), 1.0, + false, + [0; 4], + blur_strength, FRAME_TIME_FILTER, - ) - .into_iter() - .flat_map(crop_to_output) - .map(Into::into) - })); + &mut |elem| elements.extend(crop_to_output(elem.into()).map(Into::into)), + None, + ); + } } Stage::StickyPopups(layout) => { let alpha = match &overview.0 { @@ -908,14 +933,11 @@ where OverviewMode::None => 1.0, }; - elements.extend( - layout - .render_popups(renderer, alpha) - .into_iter() - .map(Into::into) - .flat_map(crop_to_output) - .map(Into::into), - ); + layout.render_popups(renderer, alpha, &mut |elem| { + if let Some(elem) = crop_to_output(elem.into()) { + elements.push(elem.into()) + } + }); } Stage::Sticky(layout) => { let alpha = match &overview.0 { @@ -940,79 +962,63 @@ where .then_some(last_active_seat) .map(|seat| workspace.focus_stack.get(seat)); - elements.extend( - layout - .render( - renderer, - current_focus.as_ref().and_then(|stack| { - stack.last().and_then(|t| match t { - FocusTarget::Window(w) => Some(w), - _ => None, - }) - }), - resize_indicator.clone(), - active_hint, - alpha, - theme.cosmic(), - ) - .into_iter() - .map(Into::into) - .flat_map(crop_to_output) - .map(Into::into), - ) + layout.render( + renderer, + current_focus.as_ref().and_then(|stack| { + stack.last().and_then(|t| match t { + FocusTarget::Window(w) => Some(w), + _ => None, + }) + }), + resize_indicator.clone(), + active_hint, + alpha, + theme.cosmic(), + &mut |elem| { + if let Some(elem) = crop_to_output(elem.into()) { + elements.push(elem.into()) + } + }, + ); } Stage::WorkspacePopups { workspace, offset } => { - elements.extend( - match workspace.render_popups( - renderer, - last_active_seat, - !move_active && is_active_space, - overview.clone(), - theme.cosmic(), - ) { - Ok(elements) => { - elements - .into_iter() - .flat_map(crop_to_output) - .map(|element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - element, - offset.to_physical_precise_round(scale), - Relocate::Relative, - )) - }) - } - Err(_) => { - return ControlFlow::Break(Err(OutputNoMode)); + workspace.render_popups( + renderer, + last_active_seat, + !move_active && is_active_space, + overview.clone(), + theme.cosmic(), + &mut |elem| { + if let Some(elem) = crop_to_output(elem) { + elements.push(CosmicElement::Workspace( + RelocateRenderElement::from_element( + elem, + offset.to_physical_precise_round(scale), + Relocate::Relative, + ), + )); } }, ); } Stage::Workspace { workspace, offset } => { - elements.extend( - match workspace.render( - renderer, - last_active_seat, - !move_active && is_active_space, - overview.clone(), - resize_indicator.clone(), - active_hint, - theme.cosmic(), - ) { - Ok(elements) => { - elements - .into_iter() - .flat_map(crop_to_output) - .map(|element| { - CosmicElement::Workspace(RelocateRenderElement::from_element( - element, - offset.to_physical_precise_round(scale), - Relocate::Relative, - )) - }) - } - Err(_) => { - return ControlFlow::Break(Err(OutputNoMode)); + workspace.render( + renderer, + last_active_seat, + !move_active && is_active_space, + overview.clone(), + resize_indicator.clone(), + active_hint, + theme.cosmic(), + &mut |elem| { + if let Some(elem) = crop_to_output(elem) { + elements.push(CosmicElement::Workspace( + RelocateRenderElement::from_element( + elem, + offset.to_physical_precise_round(scale), + Relocate::Relative, + ), + )); } }, ); @@ -1029,23 +1035,27 @@ fn session_lock_elements( renderer: &mut R, output: &Output, lock_surface: Option<&LockSurface>, -) -> Vec> -where - R: Renderer + ImportAll, + push: &mut dyn FnMut(SurfaceRenderElement), +) where + R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, { if let Some(surface) = lock_surface { let scale = Scale::from(output.current_scale().fractional_scale()); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface.wl_surface(), (0, 0), + bbox_from_surface_tree(surface.wl_surface(), (0, 0)).to_f64(), scale, 1.0, + false, + [0; 4], + 0, FRAME_TIME_FILTER, + push, + None, ) - } else { - Vec::new() } } @@ -1202,7 +1212,6 @@ where + Blit + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - R::Error: FromGlesError, CosmicElement: RenderElement, CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, @@ -1507,12 +1516,23 @@ pub fn render_workspace<'d, R>( where R: Renderer + ImportAll + ImportMem + ExportMem + Bind + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - R::Error: FromGlesError, CosmicElement: RenderElement, CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let elements: Vec> = workspace_elements( + let mut elements: Vec> = if let Some(additional_damage) = additional_damage { + let output_geo = output.geometry().to_local(output).as_logical(); + additional_damage + .into_iter() + .filter_map(|rect| rect.intersection(output_geo)) + .map(DamageElement::new) + .map(CosmicElement::from) + .collect() + } else { + Vec::new() + }; + + elements.extend(workspace_elements( gpu, renderer, shell, @@ -1523,17 +1543,7 @@ where current, cursor_mode, element_filter, - )?; - - if let Some(additional_damage) = additional_damage { - let output_geo = output.geometry().to_local(output).as_logical(); - let additional_damage_elements: Vec<_> = additional_damage - .into_iter() - .filter_map(|rect| rect.intersection(output_geo)) - .map(DamageElement::new) - .collect(); - damage_tracker.damage_output(age, &additional_damage_elements)?; - } + )?); let res = damage_tracker.render_output( renderer, diff --git a/src/backend/render/shaders/blur_downsample.frag b/src/backend/render/shaders/blur_downsample.frag new file mode 100644 index 000000000..1fa24beb8 --- /dev/null +++ b/src/backend/render/shaders/blur_downsample.frag @@ -0,0 +1,26 @@ +#version 100 + +//_DEFINES_ + +precision highp float; + +varying vec2 v_coords; + +uniform sampler2D tex; +uniform vec2 half_pixel; +uniform float offset; + +uniform float alpha; +#if defined(DEBUG_FLAGS) +uniform float tint; +#endif + +void main() { + vec4 sum = texture2D(tex, v_coords) * 4.0; + sum += texture2D(tex, v_coords - half_pixel * offset); + sum += texture2D(tex, v_coords + half_pixel * offset); + sum += texture2D(tex, v_coords + vec2(half_pixel.x, -half_pixel.y) * offset); + sum += texture2D(tex, v_coords - vec2(half_pixel.x, -half_pixel.y) * offset); + + gl_FragColor = sum / sum.a; +} diff --git a/src/backend/render/shaders/blur_upsample.frag b/src/backend/render/shaders/blur_upsample.frag new file mode 100644 index 000000000..ac026d198 --- /dev/null +++ b/src/backend/render/shaders/blur_upsample.frag @@ -0,0 +1,27 @@ +#version 100 + +precision highp float; + +varying vec2 v_coords; + +uniform sampler2D tex; +uniform vec2 half_pixel; +uniform float offset; + +uniform float alpha; +#if defined(DEBUG_FLAGS) +uniform float tint; +#endif + +void main() { + vec4 sum = texture2D(tex, v_coords + vec2(-half_pixel.x * 2.0, 0.0) * offset); + sum += texture2D(tex, v_coords + vec2(-half_pixel.x, half_pixel.y) * offset) * 2.0; + sum += texture2D(tex, v_coords + vec2(0.0, half_pixel.y * 2.0) * offset); + sum += texture2D(tex, v_coords + vec2(half_pixel.x, half_pixel.y) * offset) * 2.0; + sum += texture2D(tex, v_coords + vec2(half_pixel.x * 2.0, 0.0) * offset); + sum += texture2D(tex, v_coords + vec2(half_pixel.x, -half_pixel.y) * offset) * 2.0; + sum += texture2D(tex, v_coords + vec2(0.0, -half_pixel.y * 2.0) * offset); + sum += texture2D(tex, v_coords + vec2(-half_pixel.x, -half_pixel.y) * offset) * 2.0; + + gl_FragColor = sum / sum.a; +} diff --git a/src/backend/render/shaders/clipped_surface.frag b/src/backend/render/shaders/clipped_surface.frag index dd863d232..d99d1a569 100644 --- a/src/backend/render/shaders/clipped_surface.frag +++ b/src/backend/render/shaders/clipped_surface.frag @@ -25,6 +25,7 @@ uniform float tint; uniform vec2 geo_size; uniform vec4 corner_radius; uniform mat3 input_to_geo; +uniform float noise; float rounding_alpha(vec2 coords, vec2 size) { vec2 center; @@ -51,15 +52,26 @@ float rounding_alpha(vec2 coords, vec2 size) { return 1.0 - smoothstep(radius - half_px, radius + half_px, dist); } +float hash(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * 727.727); + p3 += dot(p3, p3.xyz + 33.33); + return fract((p3.x + p3.y) * p3.z); +} + void main() { - vec3 coords_geo = input_to_geo * vec3(v_coords, 1.0); + if (alpha <= 0.0) { + discard; + } - // Sample the texture. vec4 color = texture2D(tex, v_coords); #if defined(NO_ALPHA) color = vec4(color.rgb, 1.0); #endif + if (color.a <= 0.0) { + discard; + } + vec3 coords_geo = input_to_geo * vec3(v_coords, 1.0); if (coords_geo.x < 0.0 || 1.0 < coords_geo.x || coords_geo.y < 0.0 || 1.0 < coords_geo.y) { // Clip outside geometry. color = vec4(0.0); @@ -68,8 +80,20 @@ void main() { color = color * rounding_alpha(coords_geo.xy * geo_size, geo_size); } + if (color.a <= 0.0) { + discard; + } + + if (noise > 0.0) { + // Add noise fx + // This can be used to achieve a glass look + float noiseHash = hash(v_coords); + float noiseAmount = (mod(noiseHash, 1.0) - 0.5); + color.rgb += noiseAmount * noise; + } + // Apply final alpha and tint. - color = color * alpha; + color *= alpha; #if defined(DEBUG_FLAGS) if (tint == 1.0) diff --git a/src/backend/render/wayland/blur_effect.rs b/src/backend/render/wayland/blur_effect.rs new file mode 100644 index 000000000..2a0be977a --- /dev/null +++ b/src/backend/render/wayland/blur_effect.rs @@ -0,0 +1,627 @@ +use std::{ + borrow::{Borrow, BorrowMut}, + sync::{ + Arc, LazyLock, Mutex, + atomic::{AtomicBool, Ordering}, + }, +}; + +use cgmath::{Matrix3, SquareMatrix, Vector2}; +use smithay::{ + backend::{ + allocator::Fourcc, + renderer::{ + Bind, BlitFrame, Color32F, ContextId, Frame, FrameContext, ImportAll, Offscreen, + Renderer, Texture, TextureFilter, + element::{Element, Id, Kind, RenderElement}, + gles::{ + GlesError, GlesFrame, GlesRenderer, GlesTexProgram, GlesTexture, Uniform, + UniformName, UniformType, UniformValue, ffi, + }, + sync::SyncPoint, + utils::{CommitCounter, DamageSet}, + }, + }, + utils::{ + Buffer, Logical, Physical, Point, Rectangle, Scale, Size, Transform, user_data::UserDataMap, + }, + wayland::compositor::SurfaceData, +}; +use tracing::info; + +use crate::{ + backend::render::{element::AsGlowRenderer, wayland::clipped_surface::ClippingShader}, + wayland::handlers::background_effect::ComputedBlurRegionCachedState, +}; + +pub static BLUR_DOWNSAMPLE_SHADER: &str = include_str!("../shaders/blur_downsample.frag"); +pub static BLUR_UPSAMPLE_SHADER: &str = include_str!("../shaders/blur_upsample.frag"); + +const NOISE: f32 = 0.03; +const MAX_STEPS: usize = 15; + +#[derive(Debug, Clone, Copy, PartialEq)] +struct BlurParameters { + passes: usize, + offset: f64, + extended_radius: i32, +} + +static BLUR_PARAMS: LazyLock> = LazyLock::new(|| { + let mut params = Vec::new(); + + let mut remaining_steps = MAX_STEPS as isize; + let offsets = [ + // min offset, max offset, extended radius to avoid artifacts + (1.0, 2.0, 10), + (2.0, 3.0, 20), + (2.0, 5.0, 50), + (3.0, 8.0, 150), + ]; + + let sum = offsets.iter().map(|(min, max, _)| *max - *min).sum::(); + for (i, (min, max, extended_radius)) in offsets.into_iter().enumerate() { + let mut iter_num = f64::ceil((max - min) / sum * (MAX_STEPS as f64)) as usize; + remaining_steps -= iter_num as isize; + + if remaining_steps < 0 { + iter_num = iter_num.saturating_add_signed(remaining_steps); + } + + let diff = max - min; + for j in 1..=iter_num { + params.push(BlurParameters { + passes: i + 1, + offset: min + (diff / iter_num as f64) * j as f64, + extended_radius, + }); + } + } + + info!("Computed blur values: {:#?}", ¶ms); + params +}); + +#[derive(Debug, Clone)] +pub struct BlurShaders { + down: GlesTexProgram, + up: GlesTexProgram, +} + +impl BlurShaders { + pub fn compile(renderer: &mut GlesRenderer) -> Result { + let up = renderer.compile_custom_texture_shader( + BLUR_UPSAMPLE_SHADER, + &[ + UniformName::new("half_pixel", UniformType::_2f), + UniformName::new("offset", UniformType::_1f), + ], + )?; + let down = renderer.compile_custom_texture_shader( + BLUR_DOWNSAMPLE_SHADER, + &[ + UniformName::new("half_pixel", UniformType::_2f), + UniformName::new("offset", UniformType::_1f), + ], + )?; + + Ok(BlurShaders { up, down }) + } + + pub fn get(renderer: &R) -> Self { + Borrow::::borrow(renderer.glow_renderer()) + .egl_context() + .user_data() + .get::() + .expect("Custom Shaders not initialized") + .clone() + } +} + +type BlurTexture = Mutex>; + +struct BlurState { + id: Id, + renderer_id: Option>, + src: Size, + offset: f64, + passes: usize, + region: Vec>, + dirty: Arc, +} + +unsafe impl Send for BlurState {} +unsafe impl Sync for BlurState {} + +impl BlurState { + fn new() -> Self { + BlurState { + id: Id::new(), + renderer_id: None, + src: Size::new(0., 0.), + offset: 0., + passes: 0, + region: Vec::new(), + dirty: Arc::new(AtomicBool::new(true)), + } + } +} + +pub struct BlurElement { + id: Id, + src: Size, + geometry: Rectangle, + scaling_shaders: BlurShaders, + render_shader: GlesTexProgram, + dirty: Arc, + region: Vec>, + offset: f64, + passes: usize, + uniforms: Vec>, +} + +impl BlurElement { + pub fn from_surface( + renderer: &mut R, + states: &SurfaceData, + geometry: Rectangle, + output_scale: f64, + radii: [u8; 4], + strength: usize, + ) -> Result, R::Error> { + let mut blur_region_state = states.cached_state.get::(); + let Some(region) = blur_region_state.current().blur_region.as_ref() else { + return Ok(None); + }; + + let geo = geometry.to_physical_precise_round(output_scale); + let mut extended_geo = geo; + let radius = BLUR_PARAMS[strength.min(MAX_STEPS - 1)].extended_radius as f64; + extended_geo.loc -= Point::::new(radius, radius); + extended_geo.size += Size::::new(radius, radius).upscale(2.); + + // compute input_to_geo so that it crops the extended capture radius + let geo_scale = { + let Scale { x, y } = geo.size / extended_geo.size; + Matrix3::from_nonuniform_scale(x as f32, y as f32) + .invert() + .unwrap() + }; + let geo_translation = { + let offset = geo.loc - extended_geo.loc; + Matrix3::from_translation(Vector2::new( + (offset.x / extended_geo.size.w) as f32, + (offset.y / extended_geo.size.h) as f32, + )) + .invert() + .unwrap() + }; + let input_to_geo = geo_scale * geo_translation; + + let uniforms = vec![ + Uniform::new("geo_size", (geometry.size.w as f32, geometry.size.h as f32)), + Uniform::new( + "corner_radius", + [ + radii[3] as f32, + radii[1] as f32, + radii[0] as f32, + radii[2] as f32, + ], + ), + Uniform::new( + "input_to_geo", + UniformValue::Matrix3x3 { + matrices: vec![*AsRef::<[f32; 9]>::as_ref(&input_to_geo)], + transpose: false, + }, + ), + Uniform::new("noise", UniformValue::_1f(NOISE)), + ]; + + let state = states + .data_map + .get_or_insert_threadsafe::, _>(|| Mutex::new(BlurState::new())); + + Ok(Some(Self::from_state( + renderer, + extended_geo.to_logical(output_scale), + ®ion, + output_scale, + &mut *state.lock().unwrap(), + uniforms, + strength, + )?)) + } + + fn from_state( + renderer: &mut R, + geometry: Rectangle, + region: &Vec>, + output_scale: f64, + state: &mut BlurState, + uniforms: Vec>, + strength: usize, + ) -> Result { + let renderer_id = renderer.glow_renderer().context_id(); + let src = geometry.size.to_buffer(output_scale, Transform::Normal); + let params = &BLUR_PARAMS[strength.min(MAX_STEPS - 1)]; + + let dirty = !(state + .renderer_id + .as_ref() + .is_some_and(|id| id == &renderer_id) + && state.offset == params.offset + && state.passes == params.passes + && &state.region == region + && state.src == src); + + state.renderer_id = Some(renderer_id); + state.offset = params.offset; + state.passes = params.passes; + state.region = region.clone(); + state.src = src; + if dirty { + state.dirty.store(dirty, Ordering::Release); + } + + Ok(BlurElement { + id: state.id.clone(), + src, + geometry, + scaling_shaders: BlurShaders::get(renderer), + render_shader: ClippingShader::get(renderer), + dirty: state.dirty.clone(), + offset: state.offset, + passes: state.passes, + region: region + .iter() + .map(|rect| rect.to_physical_precise_round(output_scale)) + .collect(), + uniforms, + }) + } +} + +impl Element for BlurElement { + fn id(&self) -> &Id { + &self.id + } + + fn current_commit(&self) -> CommitCounter { + Default::default() + } + + fn src(&self) -> Rectangle { + Rectangle::from_size(self.src) + } + + fn geometry(&self, scale: Scale) -> Rectangle { + self.geometry.to_physical_precise_round(scale) + } + + fn transform(&self) -> Transform { + Transform::Normal + } + + fn damage_since( + &self, + scale: Scale, + commit: Option, + ) -> DamageSet { + if commit.is_none() || self.dirty.load(Ordering::Acquire) { + DamageSet::from_slice(&[self.geometry.to_physical_precise_round(scale)]) + } else { + DamageSet::default() + } + } + + fn alpha(&self) -> f32 { + 1.0 + } + + fn kind(&self) -> Kind { + Kind::default() + } + + fn is_framebuffer_effect(&self) -> bool { + true + } +} + +impl RenderElement for BlurElement { + fn capture_framebuffer( + &self, + frame: &mut ::Frame<'_, '_>, + src: Rectangle, + dst: Rectangle, + cache: &UserDataMap, + ) -> Result<(), ::Error> { + let glow_frame = ::glow_frame_mut(frame); + let gles_frame = BorrowMut::>::borrow_mut(glow_frame); + let transform = gles_frame.transformation(); + let tex_size = self.src.to_i32_round(); + + let texture_ref = cache.get_or_insert_threadsafe(BlurTexture::default); + let mut texture_entry = texture_ref.lock().unwrap(); + if self.dirty.swap(false, Ordering::Acquire) { + texture_entry.take(); + } + + let mut renderer = gles_frame.renderer(); + if texture_entry.is_none() { + *texture_entry = Some( + renderer + .as_mut() + .create_buffer(Fourcc::Abgr8888, tex_size) + .map_err(R::from_gles_error)?, + ); + } + let texture = texture_entry.as_mut().unwrap(); + let mut off_texture = renderer + .as_mut() + .create_buffer(Fourcc::Abgr8888, tex_size) + .map_err(R::from_gles_error)?; + std::mem::drop(renderer); + + let sync = blit_from_active_fb(gles_frame, src, dst, transform, texture) + .map_err(R::from_gles_error)?; + gles_frame.wait(&sync).map_err(R::from_gles_error)?; + + let mut textures = [texture, &mut off_texture]; + render_blur( + gles_frame.renderer().as_mut(), + &self.scaling_shaders, + &mut textures, + self.offset, + self.passes, + ) + .map_err(R::from_gles_error)?; + + Ok(()) + } + + fn draw( + &self, + frame: &mut R::Frame<'_, '_>, + src: Rectangle, + dst: Rectangle, + damage: &[Rectangle], + opaque_regions: &[Rectangle], + cache: Option<&UserDataMap>, + ) -> Result<(), R::Error> { + let glow_frame = ::glow_frame_mut(frame); + let damage = self + .region + .iter() + .flat_map(|rect| damage.iter().flat_map(|r| r.intersection(*rect))) + .collect::>(); + let cache = cache.expect("Framebuffer element without cache?"); + let Some(texture) = cache.get::() else { + return Err(R::from_gles_error(GlesError::BlitError)); + }; + let texture_ref = texture.lock().unwrap(); + + BorrowMut::>::borrow_mut(glow_frame) + .render_texture_from_to( + texture_ref + .as_ref() + .ok_or(R::from_gles_error(GlesError::BlitError))?, + src, + dst, + &damage, + opaque_regions, + Transform::Normal, + 1.0, + Some(&self.render_shader), + &self.uniforms, + ) + .map_err(R::from_gles_error) + } +} + +fn blit_from_active_fb( + frame: &mut GlesFrame<'_, '_>, + src: Rectangle, + dst: Rectangle, + transform: Transform, + to_texture: &mut GlesTexture, +) -> Result { + if transform != Transform::Normal { + let tex_size = to_texture + .size() + .to_logical(1, Transform::Normal) + .to_physical(1); + let mut renderer = frame.renderer(); + let mut tmp_texture = renderer.as_mut().create_buffer( + Fourcc::Abgr8888, + dst.size.to_logical(1).to_buffer(1, Transform::Normal), + )?; + let mut fb_tmp = renderer.as_mut().bind(&mut tmp_texture)?; + let mut fb = renderer.as_mut().bind(to_texture)?; + std::mem::drop(renderer); + + frame.blit_to( + &mut fb_tmp, + dst, + Rectangle::from_size(dst.size), + TextureFilter::Linear, + )?; + std::mem::drop(fb_tmp); + + let mut renderer = frame.renderer(); + let mut frame = renderer + .as_mut() + .render(&mut fb, tex_size, Transform::Normal)?; + Frame::render_texture_from_to( + &mut frame, + &tmp_texture, + Rectangle::from_size( + dst.size + .to_logical(1) + .to_buffer(1, Transform::Normal) + .to_f64(), + ), + src.to_logical(1., Transform::Normal, &src.size) + .to_physical(1.) + .to_i32_round(), + &[Rectangle::from_size(dst.size)], + &[Rectangle::from_size(dst.size)], + transform, + 1.0, + )?; + std::mem::drop(tmp_texture); + frame.finish() + } else { + let mut fb = frame.renderer().as_mut().bind(to_texture)?; + + frame + .blit_to( + &mut fb, + dst, + src.to_logical(1., Transform::Normal, &src.size) + .to_physical(1.) + .to_i32_round(), + TextureFilter::Linear, + ) + .map(|_| SyncPoint::signaled()) + } +} + +fn render_blur( + renderer: &mut GlesRenderer, + shaders: &BlurShaders, + textures: &mut [&mut GlesTexture; 2], + offset: f64, + passes: usize, +) -> Result<(), GlesError> { + for i in 0..passes { + let tex_size = textures[0].size(); + let [src_tex, target_tex] = textures; + let mut fb = renderer.bind(*target_tex)?; + + let adjusted_tex_size = tex_size.downscale(1 << i); + let target_tex_size = tex_size + .downscale(1 << i + 1) + .to_logical(1, Transform::Normal) + .to_physical(1); + let half_pixel = [ + 0.5 / (adjusted_tex_size.w as f32), + 0.5 / (adjusted_tex_size.h as f32), + ]; + + let mut frame = renderer.render( + &mut fb, + tex_size.to_logical(1, Transform::Normal).to_physical(1), + Transform::Normal, + )?; + frame.clear( + Color32F::new(0., 0., 0., 0.), + &[Rectangle::from_size( + tex_size.to_logical(1, Transform::Normal).to_physical(1), + )], + )?; + frame.with_context(|gl| unsafe { + gl.TexParameteri( + ffi::TEXTURE_2D, + ffi::TEXTURE_WRAP_S, + ffi::CLAMP_TO_EDGE as i32, + ); + gl.TexParameteri( + ffi::TEXTURE_2D, + ffi::TEXTURE_WRAP_T, + ffi::CLAMP_TO_EDGE as i32, + ); + })?; + frame.render_texture_from_to( + src_tex, + Rectangle::from_size(adjusted_tex_size.to_f64()), + Rectangle::from_size(target_tex_size), + &[Rectangle::from_size(target_tex_size)], + &[Rectangle::from_size(target_tex_size)], + Transform::Normal, + 1.0, + Some(&shaders.down), + &[ + Uniform::new("half_pixel", half_pixel), + Uniform::new("offset", (offset / (1 << i) as f64) as f32), + ], + )?; + frame.with_context(|gl| unsafe { + gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::REPEAT as i32); + gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::REPEAT as i32); + })?; + let sync = frame.finish()?; + std::mem::drop(fb); + renderer.wait(&sync)?; + + textures.swap(0, 1); + } + + for i in 0..passes { + let tex_size = textures[0].size(); + let [src_tex, target_tex] = textures; + let mut fb = renderer.bind(*target_tex)?; + + let adjusted_tex_size = tex_size.downscale(1 << (passes - i)); + let target_tex_size = tex_size + .downscale(1 << (passes - i - 1)) + .to_logical(1, Transform::Normal) + .to_physical(1); + let half_pixel = [ + 0.5 / (adjusted_tex_size.w as f32), + 0.5 / (adjusted_tex_size.h as f32), + ]; + + let mut frame = renderer.render( + &mut fb, + tex_size.to_logical(1, Transform::Normal).to_physical(1), + Transform::Normal, + )?; + frame.clear( + Color32F::new(0., 0., 0., 0.), + &[Rectangle::from_size( + tex_size.to_logical(1, Transform::Normal).to_physical(1), + )], + )?; + frame.with_context(|gl| unsafe { + gl.TexParameteri( + ffi::TEXTURE_2D, + ffi::TEXTURE_WRAP_S, + ffi::CLAMP_TO_EDGE as i32, + ); + gl.TexParameteri( + ffi::TEXTURE_2D, + ffi::TEXTURE_WRAP_T, + ffi::CLAMP_TO_EDGE as i32, + ); + })?; + frame.render_texture_from_to( + src_tex, + Rectangle::from_size(adjusted_tex_size.to_f64()), + Rectangle::from_size(target_tex_size), + &[Rectangle::from_size(target_tex_size)], + &[Rectangle::from_size(target_tex_size)], + Transform::Normal, + 1.0, + Some(&shaders.up), + &[ + Uniform::new("half_pixel", half_pixel), + Uniform::new("offset", (offset / (1 << (passes - i)) as f64) as f32), + ], + )?; + frame.with_context(|gl| unsafe { + gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_S, ffi::REPEAT as i32); + gl.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::REPEAT as i32); + })?; + let sync = frame.finish()?; + std::mem::drop(fb); + renderer.wait(&sync)?; + + textures.swap(0, 1); + } + + // textures always end up the right way around with `self.texture` containing our final render, + // since we render PASSES * 2 (downscale and upscale), so the number of swaps is always even. + Ok(()) +} diff --git a/src/backend/render/clipped_surface.rs b/src/backend/render/wayland/clipped_surface.rs similarity index 90% rename from src/backend/render/clipped_surface.rs rename to src/backend/render/wayland/clipped_surface.rs index 6f2a2d0c6..3e24215ca 100644 --- a/src/backend/render/clipped_surface.rs +++ b/src/backend/render/wayland/clipped_surface.rs @@ -3,19 +3,23 @@ use std::borrow::{Borrow, BorrowMut}; use cgmath::{Matrix3, Vector2}; -use smithay::backend::renderer::{ - ImportAll, ImportMem, Renderer, - element::{ - Element, Id, Kind, RenderElement, UnderlyingStorage, surface::WaylandSurfaceRenderElement, +use smithay::utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Size, Transform}; +use smithay::{ + backend::renderer::{ + ImportAll, Renderer, + element::{ + Element, Id, Kind, RenderElement, UnderlyingStorage, + surface::WaylandSurfaceRenderElement, + }, + gles::{GlesFrame, GlesRenderer, GlesTexProgram, Uniform, UniformValue}, + utils::{CommitCounter, DamageSet, OpaqueRegions}, }, - gles::{GlesFrame, GlesRenderer, GlesTexProgram, Uniform, UniformValue}, - utils::{CommitCounter, DamageSet, OpaqueRegions}, + utils::user_data::UserDataMap, }; -use smithay::utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Size, Transform}; use crate::backend::render::element::AsGlowRenderer; -pub static CLIPPING_SHADER: &str = include_str!("./shaders/clipped_surface.frag"); +pub static CLIPPING_SHADER: &str = include_str!("../shaders/clipped_surface.frag"); pub struct ClippingShader(pub GlesTexProgram); impl ClippingShader { @@ -31,10 +35,7 @@ impl ClippingShader { } #[derive(Debug)] -pub struct ClippedSurfaceRenderElement -where - R: Renderer + ImportAll + ImportMem, -{ +pub struct ClippedSurfaceRenderElement { inner: WaylandSurfaceRenderElement, program: GlesTexProgram, radius: [u8; 4], @@ -44,7 +45,7 @@ where impl ClippedSurfaceRenderElement where - R: Renderer + ImportAll + ImportMem, + R: Renderer + ImportAll, { pub fn new( renderer: &mut R, @@ -110,6 +111,7 @@ where transpose: false, }, ), + Uniform::new("noise", UniformValue::_1f(0.0)), ]; Self { @@ -170,7 +172,8 @@ where impl Element for ClippedSurfaceRenderElement where - R: Renderer + ImportAll + ImportMem, + R: Renderer + ImportAll + AsGlowRenderer, + R::TextureId: 'static, { fn id(&self) -> &Id { self.inner.id() @@ -243,7 +246,7 @@ where impl RenderElement for ClippedSurfaceRenderElement where - R: AsGlowRenderer + Renderer + ImportAll + ImportMem, + R: AsGlowRenderer + Renderer + ImportAll, R::TextureId: 'static, { fn draw( @@ -253,10 +256,12 @@ where dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + cache: Option<&UserDataMap>, ) -> Result<(), R::Error> { BorrowMut::::borrow_mut(::glow_frame_mut(frame)) .override_default_tex_program(self.program.clone(), self.uniforms.clone()); - self.inner.draw(frame, src, dst, damage, opaque_regions)?; + self.inner + .draw(frame, src, dst, damage, opaque_regions, cache)?; BorrowMut::::borrow_mut(::glow_frame_mut(frame)) .clear_tex_program_override(); Ok(()) diff --git a/src/backend/render/wayland/mod.rs b/src/backend/render/wayland/mod.rs new file mode 100644 index 000000000..9ac1109ca --- /dev/null +++ b/src/backend/render/wayland/mod.rs @@ -0,0 +1,142 @@ +use smithay::{ + backend::renderer::{ + ImportAll, Renderer, + element::surface::{KindEvaluation, WaylandSurfaceRenderElement}, + utils::RendererSurfaceStateUserData, + }, + reexports::wayland_server::protocol::wl_surface, + render_elements, + utils::{Logical, Physical, Point, Rectangle, Scale}, + wayland::compositor::{self, TraversalAction}, +}; +use tracing::warn; + +use crate::backend::render::{ + element::AsGlowRenderer, + wayland::{blur_effect::BlurElement, clipped_surface::ClippedSurfaceRenderElement}, +}; + +pub mod blur_effect; +pub mod clipped_surface; + +render_elements! { + pub SurfaceRenderElement where R: AsGlowRenderer + ImportAll; + Blur=BlurElement, + Clipped=ClippedSurfaceRenderElement, + Wayland=WaylandSurfaceRenderElement, +} + +pub fn push_render_elements_from_surface_tree( + renderer: &mut R, + main_surface: &wl_surface::WlSurface, + location: impl Into>, + geometry: impl Into>, + scale: impl Into>, + alpha: f32, + should_clip: bool, + radii: [u8; 4], + blur_strength: usize, + kind: impl Into, + push_above: &mut dyn FnMut(SurfaceRenderElement), + mut push_below: Option<&mut dyn FnMut(SurfaceRenderElement)>, +) where + R: Renderer + ImportAll + AsGlowRenderer, + R::TextureId: Clone + 'static, +{ + let location = location.into().to_f64(); + let geometry = geometry.into().to_f64(); + let scale = scale.into(); + let kind = kind.into(); + let mut passed_main = false; + + compositor::with_surface_tree_downward( + main_surface, + location, + |_, states, location| { + let mut location = *location; + let data = states.data_map.get::(); + + if let Some(data) = data { + if let Some(view) = data.lock().unwrap().view() { + location += view.offset.to_f64().to_physical(scale); + TraversalAction::DoChildren(location) + } else { + TraversalAction::SkipChildren + } + } else { + TraversalAction::SkipChildren + } + }, + |surface, states, location| { + let mut location = *location; + let kind = kind.eval(states); + let data = states.data_map.get::(); + let mut blur = Ok(None); + + if let Some(data) = data { + let has_view = if let Some(view) = data.lock().unwrap().view() { + location += view.offset.to_f64().to_physical(scale); + + true + } else { + false + }; + + if has_view { + match WaylandSurfaceRenderElement::from_surface( + renderer, surface, states, location, alpha, kind, + ) { + Ok(Some(surface)) => { + blur = BlurElement::from_surface( + renderer, + states, + geometry, + scale.x, + radii, + blur_strength, + ); + let elem: SurfaceRenderElement = if radii.iter().any(|r| *r != 0) + && should_clip + && ClippedSurfaceRenderElement::will_clip( + &surface, scale, geometry, radii, + ) { + ClippedSurfaceRenderElement::new( + renderer, surface, scale, geometry, radii, + ) + .into() + } else { + surface.into() + }; + if let Some(push_below) = push_below.as_mut() + && passed_main + { + push_below(elem); + } else { + push_above(elem); + } + } + Ok(None) => {} // surface is not mapped + Err(err) => { + warn!("Failed to import surface: {}", err); + } + }; + } + } + + if surface == main_surface { + passed_main = true; + } + + if let Ok(Some(elem)) = blur { + if let Some(push_below) = push_below.as_mut() + && passed_main + { + push_below(elem.into()); + } else { + push_above(elem.into()); + } + } + }, + |_, _, _| true, + ); +} diff --git a/src/input/mod.rs b/src/input/mod.rs index c57eeca4a..41ff6e181 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -2074,6 +2074,7 @@ impl State { layer, popup, location, + .. } => { if layer.can_receive_keyboard_focus() { let surface = popup.wl_surface(); @@ -2091,7 +2092,9 @@ impl State { } } } - Stage::LayerSurface { layer, location } => { + Stage::LayerSurface { + layer, location, .. + } => { if under_from_surface_tree( layer.wl_surface(), global_pos.as_logical(), @@ -2247,7 +2250,9 @@ impl State { )))); } } - Stage::LayerSurface { layer, location } => { + Stage::LayerSurface { + layer, location, .. + } => { let surface = layer.wl_surface(); if let Some((surface, surface_loc)) = under_from_surface_tree( surface, diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 812d572ee..460511bb1 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -1,5 +1,5 @@ use crate::{ - backend::render::element::{AsGlowRenderer, FromGlesError}, + backend::render::element::AsGlowRenderer, state::State, utils::{iced::IcedElementInternal, prelude::*}, }; @@ -12,7 +12,7 @@ use smithay::{ renderer::{ ImportAll, ImportMem, Renderer, element::{ - Element, RenderElement, UnderlyingStorage, + Element, Kind, RenderElement, UnderlyingStorage, memory::MemoryRenderBufferRenderElement, utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement}, }, @@ -31,6 +31,7 @@ use smithay::{ space_elements, utils::{ Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, + user_data::UserDataMap, }, wayland::seat::WaylandFocus, xwayland::{X11Surface, xwm::X11Relatable}, @@ -563,33 +564,31 @@ impl CosmicMapped { } } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, - ) -> Vec - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, - C: From>, { match &self.element { - CosmicMappedInternal::Stack(s) => s - .popup_render_elements::>( - renderer, location, scale, alpha, - ), - CosmicMappedInternal::Window(w) => w - .popup_render_elements::>( - renderer, location, scale, alpha, - ), + CosmicMappedInternal::Stack(s) => { + s.push_popup_render_elements(renderer, location, scale, alpha, &mut |elem| { + push(elem.into()) + }) + } + CosmicMappedInternal::Window(w) => { + w.push_popup_render_elements(renderer, location, scale, alpha, &mut |elem| { + push(elem.into()) + }) + } _ => unreachable!(), } - .into_iter() - .map(C::from) - .collect() } pub fn shadow_render_element( @@ -636,7 +635,7 @@ impl CosmicMapped { } } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: smithay::utils::Point, @@ -644,15 +643,15 @@ impl CosmicMapped { scale: smithay::utils::Scale, alpha: f32, scanout_override: Option, - ) -> Vec - where + push_above: &mut dyn FnMut(CosmicMappedRenderElement), + push_below: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, - C: From>, { #[cfg(feature = "debug")] - let mut elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { + if let Some(debug) = self.debug.lock().unwrap().as_mut() { let window = self.active_window(); let window_geo = window.geometry(); let (min_size, max_size, size) = ( @@ -813,41 +812,36 @@ impl CosmicMapped { scale.x, 0.8, ) { - Ok(element) => vec![CosmicMappedRenderElement::from(element).into()], + Ok(element) => push_above(element.into()), Err(err) => { debug!(?err, "Error rendering debug overlay."); - Vec::new() } } - } else { - Vec::new() }; - #[cfg(not(feature = "debug"))] - let mut elements = Vec::new(); - #[cfg_attr(not(feature = "debug"), allow(unused_mut))] - elements.extend(match &self.element { - CosmicMappedInternal::Stack(s) => s.render_elements::>( + match &self.element { + CosmicMappedInternal::Stack(s) => s.push_render_elements( renderer, location, max_size, scale, alpha, scanout_override, + &mut |elem| push_above(elem.into()), + &mut |elem| push_below(elem.into()), + ), + CosmicMappedInternal::Window(w) => w.push_render_elements( + renderer, + location, + max_size, + scale, + alpha, + scanout_override, + &mut |elem| push_above(elem.into()), + &mut |elem| push_below(elem.into()), ), - CosmicMappedInternal::Window(w) => w - .render_elements::>( - renderer, - location, - max_size, - scale, - alpha, - scanout_override, - ), _ => unreachable!(), - }); - - elements.into_iter().map(C::from).collect() + } } pub(crate) fn update_theme(&self, theme: cosmic::Theme) { @@ -1275,13 +1269,50 @@ where CosmicMappedRenderElement::Egui(elem) => elem.alpha(), } } + + fn kind(&self) -> Kind { + match self { + CosmicMappedRenderElement::Stack(elem) => elem.kind(), + CosmicMappedRenderElement::Window(elem) => elem.kind(), + CosmicMappedRenderElement::TiledStack(elem) => elem.kind(), + CosmicMappedRenderElement::TiledWindow(elem) => elem.kind(), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.kind(), + CosmicMappedRenderElement::MovingStack(elem) => elem.kind(), + CosmicMappedRenderElement::MovingWindow(elem) => elem.kind(), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.kind(), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.kind(), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.kind(), + CosmicMappedRenderElement::Overlay(elem) => elem.kind(), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.kind(), + #[cfg(feature = "debug")] + CosmicMappedRenderElement::Egui(elem) => elem.kind(), + } + } + + fn is_framebuffer_effect(&self) -> bool { + match self { + CosmicMappedRenderElement::Stack(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::Window(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::TiledStack(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::TiledWindow(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::TiledOverlay(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::MovingStack(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::MovingWindow(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::GrabbedStack(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::GrabbedWindow(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::FocusIndicator(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::Overlay(elem) => elem.is_framebuffer_effect(), + CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.is_framebuffer_effect(), + #[cfg(feature = "debug")] + CosmicMappedRenderElement::Egui(elem) => elem.is_framebuffer_effect(), + } + } } impl RenderElement for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: 'static, - R::Error: FromGlesError, { fn draw( &self, @@ -1290,19 +1321,20 @@ where dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + cache: Option<&UserDataMap>, ) -> Result<(), R::Error> { match self { CosmicMappedRenderElement::Stack(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::Window(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::TiledStack(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::TiledWindow(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::TiledOverlay(elem) => RenderElement::::draw( elem, @@ -1311,19 +1343,20 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error), + .map_err(R::from_gles_error), CosmicMappedRenderElement::MovingStack(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::MovingWindow(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::GrabbedStack(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::GrabbedWindow(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicMappedRenderElement::FocusIndicator(elem) => RenderElement::::draw( elem, @@ -1332,8 +1365,9 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error), + .map_err(R::from_gles_error), CosmicMappedRenderElement::Overlay(elem) => RenderElement::::draw( elem, R::glow_frame_mut(frame), @@ -1341,10 +1375,11 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error), + .map_err(R::from_gles_error), CosmicMappedRenderElement::StackHoverIndicator(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { @@ -1356,8 +1391,9 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error) + .map_err(R::from_gles_error) } } } @@ -1391,6 +1427,82 @@ where } } } + + fn capture_framebuffer( + &self, + frame: &mut R::Frame<'_, '_>, + src: Rectangle, + dst: Rectangle, + cache: &UserDataMap, + ) -> Result<(), R::Error> { + match self { + CosmicMappedRenderElement::Stack(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::Window(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::TiledStack(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::TiledWindow(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::TiledOverlay(elem) => { + RenderElement::::capture_framebuffer( + elem, + R::glow_frame_mut(frame), + src, + dst, + cache, + ) + .map_err(R::from_gles_error) + } + CosmicMappedRenderElement::MovingStack(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::MovingWindow(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::GrabbedStack(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::GrabbedWindow(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicMappedRenderElement::FocusIndicator(elem) => { + RenderElement::::capture_framebuffer( + elem, + R::glow_frame_mut(frame), + src, + dst, + cache, + ) + .map_err(R::from_gles_error) + } + CosmicMappedRenderElement::Overlay(elem) => { + RenderElement::::capture_framebuffer( + elem, + R::glow_frame_mut(frame), + src, + dst, + cache, + ) + .map_err(R::from_gles_error) + } + CosmicMappedRenderElement::StackHoverIndicator(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + #[cfg(feature = "debug")] + CosmicMappedRenderElement::Egui(elem) => { + let glow_frame = R::glow_frame_mut(frame); + RenderElement::::capture_framebuffer( + elem, glow_frame, src, dst, cache, + ) + .map_err(R::from_gles_error) + } + } + } } impl From> for CosmicMappedRenderElement diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 56e878f8c..49608d4ea 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -4,11 +4,8 @@ use super::{ }; use crate::{ backend::render::{ - IndicatorShader, Key, Usage, - clipped_surface::ClippedSurfaceRenderElement, - cursor::CursorState, - element::{AsGlowRenderer, FromGlesError}, - shadow::ShadowShader, + IndicatorShader, Key, Usage, cursor::CursorState, element::AsGlowRenderer, + shadow::ShadowShader, wayland::SurfaceRenderElement, }, hooks::{Decorations, HOOKS}, shell::{ @@ -41,9 +38,8 @@ use smithay::{ renderer::{ ImportAll, ImportMem, Renderer, element::{ - AsRenderElements, Element, Id as RendererId, Kind, RenderElement, - UnderlyingStorage, memory::MemoryRenderBufferRenderElement, - surface::WaylandSurfaceRenderElement, + Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage, + memory::MemoryRenderBufferRenderElement, }, gles::element::PixelShaderElement, glow::GlowRenderer, @@ -67,7 +63,10 @@ use smithay::{ }, output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface, - utils::{Buffer, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform}, + utils::{ + Buffer, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform, + user_data::UserDataMap, + }, wayland::seat::WaylandFocus, }; use std::{ @@ -629,30 +628,30 @@ impl CosmicStack { self.0.loop_handle() } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, - ) -> Vec - where + push: &mut dyn FnMut(CosmicStackRenderElement), + ) where R: Renderer + AsGlowRenderer + ImportAll + ImportMem, R::TextureId: Send + Clone + 'static, - C: From>, { let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); self.0.with_program(|p| { let windows = p.windows.lock().unwrap(); let active = p.active.load(Ordering::SeqCst); - windows[active] - .popup_render_elements::>( - renderer, window_loc, scale, alpha, - ) - .into_iter() - .map(C::from) - .collect() + windows[active].push_popup_render_elements( + renderer, + window_loc, + scale, + alpha, + p.appearance_conf.lock().unwrap().blur_strength as usize, + &mut |elem| push(elem.into()), + ) }) } @@ -723,7 +722,7 @@ impl CosmicStack { }) } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: Point, @@ -731,17 +730,17 @@ impl CosmicStack { scale: Scale, alpha: f32, scanout_override: Option, - ) -> Vec - where + push_above: &mut dyn FnMut(CosmicStackRenderElement), + push_below: &mut dyn FnMut(CosmicStackRenderElement), + ) where R: Renderer + AsGlowRenderer + ImportAll + ImportMem, R::TextureId: Send + Clone + 'static, - C: From>, { if !self .0 .with_program(|p| p.override_alive.load(Ordering::Acquire)) { - return Vec::new(); + return; } let geometry = self @@ -751,11 +750,12 @@ impl CosmicStack { let stack_loc = location + geometry.loc; let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32)); - let mut elements = AsRenderElements::::render_elements::>( - &self.0, renderer, stack_loc, scale, alpha, - ); + self.0 + .push_render_elements(renderer, stack_loc, scale, alpha, &mut |elem| { + push_above(elem.into()) + }); - elements.extend(self.0.with_program(|p| { + self.0.with_program(|p| { let windows = p.windows.lock().unwrap(); let active = p.active.load(Ordering::SeqCst); let theme = p.theme.lock().unwrap(); @@ -782,9 +782,9 @@ impl CosmicStack { let window_key = CosmicMappedKey(CosmicMappedKeyInner::Stack(Arc::downgrade(&self.0.0))); - let border = (!maximized).then(|| { + if !maximized { let (r, g, b, a) = theme.cosmic().bg_divider().into_components(); - CosmicStackRenderElement::Border(IndicatorShader::element( + push_above(CosmicStackRenderElement::Border(IndicatorShader::element( renderer, Key::Window(Usage::Border, window_key.clone()), geo.to_i32_round().as_local(), @@ -793,39 +793,23 @@ impl CosmicStack { a * alpha, scale.x, [r, g, b], - )) - }); - - border.into_iter().chain( - windows[active] - .render_elements::>( - renderer, - window_loc, - scale, - alpha, - scanout_override, - ) - .into_iter() - .map(move |elem| { - let radii = radii.map(|[a, _, c, _]| [a, 0, c, 0]); - if radii.is_some_and(|radii| { - ClippedSurfaceRenderElement::will_clip(&elem, scale, geo, radii) - }) { - CosmicStackRenderElement::Clipped(ClippedSurfaceRenderElement::new( - renderer, - elem, - scale, - geo, - radii.unwrap(), - )) - } else { - CosmicStackRenderElement::Window(elem) - } - }), - ) - })); + ))); + }; - elements.into_iter().map(C::from).collect() + let radii = radii.map(|[a, _, c, _]| [a, 0, c, 0]); + windows[active].push_render_elements( + renderer, + window_loc, + scale, + alpha, + scanout_override, + radii.is_some(), + radii.unwrap_or([0; 4]), + appearance.blur_strength as usize, + &mut |elem| push_above(elem.into()), + Some(&mut |elem| push_below(elem.into())), + ); + }); } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { @@ -1856,8 +1840,7 @@ pub enum CosmicStackRenderElement { Header(MemoryRenderBufferRenderElement), Shadow(PixelShaderElement), Border(PixelShaderElement), - Window(WaylandSurfaceRenderElement), - Clipped(ClippedSurfaceRenderElement), + Window(SurfaceRenderElement), } impl From> @@ -1868,25 +1851,18 @@ impl From From> +impl From> for CosmicStackRenderElement { - fn from(value: WaylandSurfaceRenderElement) -> Self { + fn from(value: SurfaceRenderElement) -> Self { Self::Window(value) } } -impl From> - for CosmicStackRenderElement -{ - fn from(value: ClippedSurfaceRenderElement) -> Self { - Self::Clipped(value) - } -} - impl Element for CosmicStackRenderElement where - R: Renderer + ImportAll + ImportMem, + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + R::TextureId: 'static, { fn id(&self) -> &RendererId { match self { @@ -1894,7 +1870,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.id(), CosmicStackRenderElement::Border(elem) => elem.id(), CosmicStackRenderElement::Window(elem) => elem.id(), - CosmicStackRenderElement::Clipped(elem) => elem.id(), } } @@ -1904,7 +1879,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.current_commit(), CosmicStackRenderElement::Border(elem) => elem.current_commit(), CosmicStackRenderElement::Window(elem) => elem.current_commit(), - CosmicStackRenderElement::Clipped(elem) => elem.current_commit(), } } @@ -1914,7 +1888,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.src(), CosmicStackRenderElement::Border(elem) => elem.src(), CosmicStackRenderElement::Window(elem) => elem.src(), - CosmicStackRenderElement::Clipped(elem) => elem.src(), } } @@ -1924,7 +1897,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.geometry(scale), CosmicStackRenderElement::Border(elem) => elem.geometry(scale), CosmicStackRenderElement::Window(elem) => elem.geometry(scale), - CosmicStackRenderElement::Clipped(elem) => elem.geometry(scale), } } @@ -1934,7 +1906,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.location(scale), CosmicStackRenderElement::Border(elem) => elem.location(scale), CosmicStackRenderElement::Window(elem) => elem.location(scale), - CosmicStackRenderElement::Clipped(elem) => elem.location(scale), } } @@ -1944,7 +1915,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.transform(), CosmicStackRenderElement::Border(elem) => elem.transform(), CosmicStackRenderElement::Window(elem) => elem.transform(), - CosmicStackRenderElement::Clipped(elem) => elem.transform(), } } @@ -1958,7 +1928,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.damage_since(scale, commit), CosmicStackRenderElement::Border(elem) => elem.damage_since(scale, commit), CosmicStackRenderElement::Window(elem) => elem.damage_since(scale, commit), - CosmicStackRenderElement::Clipped(elem) => elem.damage_since(scale, commit), } } @@ -1968,7 +1937,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.opaque_regions(scale), CosmicStackRenderElement::Border(elem) => elem.opaque_regions(scale), CosmicStackRenderElement::Window(elem) => elem.opaque_regions(scale), - CosmicStackRenderElement::Clipped(elem) => elem.opaque_regions(scale), } } @@ -1978,7 +1946,6 @@ where CosmicStackRenderElement::Shadow(elem) => elem.alpha(), CosmicStackRenderElement::Border(elem) => elem.alpha(), CosmicStackRenderElement::Window(elem) => elem.alpha(), - CosmicStackRenderElement::Clipped(elem) => elem.alpha(), } } @@ -1988,7 +1955,15 @@ where CosmicStackRenderElement::Shadow(elem) => elem.kind(), CosmicStackRenderElement::Border(elem) => elem.kind(), CosmicStackRenderElement::Window(elem) => elem.kind(), - CosmicStackRenderElement::Clipped(elem) => elem.kind(), + } + } + + fn is_framebuffer_effect(&self) -> bool { + match self { + CosmicStackRenderElement::Header(elem) => elem.is_framebuffer_effect(), + CosmicStackRenderElement::Shadow(elem) => elem.is_framebuffer_effect(), + CosmicStackRenderElement::Border(elem) => elem.is_framebuffer_effect(), + CosmicStackRenderElement::Window(elem) => elem.is_framebuffer_effect(), } } } @@ -1997,19 +1972,19 @@ impl RenderElement for CosmicStackRenderElement where R: Renderer + AsGlowRenderer + ImportAll + ImportMem, R::TextureId: 'static, - R::Error: FromGlesError, { fn draw( &self, - frame: &mut ::Frame<'_, '_>, + frame: &mut R::Frame<'_, '_>, src: Rectangle, dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + cache: Option<&UserDataMap>, ) -> Result<(), ::Error> { match self { CosmicStackRenderElement::Header(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicStackRenderElement::Shadow(elem) | CosmicStackRenderElement::Border(elem) => { RenderElement::::draw( @@ -2019,14 +1994,12 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error) + .map_err(R::from_gles_error) } CosmicStackRenderElement::Window(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) - } - CosmicStackRenderElement::Clipped(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } } } @@ -2038,7 +2011,33 @@ where elem.underlying_storage(renderer.glow_renderer_mut()) } CosmicStackRenderElement::Window(elem) => elem.underlying_storage(renderer), - CosmicStackRenderElement::Clipped(elem) => elem.underlying_storage(renderer), + } + } + + fn capture_framebuffer( + &self, + frame: &mut R::Frame<'_, '_>, + src: Rectangle, + dst: Rectangle, + cache: &UserDataMap, + ) -> Result<(), ::Error> { + match self { + CosmicStackRenderElement::Header(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicStackRenderElement::Shadow(elem) | CosmicStackRenderElement::Border(elem) => { + RenderElement::::capture_framebuffer( + elem, + R::glow_frame_mut(frame), + src, + dst, + cache, + ) + .map_err(R::from_gles_error) + } + CosmicStackRenderElement::Window(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } } } } diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 840a98ae1..6581d70fb 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -1,4 +1,8 @@ use crate::{ + backend::render::{ + element::AsGlowRenderer, + wayland::{SurfaceRenderElement, push_render_elements_from_surface_tree}, + }, shell::focus::target::PointerFocusTarget, wayland::{ handlers::compositor::frame_time_filter_fn, protocols::corner_radius::CacheableCorners, @@ -16,10 +20,7 @@ use std::{ use smithay::{ backend::renderer::{ ImportAll, Renderer, - element::{ - AsRenderElements, Kind, RenderElementStates, - surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree}, - }, + element::{Kind, RenderElementStates}, }, desktop::{ PopupManager, Window, WindowSurface, WindowSurfaceType, space::SpaceElement, @@ -142,10 +143,10 @@ impl CosmicSurface { let corners = guard.current().0?; Some([ - corners.bottom_right.min(half_min_dim), + corners.top_left.min(half_min_dim), corners.top_right.min(half_min_dim), + corners.bottom_right.min(half_min_dim), corners.bottom_left.min(half_min_dim), - corners.top_left.min(half_min_dim), ]) }) }) @@ -733,64 +734,80 @@ impl CosmicSurface { self.0.user_data() } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, - ) -> Vec - where - R: Renderer + ImportAll, + blur_strength: usize, + push: &mut dyn FnMut(SurfaceRenderElement), + ) where + R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, - C: From>, { match self.0.underlying_surface() { WindowSurface::Wayland(toplevel) => { let surface = toplevel.wl_surface(); - PopupManager::popups_for_surface(surface) - .flat_map(move |(popup, popup_offset)| { - let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc) - .to_physical_precise_round(scale); - - render_elements_from_surface_tree( - renderer, - popup.wl_surface(), - location + offset, - scale, - alpha, - FRAME_TIME_FILTER, - ) - }) - .collect() + for (popup, popup_offset) in PopupManager::popups_for_surface(surface) { + let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc) + .to_physical_precise_round(scale); + let mut geometry = popup.geometry().to_f64(); + geometry.loc += location.to_f64().to_logical(scale) + popup_offset.to_f64(); + + push_render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + location + offset, + geometry, + scale, + alpha, + false, + [0; 4], + blur_strength, + FRAME_TIME_FILTER, + push, + None, + ) + } } - WindowSurface::X11(_) => Vec::new(), + WindowSurface::X11(_) => {} } } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, scanout_override: Option, - ) -> Vec - where - R: Renderer + ImportAll, + should_clip: bool, + radii: [u8; 4], + blur_strength: usize, + push_above: &mut dyn FnMut(SurfaceRenderElement), + push_below: Option<&mut dyn FnMut(SurfaceRenderElement)>, + ) where + R: Renderer + ImportAll + AsGlowRenderer, R::TextureId: Clone + 'static, - C: From>, { + let mut geometry = self.0.geometry().to_f64(); + geometry.loc += location.to_f64().to_logical(scale); + match self.0.underlying_surface() { WindowSurface::Wayland(toplevel) => { let surface = toplevel.wl_surface(); - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, surface, location, + geometry, scale, alpha, + should_clip, + radii, + blur_strength, scanout_override .map(|val| { if val { @@ -801,19 +818,25 @@ impl CosmicSurface { .into() }) .unwrap_or(FRAME_TIME_FILTER), + push_above, + push_below, ) } WindowSurface::X11(surface) => { let Some(surface) = surface.wl_surface() else { - return Vec::new(); + return; }; - render_elements_from_surface_tree( + push_render_elements_from_surface_tree( renderer, &surface, location, + geometry, scale, alpha, + should_clip, + radii, + blur_strength, scanout_override .map(|val| { if val { @@ -824,6 +847,8 @@ impl CosmicSurface { .into() }) .unwrap_or(FRAME_TIME_FILTER), + push_above, + push_below, ) } } @@ -957,24 +982,6 @@ impl X11Relatable for CosmicSurface { } } -impl AsRenderElements for CosmicSurface -where - R: Renderer + ImportAll, - R::TextureId: Clone + 'static, -{ - type RenderElement = WaylandSurfaceRenderElement; - - fn render_elements>( - &self, - renderer: &mut R, - location: Point, - scale: Scale, - alpha: f32, - ) -> Vec { - self.0.render_elements(renderer, location, scale, alpha) - } -} - fn with_toplevel_state) -> T>( toplevel: &ToplevelSurface, pending: bool, diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 3bfc6349a..bc6e90e04 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -1,10 +1,7 @@ use crate::{ backend::render::{ - IndicatorShader, Key, Usage, - clipped_surface::ClippedSurfaceRenderElement, - cursor::CursorState, - element::{AsGlowRenderer, FromGlesError}, - shadow::ShadowShader, + IndicatorShader, Key, Usage, cursor::CursorState, element::AsGlowRenderer, + shadow::ShadowShader, wayland::SurfaceRenderElement, }, hooks::{Decorations, HOOKS}, shell::{ @@ -27,9 +24,8 @@ use smithay::{ renderer::{ ImportAll, ImportMem, Renderer, element::{ - AsRenderElements, Element, Id as RendererId, Kind, RenderElement, - UnderlyingStorage, memory::MemoryRenderBufferRenderElement, - surface::WaylandSurfaceRenderElement, + Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage, + memory::MemoryRenderBufferRenderElement, }, gles::element::PixelShaderElement, glow::GlowRenderer, @@ -53,7 +49,10 @@ use smithay::{ }, output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface, - utils::{Buffer, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform}, + utils::{ + Buffer, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform, + user_data::UserDataMap, + }, wayland::seat::WaylandFocus, }; use std::{ @@ -323,17 +322,16 @@ impl CosmicWindow { self.0.loop_handle() } - pub fn popup_render_elements( + pub fn push_popup_render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, - ) -> Vec - where - R: Renderer + ImportAll + ImportMem, + push: &mut dyn FnMut(CosmicWindowRenderElement), + ) where + R: Renderer + AsGlowRenderer + ImportAll + ImportMem, R::TextureId: Send + Clone + 'static, - C: From>, { let has_ssd = self.0.with_program(|p| p.has_ssd(false)); @@ -344,13 +342,14 @@ impl CosmicWindow { }; self.0.with_program(|p| { - p.window - .popup_render_elements::>( - renderer, window_loc, scale, alpha, - ) - .into_iter() - .map(C::from) - .collect() + p.window.push_popup_render_elements( + renderer, + window_loc, + scale, + alpha, + p.appearance_conf.lock().unwrap().blur_strength as usize, + &mut |elem| push(elem.into()), + ) }) } @@ -434,7 +433,7 @@ impl CosmicWindow { }) } - pub fn render_elements( + pub fn push_render_elements( &self, renderer: &mut R, location: Point, @@ -442,11 +441,11 @@ impl CosmicWindow { scale: Scale, alpha: f32, scanout_override: Option, - ) -> Vec - where + push_above: &mut dyn FnMut(CosmicWindowRenderElement), + push_below: &mut dyn FnMut(CosmicWindowRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - C: From>, { let (has_ssd, is_tiled, is_maximized, mut radii, appearance) = self.0.with_program(|p| { ( @@ -483,8 +482,6 @@ impl CosmicWindow { location }; - let mut elements = Vec::new(); - let (mut geo, bg_divider) = self.0.with_program(|p| { ( SpaceElement::geometry(&p.window).to_f64(), @@ -514,39 +511,27 @@ impl CosmicWindow { scale.x, [r, g, b], )); - elements.push(elem); - } - - let window_elements = self.0.with_program(|p| { - p.window - .render_elements::>( - renderer, - window_loc, - scale, - alpha, - scanout_override, - ) - }); - if window_elements.is_empty() { - return Vec::new(); + push_above(elem); } - elements.extend(window_elements.into_iter().map(|elem| { + self.0.with_program(|p| { if has_ssd { radii[1] = 0; radii[3] = 0; } - if radii.iter().any(|x| *x != 0) - && clip - && ClippedSurfaceRenderElement::will_clip(&elem, scale, geo, radii) - { - CosmicWindowRenderElement::Clipped(ClippedSurfaceRenderElement::new( - renderer, elem, scale, geo, radii, - )) - } else { - CosmicWindowRenderElement::Window(elem) - } - })); + p.window.push_render_elements( + renderer, + window_loc, + scale, + alpha, + scanout_override, + clip, + radii, + appearance.blur_strength as usize, + &mut |elem| push_above(elem.into()), + Some(&mut |elem| push_below(elem.into())), + ) + }); if has_ssd { let ssd_loc = location @@ -554,12 +539,11 @@ impl CosmicWindow { .0 .with_program(|p| p.window.geometry().loc) .to_physical_precise_round(scale); - elements.extend(AsRenderElements::::render_elements::< - CosmicWindowRenderElement, - >(&self.0, renderer, ssd_loc, scale, alpha)) + self.0 + .push_render_elements(renderer, ssd_loc, scale, alpha, &mut |elem| { + push_above(elem.into()) + }); } - - elements.into_iter().map(C::from).collect() } pub(crate) fn set_theme(&self, theme: cosmic::Theme) { @@ -1211,8 +1195,7 @@ pub enum CosmicWindowRenderElement { Header(MemoryRenderBufferRenderElement), Shadow(PixelShaderElement), Border(PixelShaderElement), - Window(WaylandSurfaceRenderElement), - Clipped(ClippedSurfaceRenderElement), + Window(SurfaceRenderElement), } impl From> @@ -1223,25 +1206,18 @@ impl From From> +impl From> for CosmicWindowRenderElement { - fn from(value: WaylandSurfaceRenderElement) -> Self { + fn from(value: SurfaceRenderElement) -> Self { Self::Window(value) } } -impl From> - for CosmicWindowRenderElement -{ - fn from(value: ClippedSurfaceRenderElement) -> Self { - Self::Clipped(value) - } -} - impl Element for CosmicWindowRenderElement where - R: Renderer + ImportAll + ImportMem, + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + R::TextureId: 'static, { fn id(&self) -> &RendererId { match self { @@ -1249,7 +1225,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.id(), CosmicWindowRenderElement::Border(elem) => elem.id(), CosmicWindowRenderElement::Window(elem) => elem.id(), - CosmicWindowRenderElement::Clipped(elem) => elem.id(), } } @@ -1259,7 +1234,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.current_commit(), CosmicWindowRenderElement::Border(elem) => elem.current_commit(), CosmicWindowRenderElement::Window(elem) => elem.current_commit(), - CosmicWindowRenderElement::Clipped(elem) => elem.current_commit(), } } @@ -1269,7 +1243,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.src(), CosmicWindowRenderElement::Border(elem) => elem.src(), CosmicWindowRenderElement::Window(elem) => elem.src(), - CosmicWindowRenderElement::Clipped(elem) => elem.src(), } } @@ -1279,7 +1252,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.geometry(scale), CosmicWindowRenderElement::Border(elem) => elem.geometry(scale), CosmicWindowRenderElement::Window(elem) => elem.geometry(scale), - CosmicWindowRenderElement::Clipped(elem) => elem.geometry(scale), } } @@ -1289,7 +1261,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.location(scale), CosmicWindowRenderElement::Border(elem) => elem.location(scale), CosmicWindowRenderElement::Window(elem) => elem.location(scale), - CosmicWindowRenderElement::Clipped(elem) => elem.location(scale), } } @@ -1299,7 +1270,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.transform(), CosmicWindowRenderElement::Border(elem) => elem.transform(), CosmicWindowRenderElement::Window(elem) => elem.transform(), - CosmicWindowRenderElement::Clipped(elem) => elem.transform(), } } @@ -1313,7 +1283,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.damage_since(scale, commit), CosmicWindowRenderElement::Border(elem) => elem.damage_since(scale, commit), CosmicWindowRenderElement::Window(elem) => elem.damage_since(scale, commit), - CosmicWindowRenderElement::Clipped(elem) => elem.damage_since(scale, commit), } } @@ -1323,7 +1292,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.opaque_regions(scale), CosmicWindowRenderElement::Border(elem) => elem.opaque_regions(scale), CosmicWindowRenderElement::Window(elem) => elem.opaque_regions(scale), - CosmicWindowRenderElement::Clipped(elem) => elem.opaque_regions(scale), } } @@ -1333,7 +1301,6 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.alpha(), CosmicWindowRenderElement::Border(elem) => elem.alpha(), CosmicWindowRenderElement::Window(elem) => elem.alpha(), - CosmicWindowRenderElement::Clipped(elem) => elem.alpha(), } } @@ -1343,7 +1310,15 @@ where CosmicWindowRenderElement::Shadow(elem) => elem.kind(), CosmicWindowRenderElement::Border(elem) => elem.kind(), CosmicWindowRenderElement::Window(elem) => elem.kind(), - CosmicWindowRenderElement::Clipped(elem) => elem.kind(), + } + } + + fn is_framebuffer_effect(&self) -> bool { + match self { + CosmicWindowRenderElement::Header(elem) => elem.is_framebuffer_effect(), + CosmicWindowRenderElement::Shadow(elem) => elem.is_framebuffer_effect(), + CosmicWindowRenderElement::Border(elem) => elem.is_framebuffer_effect(), + CosmicWindowRenderElement::Window(elem) => elem.is_framebuffer_effect(), } } } @@ -1352,7 +1327,6 @@ impl RenderElement for CosmicWindowRenderElement where R: Renderer + AsGlowRenderer + ImportAll + ImportMem, R::TextureId: 'static, - R::Error: FromGlesError, { fn draw( &self, @@ -1361,10 +1335,11 @@ where dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + cache: Option<&UserDataMap>, ) -> Result<(), ::Error> { match self { CosmicWindowRenderElement::Header(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicWindowRenderElement::Shadow(elem) | CosmicWindowRenderElement::Border(elem) => { RenderElement::::draw( @@ -1374,14 +1349,12 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error) + .map_err(R::from_gles_error) } CosmicWindowRenderElement::Window(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) - } - CosmicWindowRenderElement::Clipped(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } } } @@ -1393,7 +1366,33 @@ where elem.underlying_storage(renderer.glow_renderer_mut()) } CosmicWindowRenderElement::Window(elem) => elem.underlying_storage(renderer), - CosmicWindowRenderElement::Clipped(elem) => elem.underlying_storage(renderer), + } + } + + fn capture_framebuffer( + &self, + frame: &mut ::Frame<'_, '_>, + src: Rectangle, + dst: Rectangle, + cache: &UserDataMap, + ) -> Result<(), ::Error> { + match self { + CosmicWindowRenderElement::Header(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + CosmicWindowRenderElement::Shadow(elem) | CosmicWindowRenderElement::Border(elem) => { + RenderElement::::capture_framebuffer( + elem, + R::glow_frame_mut(frame), + src, + dst, + cache, + ) + .map_err(R::from_gles_error) + } + CosmicWindowRenderElement::Window(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } } } } diff --git a/src/shell/focus/order.rs b/src/shell/focus/order.rs index 81f23c627..f9efb5854 100644 --- a/src/shell/focus/order.rs +++ b/src/shell/focus/order.rs @@ -32,10 +32,12 @@ pub enum Stage<'a> { layer: LayerSurface, popup: &'a PopupKind, location: Point, + workspace_idx: usize, }, LayerSurface { layer: LayerSurface, location: Point, + workspace_idx: usize, }, OverrideRedirect { surface: &'a X11Surface, @@ -95,10 +97,15 @@ fn render_input_order_internal( layer, popup: &popup, location, + workspace_idx: current.1, })?; } for (layer, location) in layer_surfaces(output, Layer::Overlay, element_filter) { - callback(Stage::LayerSurface { layer, location })?; + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; } // calculate a bunch of stuff for workspace transitions @@ -187,7 +194,7 @@ fn render_input_order_internal( }); ( - Some((previous, has_fullscreen, offset)), + Some((previous, previous_idx, has_fullscreen, offset)), Point::::from(match (layout, forward) { (WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y), (WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)), @@ -206,6 +213,7 @@ fn render_input_order_internal( layer, popup: &popup, location, + workspace_idx: current.1, })?; } } @@ -238,7 +246,7 @@ fn render_input_order_internal( if element_filter != ElementFilter::LayerShellOnly { // previous workspace popups - if let Some((previous_handle, _, offset)) = previous.as_ref() { + if let Some((previous_handle, _, _, offset)) = previous.as_ref() { let Some(workspace) = shell.workspaces.space_for_handle(previous_handle) else { return ControlFlow::Break(Err(OutputNoMode)); }; @@ -267,11 +275,12 @@ fn render_input_order_internal( layer, popup: &popup, location, + workspace_idx: current.1, })?; } } - if let Some((_, has_fullscreen, offset)) = previous.as_ref() { + if let Some((_, idx, has_fullscreen, offset)) = previous.as_ref() { if !has_fullscreen { // previous bottom layer popups for (layer, popup, location) in layer_popups(output, Layer::Bottom, element_filter) { @@ -279,6 +288,7 @@ fn render_input_order_internal( layer, popup: &popup, location: location + offset.as_global(), + workspace_idx: **idx, })?; } } @@ -291,11 +301,12 @@ fn render_input_order_internal( layer, popup: &popup, location, + workspace_idx: current.1, })?; } } - if let Some((_, has_fullscreen, offset)) = previous.as_ref() { + if let Some((_, idx, has_fullscreen, offset)) = previous.as_ref() { if !has_fullscreen { // previous background layer popups for (layer, popup, location) in layer_popups(output, Layer::Background, element_filter) @@ -304,6 +315,7 @@ fn render_input_order_internal( layer, popup: &popup, location: location + offset.as_global(), + workspace_idx: **idx, })?; } } @@ -312,7 +324,11 @@ fn render_input_order_internal( if !has_focused_fullscreen { // top-layer shell for (layer, location) in layer_surfaces(output, Layer::Top, element_filter) { - callback(Stage::LayerSurface { layer, location })?; + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; } // sticky windows @@ -329,7 +345,7 @@ fn render_input_order_internal( })?; // previous workspace windows - if let Some((previous_handle, _, offset)) = previous.as_ref() { + if let Some((previous_handle, _, _, offset)) = previous.as_ref() { let Some(workspace) = shell.workspaces.space_for_handle(previous_handle) else { return ControlFlow::Break(Err(OutputNoMode)); }; @@ -344,16 +360,24 @@ fn render_input_order_internal( // bottom layer for (layer, mut location) in layer_surfaces(output, Layer::Bottom, element_filter) { location += current_offset.as_global(); - callback(Stage::LayerSurface { layer, location })?; + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; } } - if let Some((_, has_fullscreen, offset)) = previous.as_ref() { + if let Some((_, idx, has_fullscreen, offset)) = previous.as_ref() { if !has_fullscreen { // previous bottom layer for (layer, mut location) in layer_surfaces(output, Layer::Bottom, element_filter) { location += offset.as_global(); - callback(Stage::LayerSurface { layer, location })?; + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: **idx, + })?; } } } @@ -362,16 +386,24 @@ fn render_input_order_internal( // background layer for (layer, mut location) in layer_surfaces(output, Layer::Background, element_filter) { location += current_offset.as_global(); - callback(Stage::LayerSurface { layer, location })?; + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; } } - if let Some((_, has_fullscreen, offset)) = previous.as_ref() { + if let Some((_, idx, has_fullscreen, offset)) = previous.as_ref() { if !has_fullscreen { // previous background layer for (layer, mut location) in layer_surfaces(output, Layer::Background, element_filter) { location += offset.as_global(); - callback(Stage::LayerSurface { layer, location })?; + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: **idx, + })?; } } } diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index 53325f81a..6ac73d644 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -18,10 +18,7 @@ use cosmic::{ use smithay::{ backend::{ input::{ButtonState, TouchSlot}, - renderer::{ - ImportMem, Renderer, - element::{AsRenderElements, memory::MemoryRenderBufferRenderElement}, - }, + renderer::{ImportMem, Renderer, element::memory::MemoryRenderBufferRenderElement}, }, desktop::space::SpaceElement, input::{ @@ -65,29 +62,28 @@ pub struct MenuGrabState { pub type SeatMenuGrabState = Mutex>; impl MenuGrabState { - pub fn render(&self, renderer: &mut R, output: &Output) -> Vec - where + pub fn render( + &self, + renderer: &mut R, + output: &Output, + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where R: Renderer + ImportMem, R::TextureId: Send + Clone + 'static, - I: From>, { let scale = output.current_scale().fractional_scale(); - self.elements - .lock() - .unwrap() - .iter() - .flat_map(|elem| { - elem.iced.render_elements( - renderer, - elem.position - .to_local(output) - .as_logical() - .to_physical_precise_round(scale), - scale.into(), - 1.0, - ) - }) - .collect() + for elem in self.elements.lock().unwrap().iter() { + elem.iced.push_render_elements( + renderer, + elem.position + .to_local(output) + .as_logical() + .to_physical_precise_round(scale), + scale.into(), + 1.0, + push, + ) + } } pub fn is_in_screen_space(&self) -> bool { diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 8b01d086a..6f797e9f1 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -19,12 +19,13 @@ use crate::{ use calloop::LoopHandle; use cosmic::theme::CosmicTheme; +use smallvec::SmallVec; use smithay::{ backend::{ input::ButtonState, renderer::{ ImportAll, ImportMem, Renderer, - element::{AsRenderElements, RenderElement, utils::RescaleRenderElement}, + element::{RenderElement, utils::RescaleRenderElement}, }, }, desktop::{WindowSurfaceType, layer_map_for_output, space::SpaceElement}, @@ -68,12 +69,16 @@ pub struct MoveGrabState { impl MoveGrabState { #[profiling::function] - pub fn render(&self, renderer: &mut R, output: &Output, theme: &CosmicTheme) -> Vec - where + pub fn render( + &self, + renderer: &mut R, + output: &Output, + theme: &CosmicTheme, + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, - I: From>, { let scale = if self.previous == ManagedLayer::Tiling { 0.6 + ((1.0 @@ -98,7 +103,7 @@ impl MoveGrabState { .intersection(window_geo) .is_none() { - return Vec::new(); + return; } let output_scale: Scale = output.current_scale().fractional_scale().into(); @@ -108,13 +113,31 @@ impl MoveGrabState { + self.window_offset - scaling_offset; + for (indicator, location) in self.stacking_indicator.iter() { + indicator.push_render_elements( + renderer, + location.to_physical_precise_round(output_scale), + output_scale, + 1.0, + &mut |elem| push(elem.into()), + ); + } + + self.window.push_popup_render_elements::( + renderer, + (render_location - self.window.geometry().loc).to_physical_precise_round(output_scale), + output_scale, + alpha, + push, + ); + let active_window_hint = crate::theme::active_window_hint(theme); let radius = self .element() .corner_radius(window_geo.size, self.indicator_thickness); - let focus_element = if self.indicator_thickness > 0 { - Some(CosmicMappedRenderElement::from( + if self.indicator_thickness > 0 { + push( IndicatorShader::focus_element( renderer, Key::Window(Usage::MoveGrabIndicator, self.window.key()), @@ -137,131 +160,104 @@ impl MoveGrabState { active_window_hint.green, active_window_hint.blue, ], - ), - )) - } else { - None - }; - - let non_exclusive_geometry = { - let layers = layer_map_for_output(output); - layers.non_exclusive_zone() - }; - - let gaps = (theme.gaps.0 as i32, theme.gaps.1 as i32); - let thickness = self.indicator_thickness.max(1); + ) + .into(), + ) + } - let snapping_indicator = match &self.snapping_zone { - Some(t) if &self.cursor_output == output => { - let base_color = theme.palette.neutral_9; - let overlay_geometry = t.overlay_geometry(non_exclusive_geometry, gaps); - vec![ - CosmicMappedRenderElement::from(IndicatorShader::element( - renderer, - Key::Window(Usage::SnappingIndicator, self.window.key()), - overlay_geometry, - thickness, - [ - theme.radius_s()[0] as u8, - theme.radius_s()[1] as u8, - theme.radius_s()[2] as u8, - theme.radius_s()[3] as u8, - ], - 1.0, - output_scale.x, - [ - active_window_hint.red, - active_window_hint.green, - active_window_hint.blue, - ], - )), - CosmicMappedRenderElement::from(BackdropShader::element( - renderer, - Key::Window(Usage::SnappingIndicator, self.window.key()), - t.overlay_geometry(non_exclusive_geometry, gaps), - theme.radius_s()[0], // TODO: Fix once shaders support 4 corner radii customization - 0.4, - [base_color.red, base_color.green, base_color.blue], - )), - ] + let map_window_element = |elem| match elem { + CosmicMappedRenderElement::Stack(stack) => { + CosmicMappedRenderElement::GrabbedStack(RescaleRenderElement::from_element( + stack, + render_location + .to_physical_precise_round(output.current_scale().fractional_scale()), + scale, + )) + } + CosmicMappedRenderElement::Window(window) => { + CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element( + window, + render_location + .to_physical_precise_round(output.current_scale().fractional_scale()), + scale, + )) } - _ => vec![], + x => x, }; - let w_elements = self - .window - .render_elements::>( - renderer, - (render_location - self.window.geometry().loc) - .to_physical_precise_round(output_scale), - None, - output_scale, - alpha, - Some(false), - ); - let p_elements = self - .window - .popup_render_elements::>( - renderer, - (render_location - self.window.geometry().loc) - .to_physical_precise_round(output_scale), - output_scale, - alpha, - ); - let shadow_element = self.window.shadow_render_element( + let mut lower_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + self.window.push_render_elements( renderer, (render_location - self.window.geometry().loc).to_physical_precise_round(output_scale), None, output_scale, - scale, alpha, + Some(false), + &mut |elem| push(map_window_element(elem)), + &mut |elem| lower_elements.push(map_window_element(elem)), ); + if let Some(shadow_element) = self.window.shadow_render_element( + renderer, + (render_location - self.window.geometry().loc).to_physical_precise_round(output_scale), + None, + output_scale, + scale, + alpha, + ) { + push(shadow_element); + } + for elem in lower_elements.into_iter() { + push(elem); + } + + let non_exclusive_geometry = { + let layers = layer_map_for_output(output); + layers.non_exclusive_zone() + }; + + let gaps = (theme.gaps.0 as i32, theme.gaps.1 as i32); + let thickness = self.indicator_thickness.max(1); - self.stacking_indicator - .iter() - .flat_map(|(indicator, location)| { - indicator.render_elements( + if let Some(t) = &self.snapping_zone + && &self.cursor_output == output + { + let base_color = theme.palette.neutral_9; + let overlay_geometry = t.overlay_geometry(non_exclusive_geometry, gaps); + + push( + IndicatorShader::element( renderer, - location.to_physical_precise_round(output_scale), - output_scale, + Key::Window(Usage::SnappingIndicator, self.window.key()), + overlay_geometry, + thickness, + [ + theme.radius_s()[0] as u8, + theme.radius_s()[1] as u8, + theme.radius_s()[2] as u8, + theme.radius_s()[3] as u8, + ], 1.0, + output_scale.x, + [ + active_window_hint.red, + active_window_hint.green, + active_window_hint.blue, + ], ) - }) - .chain(p_elements) - .chain(focus_element) - .chain( - w_elements - .into_iter() - .chain(shadow_element) - .map(|elem| match elem { - CosmicMappedRenderElement::Stack(stack) => { - CosmicMappedRenderElement::GrabbedStack( - RescaleRenderElement::from_element( - stack, - render_location.to_physical_precise_round( - output.current_scale().fractional_scale(), - ), - scale, - ), - ) - } - CosmicMappedRenderElement::Window(window) => { - CosmicMappedRenderElement::GrabbedWindow( - RescaleRenderElement::from_element( - window, - render_location.to_physical_precise_round( - output.current_scale().fractional_scale(), - ), - scale, - ), - ) - } - x => x, - }), + .into(), + ); + push( + BackdropShader::element( + renderer, + Key::Window(Usage::SnappingIndicator, self.window.key()), + t.overlay_geometry(non_exclusive_geometry, gaps), + theme.radius_s()[0], // TODO: Fix once shaders support 4 corner radii customization + 0.4, + [base_color.red, base_color.green, base_color.blue], + ) + .into(), ) - .chain(snapping_indicator) - .map(I::from) - .collect() + } } pub fn element(&self) -> CosmicMapped { diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 582ec1b47..4f78f9e9b 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -9,11 +9,12 @@ use std::{ use cosmic_comp_config::AppearanceConfig; use cosmic_settings_config::shortcuts::action::ResizeDirection; use keyframe::{ease, functions::EaseInOutCubic}; +use smallvec::SmallVec; use smithay::{ backend::renderer::{ ImportAll, ImportMem, Renderer, element::{ - AsRenderElements, RenderElement, + RenderElement, utils::{Relocate, RelocateRenderElement, RescaleRenderElement}, }, }, @@ -1419,8 +1420,8 @@ impl FloatingLayout { &self, renderer: &mut R, alpha: f32, - ) -> Vec> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1430,8 +1431,6 @@ impl FloatingLayout { let output = self.space.outputs().next().unwrap(); let output_scale = output.current_scale().fractional_scale(); - let mut elements = Vec::default(); - for elem in self .animations .iter() @@ -1446,19 +1445,16 @@ impl FloatingLayout { .unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha)); let render_location = geometry.loc - elem.geometry().loc.as_local(); - elements.extend( - elem.popup_render_elements( - renderer, - render_location - .as_logical() - .to_physical_precise_round(output_scale), - output_scale.into(), - alpha, - ), + elem.push_popup_render_elements( + renderer, + render_location + .as_logical() + .to_physical_precise_round(output_scale), + output_scale.into(), + alpha, + push, ); } - - elements } #[profiling::function] @@ -1470,8 +1466,8 @@ impl FloatingLayout { indicator_thickness: u8, alpha: f32, theme: &cosmic::theme::CosmicTheme, - ) -> Vec> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1484,8 +1480,7 @@ impl FloatingLayout { layers.non_exclusive_zone() }; let output_scale = output.current_scale().fractional_scale(); - - let mut elements = Vec::default(); + let mut lower_elements = SmallVec::<[_; 4]>::new_const(); for elem in self .animations @@ -1499,121 +1494,9 @@ impl FloatingLayout { .get(elem) .map(|anim| (*anim.previous_geometry(), alpha * anim.alpha())) .unwrap_or_else(|| (self.space.element_geometry(elem).unwrap().as_local(), alpha)); - let render_location = geometry.loc - elem.geometry().loc.as_local(); - let mut window_elements = elem.render_elements( - renderer, - render_location - .as_logical() - .to_physical_precise_round(output_scale), - None, - output_scale.into(), - alpha, - None, - ); - window_elements.extend( - elem.shadow_render_element( - renderer, - render_location - .as_logical() - .to_physical_precise_round(output_scale), - None, - output_scale.into(), - 1., - alpha, - ), - ); - - if let Some(anim) = self.animations.get(elem) { - let original_geo = anim.previous_geometry(); - geometry = anim.geometry( - output_geometry, - self.space - .element_geometry(elem) - .map(RectExt::as_local) - .unwrap_or(geometry), - elem.floating_tiled.lock().unwrap().as_ref(), - self.gaps(), - ); - - let buffer_size = elem.geometry().size; - let scale = Scale { - x: geometry.size.w as f64 / buffer_size.w as f64, - y: geometry.size.h as f64 / buffer_size.h as f64, - }; - - window_elements = window_elements - .into_iter() - .map(|element| match element { - CosmicMappedRenderElement::Stack(elem) => { - CosmicMappedRenderElement::MovingStack({ - let rescaled = RescaleRenderElement::from_element( - elem, - original_geo - .loc - .as_logical() - .to_physical_precise_round(output_scale), - scale, - ); - - RelocateRenderElement::from_element( - rescaled, - (geometry.loc - original_geo.loc) - .as_logical() - .to_physical_precise_round(output_scale), - Relocate::Relative, - ) - }) - } - CosmicMappedRenderElement::Window(elem) => { - CosmicMappedRenderElement::MovingWindow({ - let rescaled = RescaleRenderElement::from_element( - elem, - original_geo - .loc - .as_logical() - .to_physical_precise_round(output_scale), - scale, - ); - - RelocateRenderElement::from_element( - rescaled, - (geometry.loc - original_geo.loc) - .as_logical() - .to_physical_precise_round(output_scale), - Relocate::Relative, - ) - }) - } - x => x, - }) - .collect(); - } if focused == Some(elem) && !elem.is_maximized(false) { - if let Some((mode, resize)) = resize_indicator.as_mut() { - let mut resize_geometry = geometry; - resize_geometry.loc -= (18, 18).into(); - resize_geometry.size += (36, 36).into(); - - resize.resize(resize_geometry.size.as_logical()); - resize.output_enter(output, Rectangle::default() /* unused */); - window_elements = resize - .render_elements::>( - renderer, - resize_geometry - .loc - .as_logical() - .to_physical_precise_round(output_scale), - output_scale.into(), - alpha * mode.alpha().unwrap_or(1.0), - ) - .into_iter() - .map(CosmicMappedRenderElement::Window) - .chain(window_elements.into_iter()) - .collect(); - } - let active_window_hint = crate::theme::active_window_hint(theme); let radius = elem.corner_radius(geometry.size.as_logical(), indicator_thickness); if indicator_thickness > 0 { @@ -1631,14 +1514,129 @@ impl FloatingLayout { active_window_hint.blue, ], ); - window_elements.insert(0, element.into()); + push(element.into()); + } + + if let Some((mode, resize)) = resize_indicator.as_mut() { + let mut resize_geometry = geometry; + resize_geometry.loc -= (18, 18).into(); + resize_geometry.size += (36, 36).into(); + + resize.resize(resize_geometry.size.as_logical()); + resize.output_enter(output, Rectangle::default() /* unused */); + resize.push_render_elements( + renderer, + resize_geometry + .loc + .as_logical() + .to_physical_precise_round(output_scale), + output_scale.into(), + alpha * mode.alpha().unwrap_or(1.0), + &mut |elem| push(CosmicMappedRenderElement::Window(elem.into())), + ); } } - elements.extend(window_elements); - } + let maybe_map = if let Some(anim) = self.animations.get(elem) { + let original_geo = anim.previous_geometry(); + geometry = anim.geometry( + output_geometry, + self.space + .element_geometry(elem) + .map(RectExt::as_local) + .unwrap_or(geometry), + elem.floating_tiled.lock().unwrap().as_ref(), + self.gaps(), + ); + + let buffer_size = elem.geometry().size; + let scale = Scale { + x: geometry.size.w as f64 / buffer_size.w as f64, + y: geometry.size.h as f64 / buffer_size.h as f64, + }; + + Some(move |element| match element { + CosmicMappedRenderElement::Stack(elem) => { + CosmicMappedRenderElement::MovingStack({ + let rescaled = RescaleRenderElement::from_element( + elem, + original_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale), + scale, + ); + + RelocateRenderElement::from_element( + rescaled, + (geometry.loc - original_geo.loc) + .as_logical() + .to_physical_precise_round(output_scale), + Relocate::Relative, + ) + }) + } + CosmicMappedRenderElement::Window(elem) => { + CosmicMappedRenderElement::MovingWindow({ + let rescaled = RescaleRenderElement::from_element( + elem, + original_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale), + scale, + ); + + RelocateRenderElement::from_element( + rescaled, + (geometry.loc - original_geo.loc) + .as_logical() + .to_physical_precise_round(output_scale), + Relocate::Relative, + ) + }) + } + x => x, + }) + } else { + None + }; + let map_anim = |elem| { + if let Some(map) = maybe_map { + map(elem) + } else { + elem + } + }; - elements + elem.push_render_elements( + renderer, + render_location + .as_logical() + .to_physical_precise_round(output_scale), + None, + output_scale.into(), + alpha, + None, + &mut |elem| push(map_anim(elem)), + &mut |elem| lower_elements.push(map_anim(elem)), + ); + if let Some(shadow_element) = elem.shadow_render_element( + renderer, + render_location + .as_logical() + .to_physical_precise_round(output_scale), + None, + output_scale.into(), + 1., + alpha, + ) { + push(map_anim(shadow_element)); + } + for elem in lower_elements.drain(..) { + push(elem); + } + } } pub fn snap_to_corner(&self, mapped: &CosmicMapped, corners: &TiledCorners) { diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 85efb2ceb..694476a6e 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -6,8 +6,7 @@ use crate::{ element::AsGlowRenderer, }, shell::{ - CosmicSurface, Direction, FocusResult, MoveResult, OutputNotMapped, OverviewMode, - ResizeMode, Trigger, + CosmicSurface, Direction, FocusResult, MoveResult, OverviewMode, ResizeMode, Trigger, element::{ CosmicMapped, CosmicMappedRenderElement, CosmicStack, CosmicWindow, resize_indicator::ResizeIndicator, @@ -45,11 +44,12 @@ use keyframe::{ ease, functions::{EaseInOutCubic, Linear}, }; +use smallvec::SmallVec; use smithay::{ backend::renderer::{ ImportAll, ImportMem, Renderer, element::{ - AsRenderElements, Id, RenderElement, + Id, RenderElement, utils::{ ConstrainAlign, ConstrainScaleBehavior, RescaleRenderElement, constrain_render_elements, @@ -3423,8 +3423,8 @@ impl TilingLayout { None, None, self.theme.cosmic(), - ) - .0; + &mut |_| {}, + ); let mut result = None; let mut lookup = Some(root.clone()); @@ -4009,8 +4009,8 @@ impl TilingLayout { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &cosmic::theme::CosmicTheme, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -4050,8 +4050,6 @@ impl TilingLayout { }; let draw_groups = overview.0.alpha(); - let mut elements = Vec::default(); - let is_overview = !matches!(overview.0, OverviewMode::None); let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); @@ -4063,7 +4061,7 @@ impl TilingLayout { // all gone windows and fade them out let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() { - let (geometries, _) = if let Some(transition) = draw_groups { + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( reference_tree, &mut *renderer, @@ -4078,14 +4076,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |_elem| {}, )) } else { None - } - .unzip(); + }; // all old windows we want to fade out - elements.extend(render_old_tree_windows( + render_old_tree_windows( reference_tree, target_tree, renderer, @@ -4095,14 +4093,16 @@ impl TilingLayout { indicator_thickness, swap_desc.is_some(), theme, - )); + push, + ); geometries } else { None }; - let (geometries, group_elements) = if let Some(transition) = draw_groups { + let mut group_elements = SmallVec::<[_; 4]>::new_const(); + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( target_tree, &mut *renderer, @@ -4116,14 +4116,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |elem| group_elements.push(elem), )) } else { None - } - .unzip(); + }; // all alive windows - elements.extend(render_new_tree_windows( + render_new_tree_windows( target_tree, reference_tree, renderer, @@ -4151,14 +4151,13 @@ impl TilingLayout { &self.swapping_stack_surface_id, &self.backdrop_id, theme, - )); + push, + ); // tiling hints - if let Some(group_elements) = group_elements { - elements.extend(group_elements); + for elem in group_elements.into_iter() { + push(elem); } - - Ok(elements) } #[profiling::function] @@ -4169,8 +4168,8 @@ impl TilingLayout { non_exclusive_zone: Rectangle, overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), theme: &cosmic::theme::CosmicTheme, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(CosmicMappedRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -4202,8 +4201,6 @@ impl TilingLayout { }; let draw_groups = overview.0.alpha(); - let mut elements = Vec::default(); - let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() { @@ -4214,7 +4211,7 @@ impl TilingLayout { // all gone windows and fade them out let old_geometries = if let Some(reference_tree) = reference_tree.as_ref() { - let (geometries, _) = if let Some(transition) = draw_groups { + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( reference_tree, &mut *renderer, @@ -4229,14 +4226,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |_| {}, )) } else { None - } - .unzip(); + }; // all old windows we want to fade out - elements.extend(render_old_tree_popups( + render_old_tree_popups( reference_tree, target_tree, renderer, @@ -4244,14 +4241,15 @@ impl TilingLayout { output_scale, percentage, swap_desc.is_some(), - )); + push, + ); geometries } else { None }; - let (geometries, _) = if let Some(transition) = draw_groups { + let geometries = if let Some(transition) = draw_groups { Some(geometries_for_groupview( target_tree, &mut *renderer, @@ -4265,14 +4263,14 @@ impl TilingLayout { swap_desc.clone(), overview.1.as_ref().and_then(|(_, tree)| *tree), theme, + &mut |_| {}, )) } else { None - } - .unzip(); + }; // all alive windows - elements.extend(render_new_tree_popups( + render_new_tree_popups( target_tree, reference_tree, renderer, @@ -4283,9 +4281,8 @@ impl TilingLayout { percentage, overview, swap_desc.clone(), - )); - - Ok(elements) + push, + ); } fn gaps(&self) -> (i32, i32) { @@ -4340,10 +4337,8 @@ fn geometries_for_groupview<'a, R>( swap_desc: Option, swap_tree: Option<&Tree>, _theme: &cosmic::theme::CosmicTheme, -) -> ( - HashMap>, - Vec>, -) + push: &mut dyn FnMut(CosmicMappedRenderElement), +) -> HashMap> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer + 'a, R::TextureId: 'static, @@ -4366,11 +4361,18 @@ where // push bogos value, that will get ignored anyway stack.push((Rectangle::from_size((320, 240).into()), 0)); } - if root.is_some() { + + let has_root = root.is_some(); + if has_root { stack.push((non_exclusive_zone, 0)); } - let mut elements = Vec::new(); + let mut push = |elem| { + if has_root { + push(elem) + } + }; + let mut geometries: HashMap> = HashMap::new(); let alpha = alpha * transition; @@ -4525,7 +4527,7 @@ where if let Some(renderer) = renderer.as_mut() { if (render_potential_group || render_active_child) && Some(&node_id) != root { - elements.push( + push( IndicatorShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4543,7 +4545,7 @@ where && pill_indicator.is_some() && Some(&node_id) != root { - elements.push( + push( IndicatorShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4607,7 +4609,7 @@ where }; if draw_outline { - elements.push( + push( IndicatorShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4667,7 +4669,7 @@ where }; if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, backdrop_id.clone(), @@ -4686,7 +4688,7 @@ where if matches!(swap_desc, Some(ref desc) if desc.node == node_id) { if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, Key::Group(Arc::downgrade(alive)), @@ -4770,7 +4772,7 @@ where .unwrap_or(false) { if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, backdrop_id.clone(), @@ -4812,7 +4814,7 @@ where .unwrap_or(false) { if let Some(renderer) = renderer.as_mut() { - elements.push( + push( BackdropShader::element( *renderer, backdrop_id.clone(), @@ -4844,7 +4846,7 @@ where if let Some(renderer) = renderer.as_mut() { if render_potential_group { - elements.push( + push( IndicatorShader::element( *renderer, Key::Window(Usage::PotentialGroupIndicator, mapped.key()), @@ -4884,7 +4886,7 @@ where geo.loc += (WINDOW_BACKDROP_BORDER, WINDOW_BACKDROP_BORDER).into(); geo.size -= (WINDOW_BACKDROP_BORDER * 2, WINDOW_BACKDROP_BORDER * 2).into(); - elements.push( + push( BackdropShader::element( *renderer, Key::Window(Usage::OverviewBackdrop, mapped.key()), @@ -4941,7 +4943,7 @@ where if let Some(renderer) = renderer.as_mut() { geo.loc += (WINDOW_BACKDROP_BORDER, WINDOW_BACKDROP_BORDER).into(); geo.size -= (WINDOW_BACKDROP_BORDER * 2, WINDOW_BACKDROP_BORDER * 2).into(); - elements.push( + push( BackdropShader::element( *renderer, id.clone(), @@ -4960,11 +4962,7 @@ where } } - if root.is_none() { - elements.clear(); - } - - (geometries, elements) + geometries } fn render_old_tree_popups( @@ -4975,16 +4973,14 @@ fn render_old_tree_popups( output_scale: f64, percentage: f32, is_swap_mode: bool, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, CosmicWindowRenderElement: RenderElement, CosmicStackRenderElement: RenderElement, { - let mut elements = Vec::default(); - render_old_tree( reference_tree, target_tree, @@ -4993,19 +4989,15 @@ where percentage, is_swap_mode, |mapped, elem_geometry, geo, alpha, _| { - elements.extend( - mapped.popup_render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - Scale::from(output_scale), - alpha, - ), - ); + mapped.push_popup_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + Scale::from(output_scale), + alpha, + push, + ) }, - ); - - elements + ) } fn render_old_tree_windows( @@ -5018,8 +5010,8 @@ fn render_old_tree_windows( indicator_thickness: u8, is_swap_mode: bool, theme: &cosmic::theme::CosmicTheme, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -5027,8 +5019,35 @@ where CosmicStackRenderElement: RenderElement, { let window_hint = crate::theme::active_window_hint(theme); - let mut elements = Vec::default(); - let mut shadow_elements = Vec::default(); + let mut lower_elements = Vec::default(); + let mut shadow_elements = SmallVec::<[_; 4]>::new_const(); + + let window_map = + |elem, geo: Rectangle, elem_geometry: Rectangle| match elem { + CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( + std::iter::once(elem), + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + geo.as_logical().to_physical_precise_round(output_scale), + elem_geometry, + ConstrainScaleBehavior::Stretch, + ConstrainAlign::CENTER, + output_scale, + ) + .next() + .map(CosmicMappedRenderElement::TiledStack), + CosmicMappedRenderElement::Window(elem) => constrain_render_elements( + std::iter::once(elem), + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + geo.as_logical().to_physical_precise_round(output_scale), + elem_geometry, + ConstrainScaleBehavior::Stretch, + ConstrainAlign::CENTER, + output_scale, + ) + .next() + .map(CosmicMappedRenderElement::TiledWindow), + x => Some(x), + }; render_old_tree( reference_tree, @@ -5038,56 +5057,9 @@ where percentage, is_swap_mode, |mapped, elem_geometry, geo, alpha, is_minimizing| { - shadow_elements.extend(mapped.shadow_render_element( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, - Some(geo.size.as_logical()), - Scale::from(output_scale), - 1., - alpha, - )); - - let window_elements = mapped.render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, - Some(geo.size.as_logical()), - Scale::from(output_scale), - alpha, - None, - ); - - elements.extend(window_elements.into_iter().flat_map(|element| { - match element { - CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( - std::iter::once(elem), - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - geo.as_logical().to_physical_precise_round(output_scale), - elem_geometry, - ConstrainScaleBehavior::Stretch, - ConstrainAlign::CENTER, - output_scale, - ) - .next() - .map(CosmicMappedRenderElement::TiledStack), - CosmicMappedRenderElement::Window(elem) => constrain_render_elements( - std::iter::once(elem), - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - geo.as_logical().to_physical_precise_round(output_scale), - elem_geometry, - ConstrainScaleBehavior::Stretch, - ConstrainAlign::CENTER, - output_scale, - ) - .next() - .map(CosmicMappedRenderElement::TiledWindow), - x => Some(x), - } - })); let radius = mapped.corner_radius(geo.size.as_logical(), indicator_thickness); if is_minimizing && indicator_thickness > 0 { - elements.push(CosmicMappedRenderElement::FocusIndicator( + push(CosmicMappedRenderElement::FocusIndicator( IndicatorShader::focus_element( renderer, Key::Window(Usage::FocusIndicator, mapped.clone().key()), @@ -5100,13 +5072,43 @@ where ), )); } + + mapped.push_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + Some(geo.size.as_logical()), + Scale::from(output_scale), + alpha, + None, + &mut |elem| { + if let Some(elem) = window_map(elem, geo, elem_geometry) { + push(elem); + } + }, + &mut |elem| { + if let Some(elem) = window_map(elem, geo, elem_geometry) { + lower_elements.push(elem); + } + }, + ); + + shadow_elements.extend(mapped.shadow_render_element( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) - elem_geometry.loc, + Some(geo.size.as_logical()), + Scale::from(output_scale), + 1., + alpha, + )); }, ); - shadow_elements - .into_iter() - .chain(elements.into_iter()) - .collect() + for elem in shadow_elements { + push(elem); + } + for elem in lower_elements { + push(elem); + } } fn render_old_tree( @@ -5201,15 +5203,14 @@ fn render_new_tree_popups( percentage: f32, overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), swap_desc: Option, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, CosmicWindowRenderElement: RenderElement, CosmicStackRenderElement: RenderElement, { - let mut popup_elements = Vec::new(); let output_scale = output.current_scale().fractional_scale(); let is_active_output = seat @@ -5232,20 +5233,17 @@ where if let Data::Mapped { mapped, .. } = data { let elem_geometry = mapped.geometry().to_physical_precise_round(output_scale); - popup_elements.extend( - mapped.popup_render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - Scale::from(output_scale), - alpha, - ), + mapped.push_popup_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + Scale::from(output_scale), + alpha, + push, ); } }, ); - - popup_elements } fn render_new_tree_windows( @@ -5267,8 +5265,8 @@ fn render_new_tree_windows( swapping_stack_surface_id: &Id, backdrop_id: &Id, theme: &cosmic::theme::CosmicTheme, -) -> Vec> -where + push: &mut dyn FnMut(CosmicMappedRenderElement), +) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -5308,14 +5306,18 @@ where .map(|seat| &seat.active_output() == output) .unwrap_or(false); - let mut animating_window_elements = Vec::new(); - let mut window_elements = Vec::new(); + let mut animating_window_upper_elements = Vec::new(); + let mut animating_window_lower_elements = Vec::new(); + let mut animating_shadow_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + + let mut window_upper_elements = Vec::new(); + let mut window_lower_elements = Vec::new(); + let mut shadow_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); let mut group_backdrop = None; - let mut indicators = Vec::new(); - let mut resize_elements = None; - let mut swap_elements = Vec::new(); - let mut shadow_elements = Vec::new(); + let mut indicators = SmallVec::<[CosmicMappedRenderElement; 2]>::new_const(); + let mut resize_element = None; + let mut swap_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); let output_geo = output.geometry(); let output_scale = output.current_scale().fractional_scale(); @@ -5328,7 +5330,7 @@ where // render placeholder, if we are swapping to an empty workspace if target_tree.root_node_id().is_none() && swap_desc.is_some() { - window_elements.push( + window_upper_elements.push( BackdropShader::element( renderer, backdrop_id.clone(), @@ -5383,31 +5385,35 @@ where let render_loc = (swap_geo.loc.as_logical() - window_geo.loc).to_physical_precise_round(output_scale); - swap_elements.extend( - AsRenderElements::render_elements::>( - &window, - renderer, - render_loc, - output_scale.into(), - 1.0, - ) - .into_iter() - .map(|window| { - CosmicMappedRenderElement::GrabbedWindow(RescaleRenderElement::from_element( - window, - swap_geo - .loc - .as_logical() - .to_physical_precise_round(output_scale), - ease( - Linear, - 1.0, - swap_factor(window_geo.size), - transition.unwrap_or(1.0), + window.push_render_elements( + renderer, + render_loc, + output_scale.into(), + 1.0, + None, + false, + [0, 0, 0, 0], + // TODO + 0, + &mut |elem| { + swap_elements.push(CosmicMappedRenderElement::GrabbedWindow( + RescaleRenderElement::from_element( + elem.into(), + swap_geo + .loc + .as_logical() + .to_physical_precise_round(output_scale), + ease( + Linear, + 1.0, + swap_factor(window_geo.size), + transition.unwrap_or(1.0), + ), ), - )) - }), - ) + )); + }, + None, + ); } // render actual tree nodes @@ -5523,16 +5529,13 @@ where if let Some(swap) = swap_indicator.as_ref() { swap.resize(geo.size.as_logical()); swap.output_enter(output, output_geo.as_logical()); - swap_elements.extend( - swap.render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale), - output_scale.into(), - alpha * overview.0.alpha().unwrap_or(1.0), - ) - .into_iter() - .map(CosmicMappedRenderElement::from), - ); + swap.push_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale), + output_scale.into(), + alpha * overview.0.alpha().unwrap_or(1.0), + &mut |elem| swap_elements.push(elem.into()), + ) } } } @@ -5558,17 +5561,14 @@ where }) { resize.force_update(); } - resize_elements = Some( - resize - .render_elements::>( - renderer, - geo.loc.as_logical().to_physical_precise_round(output_scale), - output_scale.into(), - alpha * mode.alpha().unwrap_or(1.0), - ) - .into_iter() - .map(CosmicMappedRenderElement::from) - .collect::>(), + resize.push_render_elements( + renderer, + geo.loc.as_logical().to_physical_precise_round(output_scale), + output_scale.into(), + alpha * mode.alpha().unwrap_or(1.0), + &mut |elem| { + resize_element = Some(elem.into()); + }, ); } } @@ -5594,51 +5594,6 @@ where scale.x.min(scale.y), alpha, ); - let mut elements = mapped.render_elements::>( - renderer, - //original_location, - geo.loc.as_logical().to_physical_precise_round(output_scale) - - elem_geometry.loc, - max_size, - Scale::from(output_scale), - alpha, - None, - ); - - if swap_desc - .as_ref() - .filter(|swap_desc| swap_desc.node == node_id) - .and_then(|swap_desc| swap_desc.stack_window.as_ref()) - .zip(focused.as_ref()) - .map(|(stack_window, focused_id)| { - target_tree - .get(focused_id) - .ok() - .map(|focused| match focused.data() { - Data::Mapped { mapped, .. } => mapped - .stack_ref() - .map(|stack| &stack.active() == stack_window) - .unwrap_or(false), - _ => false, - }) - .unwrap_or(false) - }) - .unwrap_or(false) - { - let mut active_geo = mapped.active_window_geometry().as_local(); - active_geo.loc += geo.loc - mapped.geometry().loc.as_local(); - elements.insert( - 0, - CosmicMappedRenderElement::Overlay(BackdropShader::element( - renderer, - Key::Window(Usage::Overlay, mapped.key()), - active_geo, - 0.0, - 0.3, - group_color, - )), - ) - } let (behavior, align) = if is_overview { (ConstrainScaleBehavior::Fit, ConstrainAlign::CENTER) @@ -5648,7 +5603,7 @@ where (ConstrainScaleBehavior::CutOff, ConstrainAlign::TOP_LEFT) }; - let elements = elements.into_iter().flat_map(|element| match element { + let map_elem = |element| match element { CosmicMappedRenderElement::Stack(elem) => constrain_render_elements( std::iter::once(elem), geo.loc.as_logical().to_physical_precise_round(output_scale) @@ -5686,7 +5641,65 @@ where .next() .map(CosmicMappedRenderElement::TiledOverlay), x => Some(x), - }); + }; + + let mut upper_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + let mut lower_elements = SmallVec::<[CosmicMappedRenderElement; 4]>::new_const(); + mapped.push_render_elements( + renderer, + //original_location, + geo.loc.as_logical().to_physical_precise_round(output_scale) + - elem_geometry.loc, + max_size, + Scale::from(output_scale), + alpha, + None, + &mut |elem| { + if let Some(elem) = map_elem(elem) { + upper_elements.push(elem) + } + }, + &mut |elem| { + if let Some(elem) = map_elem(elem) { + lower_elements.push(elem) + } + }, + ); + + if swap_desc + .as_ref() + .filter(|swap_desc| swap_desc.node == node_id) + .and_then(|swap_desc| swap_desc.stack_window.as_ref()) + .zip(focused.as_ref()) + .map(|(stack_window, focused_id)| { + target_tree + .get(focused_id) + .ok() + .map(|focused| match focused.data() { + Data::Mapped { mapped, .. } => mapped + .stack_ref() + .map(|stack| &stack.active() == stack_window) + .unwrap_or(false), + _ => false, + }) + .unwrap_or(false) + }) + .unwrap_or(false) + { + let mut active_geo = mapped.active_window_geometry().as_local(); + active_geo.loc += geo.loc - mapped.geometry().loc.as_local(); + upper_elements.insert( + 0, + CosmicMappedRenderElement::Overlay(BackdropShader::element( + renderer, + Key::Window(Usage::Overlay, mapped.key()), + active_geo, + 0.0, + 0.3, + group_color, + )), + ) + } if swap_desc .as_ref() @@ -5699,30 +5712,38 @@ where }) .unwrap_or(false) { + swap_elements.extend(upper_elements); swap_elements.extend(shadow_element); - swap_elements.extend(elements); + swap_elements.extend(lower_elements); } else { - shadow_elements.extend(shadow_element); if animating { - animating_window_elements.extend(elements); + animating_window_upper_elements.extend(upper_elements); + animating_shadow_elements.extend(shadow_element); + animating_window_lower_elements.extend(lower_elements); } else { - window_elements.extend(elements); + window_upper_elements.extend(upper_elements); + shadow_elements.extend(shadow_element); + window_lower_elements.extend(lower_elements); } } } }, ); - resize_elements + for elem in resize_element .into_iter() - .flatten() .chain(swap_elements) .chain(indicators.into_iter().map(Into::into)) - .chain(window_elements) - .chain(animating_window_elements) + .chain(window_upper_elements) .chain(shadow_elements) + .chain(window_lower_elements) + .chain(animating_window_upper_elements) + .chain(animating_shadow_elements) + .chain(animating_window_lower_elements) .chain(group_backdrop.into_iter().map(Into::into)) - .collect() + { + push(elem); + } } fn render_new_tree( diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 6ba300d13..ae3e047b1 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -4852,6 +4852,7 @@ impl Shell { |surface, _| { surface_presentation_feedback_flags_from_states( surface, + None, render_element_states, ) }, @@ -4868,6 +4869,7 @@ impl Shell { |surface, _| { surface_presentation_feedback_flags_from_states( surface, + None, render_element_states, ) }, @@ -4877,11 +4879,16 @@ impl Shell { let map = smithay::desktop::layer_map_for_output(output); for layer_surface in map.layers() { + let namespace = self.workspaces.active_num(output).1; layer_surface.take_presentation_feedback( &mut output_presentation_feedback, surface_primary_scanout_output, |surface, _| { - surface_presentation_feedback_flags_from_states(surface, render_element_states) + surface_presentation_feedback_flags_from_states( + surface, + Some(namespace), + render_element_states, + ) }, ); } diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index b03ac7766..f58ea989d 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -1,11 +1,9 @@ +use crate::backend::render::wayland::SurfaceRenderElement; use crate::shell::focus::FocusTarget; use crate::shell::layout::tiling::RestoreTilingState; use crate::wayland::handlers::xdg_activation::ActivationContext; use crate::{ - backend::render::{ - BackdropShader, - element::{AsGlowRenderer, FromGlesError}, - }, + backend::render::{BackdropShader, element::AsGlowRenderer}, shell::{ ANIMATION_DURATION, OverviewMode, SeatMoveGrabState, layout::{ @@ -31,13 +29,15 @@ use cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::Tiling use id_tree::Tree; use indexmap::IndexSet; use keyframe::{ease, functions::EaseInOutCubic}; +use smallvec::SmallVec; +use smithay::backend::renderer::element::{Kind, NamespacedElement}; use smithay::output::WeakOutput; +use smithay::utils::user_data::UserDataMap; use smithay::{ backend::renderer::{ ImportAll, ImportMem, Renderer, element::{ - Element, Id, RenderElement, surface::WaylandSurfaceRenderElement, - texture::TextureRenderElement, utils::RescaleRenderElement, + Element, Id, RenderElement, texture::TextureRenderElement, utils::RescaleRenderElement, }, gles::GlesTexture, glow::GlowRenderer, @@ -1516,8 +1516,8 @@ impl Workspace { resize_indicator: Option<(ResizeMode, ResizeIndicator)>, indicator_thickness: u8, theme: &CosmicTheme, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(WorkspaceRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1525,16 +1525,16 @@ impl Workspace { CosmicStackRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = Vec::default(); - let output_scale = self.output.current_scale().fractional_scale(); let zone = { let layer_map = layer_map_for_output(&self.output); layer_map.non_exclusive_zone().as_local() }; let focused = self.focus_stack.get(last_active_seat).last().cloned(); + let fullscreen_focused = matches!(focused, Some(FocusTarget::Fullscreen(_))); - let mut fullscreen_elements = if let Some(fullscreen) = self.fullscreen.as_ref() { + let mut fullscreen_elements = SmallVec::<[WorkspaceRenderElement; 2]>::new_const(); + if let Some(fullscreen) = self.fullscreen.as_ref() { let fullscreen_geo = self.fullscreen_geometry().unwrap(); let previous_geo = fullscreen .previous_geometry @@ -1593,27 +1593,28 @@ impl Workspace { } }; - fullscreen - .surface - .render_elements::>( - renderer, - render_loc, - output_scale.into(), - alpha, - Some(true), - ) - .into_iter() - .map(animation_rescale) - .collect::>() - } else { - Vec::new() - }; - - if matches!(focused, Some(FocusTarget::Fullscreen(_))) { - elements.append(&mut fullscreen_elements); + let mut fullscreen_push = |elem: SurfaceRenderElement| { + if fullscreen_focused { + push(animation_rescale(elem.into())) + } else { + fullscreen_elements.push(animation_rescale(elem.into())) + } + }; + fullscreen.surface.push_render_elements( + renderer, + render_loc, + output_scale.into(), + alpha, + Some(true), + false, + [0, 0, 0, 0], + 0, + &mut fullscreen_push, + None, + ); } - if !matches!(focused, Some(FocusTarget::Fullscreen(_))) + if !fullscreen_focused || self .fullscreen .as_ref() @@ -1639,24 +1640,20 @@ impl Workspace { OverviewMode::None => 1.0, }; - elements.extend( - self.floating_layer - .render::( - renderer, - focused.as_ref().and_then(|target| { - if let FocusTarget::Window(mapped) = target { - Some(mapped) - } else { - None - } - }), - resize_indicator.clone(), - indicator_thickness, - alpha, - theme, - ) - .into_iter() - .map(WorkspaceRenderElement::from), + self.floating_layer.render( + renderer, + focused.as_ref().and_then(|target| { + if let FocusTarget::Window(mapped) = target { + Some(mapped) + } else { + None + } + }), + resize_indicator.clone(), + indicator_thickness, + alpha, + theme, + &mut |elem| push(elem.into()), ); let alpha = match &overview.0 { @@ -1673,23 +1670,19 @@ impl Workspace { }; //tiling surfaces - elements.extend( - self.tiling_layer - .render::( - renderer, - render_focus.then_some(last_active_seat), - zone, - overview, - resize_indicator, - indicator_thickness, - theme, - )? - .into_iter() - .map(WorkspaceRenderElement::from), + self.tiling_layer.render( + renderer, + render_focus.then_some(last_active_seat), + zone, + overview, + resize_indicator, + indicator_thickness, + theme, + &mut |elem| push(elem.into()), ); if let Some(alpha) = alpha { - elements.push( + push( Into::>::into(BackdropShader::element( renderer, self.backdrop_id.clone(), @@ -1703,11 +1696,9 @@ impl Workspace { } } - if !matches!(focused, Some(FocusTarget::Fullscreen(_))) { - elements.extend(fullscreen_elements.into_iter()); + for elem in fullscreen_elements { + push(elem); } - - Ok(elements) } #[profiling::function] @@ -1718,8 +1709,8 @@ impl Workspace { render_focus: bool, overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree>)>), theme: &CosmicTheme, - ) -> Result>, OutputNotMapped> - where + push: &mut dyn FnMut(WorkspaceRenderElement), + ) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, @@ -1727,8 +1718,6 @@ impl Workspace { CosmicStackRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, { - let mut elements = Vec::default(); - let output_scale = self.output.current_scale().fractional_scale(); let zone = { let layer_map = layer_map_for_output(&self.output); @@ -1779,17 +1768,13 @@ impl Workspace { .as_logical() .to_physical_precise_round(output_scale); - elements.extend( - fullscreen - .surface - .popup_render_elements::>( - renderer, - render_loc, - output_scale.into(), - alpha, - ) - .into_iter() - .map(Into::into), + fullscreen.surface.push_popup_render_elements( + renderer, + render_loc, + output_scale.into(), + alpha, + 0, + &mut |elem| push(WorkspaceRenderElement::FullscreenPopup(elem.into())), ); } @@ -1820,29 +1805,19 @@ impl Workspace { OverviewMode::None => 1.0, }; - elements.extend( - self.floating_layer - .render_popups::(renderer, alpha) - .into_iter() - .map(WorkspaceRenderElement::from), - ); + self.floating_layer + .render_popups(renderer, alpha, &mut |elem| push(elem.into())); //tiling surfaces - elements.extend( - self.tiling_layer - .render_popups::( - renderer, - render_focus.then_some(last_active_seat), - zone, - overview, - theme, - )? - .into_iter() - .map(WorkspaceRenderElement::from), + self.tiling_layer.render_popups( + renderer, + render_focus.then_some(last_active_seat), + zone, + overview, + theme, + &mut |elem| push(elem.into()), ); } - - Ok(elements) } } @@ -1863,7 +1838,8 @@ where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: 'static, { - OverrideRedirect(WaylandSurfaceRenderElement), + OverrideRedirect(SurfaceRenderElement), + LowerLayerShell(NamespacedElement>), Fullscreen(RescaleRenderElement>), FullscreenPopup(CosmicWindowRenderElement), Window(CosmicMappedRenderElement), @@ -1878,6 +1854,7 @@ where fn id(&self) -> &smithay::backend::renderer::element::Id { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.id(), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.id(), WorkspaceRenderElement::Fullscreen(elem) => elem.id(), WorkspaceRenderElement::FullscreenPopup(elem) => elem.id(), WorkspaceRenderElement::Window(elem) => elem.id(), @@ -1888,6 +1865,7 @@ where fn current_commit(&self) -> smithay::backend::renderer::utils::CommitCounter { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.current_commit(), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.current_commit(), WorkspaceRenderElement::Fullscreen(elem) => elem.current_commit(), WorkspaceRenderElement::FullscreenPopup(elem) => elem.current_commit(), WorkspaceRenderElement::Window(elem) => elem.current_commit(), @@ -1898,6 +1876,7 @@ where fn src(&self) -> Rectangle { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.src(), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.src(), WorkspaceRenderElement::Fullscreen(elem) => elem.src(), WorkspaceRenderElement::FullscreenPopup(elem) => elem.src(), WorkspaceRenderElement::Window(elem) => elem.src(), @@ -1908,6 +1887,7 @@ where fn geometry(&self, scale: Scale) -> Rectangle { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.geometry(scale), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.geometry(scale), WorkspaceRenderElement::Fullscreen(elem) => elem.geometry(scale), WorkspaceRenderElement::FullscreenPopup(elem) => elem.geometry(scale), WorkspaceRenderElement::Window(elem) => elem.geometry(scale), @@ -1918,6 +1898,7 @@ where fn location(&self, scale: Scale) -> Point { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.location(scale), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.location(scale), WorkspaceRenderElement::Fullscreen(elem) => elem.location(scale), WorkspaceRenderElement::FullscreenPopup(elem) => elem.location(scale), WorkspaceRenderElement::Window(elem) => elem.location(scale), @@ -1928,6 +1909,7 @@ where fn transform(&self) -> smithay::utils::Transform { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.transform(), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.transform(), WorkspaceRenderElement::Fullscreen(elem) => elem.transform(), WorkspaceRenderElement::FullscreenPopup(elem) => elem.transform(), WorkspaceRenderElement::Window(elem) => elem.transform(), @@ -1942,6 +1924,7 @@ where ) -> DamageSet { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.damage_since(scale, commit), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.damage_since(scale, commit), WorkspaceRenderElement::Fullscreen(elem) => elem.damage_since(scale, commit), WorkspaceRenderElement::FullscreenPopup(elem) => elem.damage_since(scale, commit), WorkspaceRenderElement::Window(elem) => elem.damage_since(scale, commit), @@ -1952,6 +1935,7 @@ where fn opaque_regions(&self, scale: Scale) -> OpaqueRegions { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.opaque_regions(scale), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.opaque_regions(scale), WorkspaceRenderElement::Fullscreen(elem) => elem.opaque_regions(scale), WorkspaceRenderElement::FullscreenPopup(elem) => elem.opaque_regions(scale), WorkspaceRenderElement::Window(elem) => elem.opaque_regions(scale), @@ -1962,19 +1946,41 @@ where fn alpha(&self) -> f32 { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.alpha(), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.alpha(), WorkspaceRenderElement::Fullscreen(elem) => elem.alpha(), WorkspaceRenderElement::FullscreenPopup(elem) => elem.alpha(), WorkspaceRenderElement::Window(elem) => elem.alpha(), WorkspaceRenderElement::Backdrop(elem) => elem.alpha(), } } + + fn kind(&self) -> Kind { + match self { + WorkspaceRenderElement::OverrideRedirect(elem) => elem.kind(), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.kind(), + WorkspaceRenderElement::Fullscreen(elem) => elem.kind(), + WorkspaceRenderElement::FullscreenPopup(elem) => elem.kind(), + WorkspaceRenderElement::Window(elem) => elem.kind(), + WorkspaceRenderElement::Backdrop(elem) => elem.kind(), + } + } + + fn is_framebuffer_effect(&self) -> bool { + match self { + WorkspaceRenderElement::OverrideRedirect(elem) => elem.is_framebuffer_effect(), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.is_framebuffer_effect(), + WorkspaceRenderElement::Fullscreen(elem) => elem.is_framebuffer_effect(), + WorkspaceRenderElement::FullscreenPopup(elem) => elem.is_framebuffer_effect(), + WorkspaceRenderElement::Window(elem) => elem.is_framebuffer_effect(), + WorkspaceRenderElement::Backdrop(elem) => elem.is_framebuffer_effect(), + } + } } impl RenderElement for WorkspaceRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: 'static, - R::Error: FromGlesError, { fn draw( &self, @@ -1983,19 +1989,23 @@ where dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], + cache: Option<&UserDataMap>, ) -> Result<(), R::Error> { match self { WorkspaceRenderElement::OverrideRedirect(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) + } + WorkspaceRenderElement::LowerLayerShell(elem) => { + elem.draw(frame, src, dst, damage, opaque_regions, cache) } WorkspaceRenderElement::Fullscreen(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } WorkspaceRenderElement::FullscreenPopup(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } WorkspaceRenderElement::Window(elem) => { - elem.draw(frame, src, dst, damage, opaque_regions) + elem.draw(frame, src, dst, damage, opaque_regions, cache) } WorkspaceRenderElement::Backdrop(elem) => RenderElement::::draw( elem, @@ -2004,8 +2014,9 @@ where dst, damage, opaque_regions, + cache, ) - .map_err(FromGlesError::from_gles_error), + .map_err(R::from_gles_error), } } @@ -2015,6 +2026,7 @@ where ) -> Option> { match self { WorkspaceRenderElement::OverrideRedirect(elem) => elem.underlying_storage(renderer), + WorkspaceRenderElement::LowerLayerShell(elem) => elem.underlying_storage(renderer), WorkspaceRenderElement::Fullscreen(elem) => elem.underlying_storage(renderer), WorkspaceRenderElement::FullscreenPopup(elem) => elem.underlying_storage(renderer), WorkspaceRenderElement::Window(elem) => elem.underlying_storage(renderer), @@ -2023,6 +2035,42 @@ where } } } + + fn capture_framebuffer( + &self, + frame: &mut R::Frame<'_, '_>, + src: Rectangle, + dst: Rectangle, + cache: &UserDataMap, + ) -> Result<(), R::Error> { + match self { + WorkspaceRenderElement::OverrideRedirect(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + WorkspaceRenderElement::LowerLayerShell(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + WorkspaceRenderElement::Fullscreen(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + WorkspaceRenderElement::FullscreenPopup(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + WorkspaceRenderElement::Window(elem) => { + elem.capture_framebuffer(frame, src, dst, cache) + } + WorkspaceRenderElement::Backdrop(elem) => { + RenderElement::::capture_framebuffer( + elem, + R::glow_frame_mut(frame), + src, + dst, + cache, + ) + .map_err(R::from_gles_error) + } + } + } } impl From>> for WorkspaceRenderElement @@ -2047,17 +2095,28 @@ where } } -impl From> for WorkspaceRenderElement +impl From> for WorkspaceRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - fn from(elem: WaylandSurfaceRenderElement) -> Self { + fn from(elem: SurfaceRenderElement) -> Self { WorkspaceRenderElement::OverrideRedirect(elem) } } +impl From>> for WorkspaceRenderElement +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + R::TextureId: 'static, + CosmicMappedRenderElement: RenderElement, +{ + fn from(elem: NamespacedElement>) -> Self { + WorkspaceRenderElement::LowerLayerShell(elem) + } +} + impl From> for WorkspaceRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, diff --git a/src/shell/zoom.rs b/src/shell/zoom.rs index fc018c485..753b23778 100644 --- a/src/shell/zoom.rs +++ b/src/shell/zoom.rs @@ -11,7 +11,7 @@ use cosmic_comp_config::ZoomMovement; use cosmic_config::ConfigSet; use keyframe::{ease, functions::EaseInOutCubic}; use smithay::{ - backend::renderer::{ImportMem, Renderer, element::AsRenderElements}, + backend::renderer::{ImportMem, Renderer, element::memory::MemoryRenderBufferRenderElement}, desktop::space::SpaceElement, input::{ Seat, @@ -192,9 +192,12 @@ impl OutputZoomState { }); } - fn render(&mut self, renderer: &mut R, output: &Output) -> Vec - where - C: From< as AsRenderElements>::RenderElement>, + fn render( + &mut self, + renderer: &mut R, + output: &Output, + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where R: Renderer + ImportMem, R::TextureId: Send + Clone + 'static, { @@ -208,8 +211,13 @@ impl OutputZoomState { .to_physical(scale.fractional_scale()) .to_i32_round(); - self.element - .render_elements(renderer, location, scale.fractional_scale().into(), 1.0) + self.element.push_render_elements( + renderer, + location, + scale.fractional_scale().into(), + 1.0, + push, + ) } } @@ -389,14 +397,16 @@ impl ZoomState { None } - pub fn render(renderer: &mut R, output: &Output) -> Vec - where - C: From< as AsRenderElements>::RenderElement>, + pub fn render( + renderer: &mut R, + output: &Output, + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where R: Renderer + ImportMem, R::TextureId: Send + Clone + 'static, { let output_state = output.user_data().get::>().unwrap(); - output_state.lock().unwrap().render(renderer, output) + output_state.lock().unwrap().render(renderer, output, push) } } diff --git a/src/state.rs b/src/state.rs index a251d2c65..56e7928f6 100644 --- a/src/state.rs +++ b/src/state.rs @@ -73,6 +73,7 @@ use smithay::{ utils::{Clock, Monotonic, Point}, wayland::{ alpha_modifier::AlphaModifierState, + background_effect::BackgroundEffectState, compositor::{CompositorClientState, CompositorState, SurfaceData}, cursor_shape::CursorShapeManagerState, dmabuf::{DmabufFeedback, DmabufGlobal, DmabufState}, @@ -280,6 +281,7 @@ pub struct Common { pub overlap_notify_state: OverlapNotifyState, pub a11y_state: A11yState, pub a11y_keyboard_monitor_state: A11yKeyboardMonitorState, + pub background_effect_state: BackgroundEffectState, // shell-related wayland state pub xdg_shell_state: XdgShellState, @@ -683,6 +685,8 @@ impl State { SinglePixelBufferState::new::(dh); FixesState::new::(&dh); + let background_effect_state = BackgroundEffectState::new::(dh); + let idle_notifier_state = IdleNotifierState::::new(dh, handle.clone()); let idle_inhibit_manager_state = IdleInhibitManagerState::new::(dh); let idle_inhibiting_surfaces = HashSet::new(); @@ -795,6 +799,7 @@ impl State { xdg_activation_state, xdg_foreign_state, workspace_state, + background_effect_state, a11y_state, a11y_keyboard_monitor_state, xwayland_scale: None, @@ -938,25 +943,29 @@ impl Common { render_element_states: &RenderElementStates, ) { let shell = self.shell.read(); - let processor = |surface: &WlSurface, states: &SurfaceData| { - let primary_scanout_output = update_surface_primary_scanout_output( - surface, - output, - states, - render_element_states, - primary_scanout_output_compare, - ); - if let Some(output) = primary_scanout_output { - with_fractional_scale(states, |fraction_scale| { - fraction_scale.set_preferred_scale(output.current_scale().fractional_scale()); - }); + let processor = |namespace: Option| { + move |surface: &WlSurface, states: &SurfaceData| { + let primary_scanout_output = update_surface_primary_scanout_output( + surface, + output, + states, + namespace, + render_element_states, + primary_scanout_output_compare, + ); + if let Some(output) = primary_scanout_output { + with_fractional_scale(states, |fraction_scale| { + fraction_scale + .set_preferred_scale(output.current_scale().fractional_scale()); + }); + } } }; // lock surface if let Some(session_lock) = shell.session_lock.as_ref() { if let Some(lock_surface) = session_lock.surfaces.get(output) { - with_surfaces_surface_tree(lock_surface.wl_surface(), processor) + with_surfaces_surface_tree(lock_surface.wl_surface(), processor(None)) } } @@ -969,20 +978,20 @@ impl Common { // cursor ... if let CursorImageStatus::Surface(wl_surface) = cursor_status { - with_surfaces_surface_tree(&wl_surface, processor); + with_surfaces_surface_tree(&wl_surface, processor(None)); } // grabs if let Some(move_grab) = seat.user_data().get::() { if let Some(grab_state) = move_grab.lock().unwrap().as_ref() { for (window, _) in grab_state.element().windows() { - window.with_surfaces(processor); + window.with_surfaces(processor(None)); } } } if let Some(icon) = get_dnd_icon(seat) { - with_surfaces_surface_tree(&icon.surface, processor); + with_surfaces_surface_tree(&icon.surface, processor(None)); } } @@ -990,7 +999,7 @@ impl Common { for set in shell.workspaces.sets.values() { set.sticky_layer.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { - window.with_surfaces(processor); + window.with_surfaces(processor(None)); } }); } @@ -998,16 +1007,16 @@ impl Common { // normal windows for space in shell.workspaces.spaces() { if let Some(window) = space.get_fullscreen() { - window.with_surfaces(processor); + window.with_surfaces(processor(None)); } space.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { - window.with_surfaces(processor); + window.with_surfaces(processor(None)); } }); space.minimized_windows.iter().for_each(|m| { for window in m.windows() { - window.with_surfaces(processor); + window.with_surfaces(processor(None)); } }) } @@ -1015,15 +1024,16 @@ impl Common { // OR windows shell.override_redirect_windows.iter().for_each(|or| { if let Some(wl_surface) = or.wl_surface() { - with_surfaces_surface_tree(&wl_surface, processor); + with_surfaces_surface_tree(&wl_surface, processor(None)); } }); // layer surfaces for o in shell.outputs() { + let namespace = shell.workspaces.active_num(o).1; let map = smithay::desktop::layer_map_for_output(o); for layer_surface in map.layers() { - layer_surface.with_surfaces(processor); + layer_surface.with_surfaces(processor(Some(namespace))); } } } diff --git a/src/utils/iced.rs b/src/utils/iced.rs index 43fa005f7..b7d7a0bc9 100644 --- a/src/utils/iced.rs +++ b/src/utils/iced.rs @@ -37,7 +37,7 @@ use smithay::{ renderer::{ ImportMem, Renderer, element::{ - AsRenderElements, Kind, + Kind, memory::{MemoryRenderBuffer, MemoryRenderBufferRenderElement}, }, }, @@ -882,21 +882,18 @@ impl SpaceElement for IcedElement

{ } } -impl AsRenderElements for IcedElement

-where - P: Program + Send + 'static, - R: Renderer + ImportMem, - R::TextureId: Send + Clone + 'static, -{ - type RenderElement = MemoryRenderBufferRenderElement; - - fn render_elements>( +impl IcedElement

{ + pub fn push_render_elements( &self, renderer: &mut R, location: Point, mut scale: Scale, alpha: f32, - ) -> Vec { + push: &mut dyn FnMut(MemoryRenderBufferRenderElement), + ) where + R: Renderer + ImportMem, + R::TextureId: Send + Clone + 'static, + { let mut internal = self.0.lock().unwrap(); // makes partial borrows easier let internal_ref = &mut *internal; @@ -1029,11 +1026,10 @@ where Kind::Unspecified, ) { Ok(buffer) => { - return vec![C::from(buffer)]; + push(buffer); } Err(err) => tracing::warn!("What? {:?}", err), } } - Vec::new() } } diff --git a/src/utils/screenshot.rs b/src/utils/screenshot.rs index d983271d9..ac63aafe1 100644 --- a/src/utils/screenshot.rs +++ b/src/utils/screenshot.rs @@ -3,9 +3,7 @@ use smithay::{ backend::{ allocator::Fourcc, renderer::{ - ExportMem, ImportAll, Offscreen, Renderer, - damage::OutputDamageTracker, - element::{AsRenderElements, surface::WaylandSurfaceRenderElement}, + ExportMem, ImportAll, Offscreen, Renderer, damage::OutputDamageTracker, gles::GlesRenderbuffer, }, }, @@ -16,7 +14,7 @@ use smithay::{ use tracing::warn; use crate::{ - backend::render::RendererRef, + backend::render::{RendererRef, element::AsGlowRenderer}, shell::element::CosmicSurface, state::{State, advertised_node_for_surface}, }; @@ -28,17 +26,23 @@ pub fn screenshot_window(state: &mut State, surface: &CosmicSurface) { offset: &time::UtcOffset, ) -> anyhow::Result<()> where - R: Renderer + ImportAll + Offscreen + ExportMem, + R: Renderer + ImportAll + Offscreen + ExportMem + AsGlowRenderer, R::TextureId: Clone + 'static, R::Error: Send + Sync + 'static, { let bbox = bbox_from_surface_tree(&window.wl_surface().unwrap(), (0, 0)); - let elements = AsRenderElements::::render_elements::>( - window, + let mut elements = Vec::new(); + window.push_render_elements( renderer, (-bbox.loc.x, -bbox.loc.y).into(), Scale::from(1.0), 1.0, + None, + false, + [0; 4], + 0, + &mut |elem| elements.push(elem), + None, ); // TODO: 10-bit diff --git a/src/wayland/handlers/background_effect.rs b/src/wayland/handlers/background_effect.rs new file mode 100644 index 000000000..6a7bb75b8 --- /dev/null +++ b/src/wayland/handlers/background_effect.rs @@ -0,0 +1,62 @@ +use smithay::{ + delegate_background_effect, + reexports::wayland_server::{DisplayHandle, protocol::wl_surface::WlSurface}, + utils::{Logical, Rectangle}, + wayland::{ + background_effect::{Capability, ExtBackgroundEffectHandler}, + compositor::{Cacheable, RectangleKind, RegionAttributes, with_states}, + }, +}; + +use crate::state::State; + +#[derive(Debug, Clone, Default)] +pub struct ComputedBlurRegionCachedState { + /// Region of the surface that will have its background blurred. + pub blur_region: Option>>, +} + +impl Cacheable for ComputedBlurRegionCachedState { + fn commit(&mut self, _dh: &DisplayHandle) -> Self { + self.clone() + } + + fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) { + *into = self; + } +} + +impl ExtBackgroundEffectHandler for State { + fn capabilities(&self) -> Capability { + Capability::Blur + } + + fn set_blur_region(&mut self, surface: WlSurface, region: RegionAttributes) { + with_states(&surface, |states| { + let mut blur_state = states.cached_state.get::(); + + blur_state.pending().blur_region = Some({ + let (added, subtracted) = region + .rects + .iter() + .cloned() + .partition::, _>(|(op, _)| matches!(op, RectangleKind::Add)); + let added = added.into_iter().map(|(_, rect)| rect).collect::>(); + Rectangle::subtract_rects_many_in_place( + added, + subtracted.into_iter().map(|(_, rect)| rect), + ) + }) + }) + } + + fn unset_blur_region(&mut self, surface: WlSurface) { + with_states(&surface, |states| { + let mut blur_state = states.cached_state.get::(); + + blur_state.pending().blur_region.take(); + }) + } +} + +delegate_background_effect!(State); diff --git a/src/wayland/handlers/image_copy_capture/render.rs b/src/wayland/handlers/image_copy_capture/render.rs index a0e58f5d2..3d8ecc50a 100644 --- a/src/wayland/handlers/image_copy_capture/render.rs +++ b/src/wayland/handlers/image_copy_capture/render.rs @@ -9,8 +9,7 @@ use smithay::{ buffer_dimensions, buffer_type, damage::{Error as DTError, OutputDamageTracker, RenderOutputResult}, element::{ - AsRenderElements, RenderElement, - surface::WaylandSurfaceRenderElement, + RenderElement, utils::{Relocate, RelocateRenderElement}, }, gles::{GlesError, GlesRenderbuffer}, @@ -40,9 +39,11 @@ use tracing::warn; use crate::{ backend::render::{ - CursorMode, ElementFilter, RendererRef, cursor, - element::{AsGlowRenderer, CosmicElement, DamageElement, FromGlesError}, + CursorMode, ElementFilter, RendererRef, + cursor::{self, CursorRenderElement}, + element::{AsGlowRenderer, CosmicElement, DamageElement}, render_workspace, + wayland::SurfaceRenderElement, }, shell::{CosmicMappedRenderElement, CosmicSurface, WorkspaceRenderElement}, state::{Common, KmsNodes, State}, @@ -105,8 +106,7 @@ pub fn submit_buffer( mut sync: SyncPoint, ) -> Result, R::Error> where - R: ExportMem, - R::Error: FromGlesError, + R: ExportMem + AsGlowRenderer, { let Some(damage) = damage else { frame.success( @@ -164,7 +164,7 @@ where Ok(()) }) - .map_err(|err| R::Error::from_gles_error(GlesError::BufferAccessError(err))) + .map_err(|err| R::from_gles_error(GlesError::BufferAccessError(err))) .and_then(|x| x) { frame.fail(CaptureFailureReason::Unknown); @@ -193,8 +193,7 @@ pub fn render_session( render_fn: F, ) -> Result, DTError> where - R: ExportMem + Offscreen, - R::Error: FromGlesError, + R: ExportMem + Offscreen + AsGlowRenderer, F: for<'d> FnOnce( &WlBuffer, &mut R, @@ -306,7 +305,6 @@ pub fn render_workspace_to_buffer( where R: Renderer + ImportAll + ImportMem + ExportMem + Bind + Blit + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - R::Error: FromGlesError, CosmicElement: RenderElement, CosmicMappedRenderElement: RenderElement, WorkspaceRenderElement: RenderElement, @@ -489,9 +487,10 @@ pub fn render_workspace_to_buffer( } smithay::render_elements! { - pub WindowCaptureElement where R: ImportAll + ImportMem; - WaylandElement=WaylandSurfaceRenderElement, + pub WindowCaptureElement where R: ImportAll + ImportMem + AsGlowRenderer; + WaylandElement=SurfaceRenderElement, CursorElement=RelocateRenderElement>, + DamageElement=DamageElement, } pub fn render_window_to_buffer( @@ -538,11 +537,10 @@ pub fn render_window_to_buffer( where R: Renderer + ImportAll + ImportMem + ExportMem + Bind + Blit + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - R::Error: FromGlesError, CosmicElement: RenderElement, CosmicMappedRenderElement: RenderElement, { - let additional_damage_elements: Vec<_> = additional_damage + let mut elements: Vec<_> = additional_damage .into_iter() .filter_map(|rect| { let logical_rect = rect.to_logical( @@ -553,10 +551,11 @@ pub fn render_window_to_buffer( logical_rect.intersection(Rectangle::from_size(geometry.size)) }) .map(DamageElement::new) + .map(WindowCaptureElement::::from) .collect(); - dt.damage_output(age, &additional_damage_elements)?; let shell = common.shell.read(); + let blur_strength = shell.appearance_config().blur_strength as usize; let seat = shell.seats.last_active().clone(); let pointer = seat.get_pointer().unwrap(); let pointer_loc = pointer.current_location().to_i32_round().as_global(); @@ -577,28 +576,26 @@ pub fn render_window_to_buffer( }; std::mem::drop(shell); - let mut elements = Vec::new(); - if let Some(location) = location { if draw_cursor { - elements.extend( - cursor::draw_cursor( - renderer, - &seat, - location, - 1.0.into(), - 1.0, - common.clock.now(), - true, - ) - .into_iter() - .map(|(elem, hotspot)| { - WindowCaptureElement::CursorElement(RelocateRenderElement::from_element( - elem, - Point::from((-hotspot.x, -hotspot.y)), - Relocate::Relative, - )) - }), + cursor::draw_cursor( + renderer, + &seat, + location, + 1.0.into(), + 1.0, + common.clock.now(), + blur_strength, + true, + &mut |elem, hotspot| { + elements.push(WindowCaptureElement::CursorElement( + RelocateRenderElement::from_element( + elem, + Point::from((-hotspot.x, -hotspot.y)), + Relocate::Relative, + ), + )); + }, ); } @@ -606,29 +603,39 @@ pub fn render_window_to_buffer( // still include dnd surface in window capture buffer? if draw_cursor { if let Some(dnd_icon) = get_dnd_icon(&seat) { - elements.extend( - cursor::draw_dnd_icon( - renderer, - &dnd_icon.surface, - (location + dnd_icon.offset.to_f64()).to_i32_round(), - 1.0, - ) - .into_iter() - .map(WindowCaptureElement::from), + cursor::draw_dnd_icon( + renderer, + &dnd_icon.surface, + (location + dnd_icon.offset.to_f64()).to_i32_round(), + 1.0, + blur_strength, + &mut |elem| { + elements.push( + RelocateRenderElement::from_element( + CursorRenderElement::Surface(elem), + Point::new(0, 0), + Relocate::Relative, + ) + .into(), + ) + }, ); } } } - elements.extend(AsRenderElements::::render_elements::< - WindowCaptureElement, - >( - toplevel, + toplevel.push_render_elements( renderer, (-geometry.loc.x, -geometry.loc.y).into(), Scale::from(1.0), 1.0, - )); + None, + false, + [0; 4], + blur_strength, + &mut |elem| elements.push(elem.into()), + None, + ); if let Ok(dmabuf) = get_dmabuf(buffer) { let mut dmabuf_clone = dmabuf.clone(); @@ -637,8 +644,10 @@ pub fn render_window_to_buffer( .map_err(DTError::Rendering)?; dt.render_output(renderer, &mut fb, age, &elements, Color32F::TRANSPARENT) } else { + let states = dt.damage_output(age, &elements)?.1; + let fb = offscreen.expect("shm buffer should have an offscreen target"); - dt.render_output(renderer, fb, 0, &elements, Color32F::TRANSPARENT) + dt.render_output_with_states(renderer, fb, 0, &elements, Color32F::TRANSPARENT, states) } } @@ -777,33 +786,34 @@ pub fn render_cursor_to_buffer( where R: Renderer + ImportAll + ImportMem + ExportMem + Bind + Blit + AsGlowRenderer, R::TextureId: Send + Clone + 'static, - R::Error: FromGlesError, CosmicElement: RenderElement, CosmicMappedRenderElement: RenderElement, { - let additional_damage_elements: Vec<_> = additional_damage + let mut elements: Vec<_> = additional_damage .into_iter() .filter_map(|rect| { let logical_rect = rect.to_logical(1, Transform::Normal, &Size::from((64, 64))); logical_rect.intersection(Rectangle::from_size((64, 64).into())) }) .map(DamageElement::new) + .map(WindowCaptureElement::from) .collect(); - dt.damage_output(age, &additional_damage_elements)?; - let elements = cursor::draw_cursor( + cursor::draw_cursor( renderer, seat, Point::from((0.0, 0.0)), 1.0.into(), 1.0, common.clock.now(), + 0, true, - ) - .into_iter() - .map(|(elem, _)| RelocateRenderElement::from_element(elem, (0, 0), Relocate::Relative)) - .map(WindowCaptureElement::from) - .collect::>(); + &mut |elem, _| { + elements.push( + RelocateRenderElement::from_element(elem, (0, 0), Relocate::Relative).into(), + ) + }, + ); if let Ok(dmabuf) = get_dmabuf(buffer) { let mut dmabuf_clone = dmabuf.clone(); @@ -812,8 +822,10 @@ pub fn render_cursor_to_buffer( .map_err(DTError::Rendering)?; dt.render_output(renderer, &mut fb, age, &elements, [0.0, 0.0, 0.0, 0.0]) } else { + let states = dt.damage_output(age, &elements)?.1; + let fb = offscreen.expect("shm buffers should have offscreen target"); - dt.render_output(renderer, fb, 0, &elements, [0.0, 0.0, 0.0, 0.0]) + dt.render_output_with_states(renderer, fb, 0, &elements, [0.0, 0.0, 0.0, 0.0], states) } } diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index d3d22f005..c970c92c6 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -2,6 +2,7 @@ pub mod a11y; pub mod alpha_modifier; +pub mod background_effect; pub mod buffer; pub mod compositor; pub mod corner_radius;