diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/compositor.rs | 2 | ||||
| -rw-r--r-- | src/handlers/xdg_shell.rs | 8 | ||||
| -rw-r--r-- | src/layout/closing_window.rs | 3 | ||||
| -rw-r--r-- | src/layout/mod.rs | 32 | ||||
| -rw-r--r-- | src/layout/tile.rs | 109 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 5 | ||||
| -rw-r--r-- | src/render_helpers/mod.rs | 25 | ||||
| -rw-r--r-- | src/render_helpers/snapshot.rs | 111 | ||||
| -rw-r--r-- | src/window/mapped.rs | 62 |
9 files changed, 180 insertions, 177 deletions
diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs index 785ad2fe..060980a5 100644 --- a/src/handlers/compositor.rs +++ b/src/handlers/compositor.rs @@ -304,7 +304,7 @@ impl CompositorHandler for State { if let Some(root) = self.niri.root_surface.get(surface) { if let Some((mapped, _)) = self.niri.layout.find_window_and_output(root) { self.backend.with_primary_renderer(|renderer| { - mapped.render_and_store_snapshot(renderer); + mapped.store_unmap_snapshot_if_empty(renderer); }); } } diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index ab9d7072..7ebf360a 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -387,7 +387,7 @@ impl XdgShellHandler for State { let output = output.clone(); self.backend.with_primary_renderer(|renderer| { - mapped.render_and_store_snapshot(renderer); + mapped.store_unmap_snapshot_if_empty(renderer); }); self.backend.with_primary_renderer(|renderer| { self.niri @@ -845,11 +845,11 @@ pub fn add_mapped_toplevel_pre_commit_hook(toplevel: &ToplevelSurface) -> HookId if got_unmapped { state.backend.with_primary_renderer(|renderer| { - mapped.render_and_store_snapshot(renderer); + mapped.store_unmap_snapshot_if_empty(renderer); }); } else { - // The toplevel remains mapped; clear any cached render snapshot. - let _ = mapped.take_last_render(); + // The toplevel remains mapped; clear any stored unmap snapshot. + let _ = mapped.take_unmap_snapshot(); if animate { state.backend.with_primary_renderer(|renderer| { diff --git a/src/layout/closing_window.rs b/src/layout/closing_window.rs index 47e039aa..d30d8646 100644 --- a/src/layout/closing_window.rs +++ b/src/layout/closing_window.rs @@ -14,7 +14,8 @@ use smithay::utils::{Logical, Point, Scale, Transform}; use crate::animation::Animation; use crate::niri_render_elements; use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement; -use crate::render_helpers::{render_to_encompassing_texture, RenderSnapshot, RenderTarget}; +use crate::render_helpers::snapshot::RenderSnapshot; +use crate::render_helpers::{render_to_encompassing_texture, RenderTarget}; #[derive(Debug)] pub struct ClosingWindow { diff --git a/src/layout/mod.rs b/src/layout/mod.rs index efcc8167..afb101c8 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -50,7 +50,8 @@ pub use self::monitor::MonitorRenderElement; use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Workspace}; use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; -use crate::render_helpers::{BakedBuffer, RenderSnapshot, RenderTarget}; +use crate::render_helpers::snapshot::RenderSnapshot; +use crate::render_helpers::{BakedBuffer, RenderTarget}; use crate::utils::output_size; use crate::window::ResolvedWindowRules; @@ -73,15 +74,6 @@ niri_render_elements! { pub type LayoutElementRenderSnapshot = RenderSnapshot<BakedBuffer<TextureBuffer<GlesTexture>>, BakedBuffer<SolidColorBuffer>>; -/// Snapshot of an element for animation. -#[derive(Debug)] -pub struct AnimationSnapshot { - /// Snapshot of the render. - pub render: LayoutElementRenderSnapshot, - /// Visual size of the element at the point of the snapshot. - pub size: Size<i32, Logical>, -} - pub trait LayoutElement { /// Type that can be used as a unique ID of this element. type Id: PartialEq; @@ -118,8 +110,6 @@ pub trait LayoutElement { target: RenderTarget, ) -> Vec<LayoutElementRenderElement<R>>; - fn take_last_render(&self) -> LayoutElementRenderSnapshot; - fn request_size(&mut self, size: Size<i32, Logical>, animate: bool); fn request_fullscreen(&self, size: Size<i32, Logical>); fn min_size(&self) -> Size<i32, Logical>; @@ -150,8 +140,10 @@ pub trait LayoutElement { /// Runs periodic clean-up tasks. fn refresh(&self); - fn animation_snapshot(&self) -> Option<&AnimationSnapshot>; - fn take_animation_snapshot(&mut self) -> Option<AnimationSnapshot>; + fn take_unmap_snapshot(&self) -> Option<LayoutElementRenderSnapshot>; + + fn animation_snapshot(&self) -> Option<&LayoutElementRenderSnapshot>; + fn take_animation_snapshot(&mut self) -> Option<LayoutElementRenderSnapshot>; } #[derive(Debug)] @@ -1966,10 +1958,6 @@ mod tests { vec![] } - fn take_last_render(&self) -> LayoutElementRenderSnapshot { - RenderSnapshot::default() - } - fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) { self.0.requested_size.set(Some(size)); self.0.pending_fullscreen.set(false); @@ -2024,11 +2012,15 @@ mod tests { &EMPTY } - fn animation_snapshot(&self) -> Option<&AnimationSnapshot> { + fn take_unmap_snapshot(&self) -> Option<LayoutElementRenderSnapshot> { + None + } + + fn animation_snapshot(&self) -> Option<&LayoutElementRenderSnapshot> { None } - fn take_animation_snapshot(&mut self) -> Option<AnimationSnapshot> { + fn take_animation_snapshot(&mut self) -> Option<LayoutElementRenderSnapshot> { None } } diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 578de86a..86082f74 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -1,19 +1,17 @@ -use std::cell::OnceCell; use std::cmp::max; use std::rc::Rc; use std::time::Duration; -use niri_config::BlockOutFrom; use smithay::backend::allocator::Fourcc; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; use smithay::backend::renderer::element::utils::RescaleRenderElement; use smithay::backend::renderer::element::{Element, Kind}; -use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; -use smithay::utils::{Logical, Physical, Point, Rectangle, Scale, Size, Transform}; +use smithay::backend::renderer::gles::GlesRenderer; +use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform}; use super::focus_ring::{FocusRing, FocusRingRenderElement}; use super::{ - AnimationSnapshot, LayoutElement, LayoutElementRenderElement, Options, + LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot, Options, RESIZE_ANIMATION_THRESHOLD, }; use crate::animation::Animation; @@ -23,9 +21,8 @@ use crate::render_helpers::offscreen::OffscreenRenderElement; use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::shaders::Shaders; -use crate::render_helpers::{ - render_to_encompassing_texture, RenderSnapshot, RenderTarget, ToRenderElement, -}; +use crate::render_helpers::snapshot::RenderSnapshot; +use crate::render_helpers::{render_to_encompassing_texture, RenderTarget, ToRenderElement}; /// Toplevel window with decorations. #[derive(Debug)] @@ -96,10 +93,7 @@ niri_render_elements! { struct ResizeAnimation { anim: Animation, size_from: Size<i32, Logical>, - snapshot: AnimationSnapshot, - /// Snapshot rendered into a texture (happens lazily). - snapshot_texture: OnceCell<Option<(GlesTexture, Rectangle<i32, Physical>)>>, - snapshot_blocked_out_texture: OnceCell<Option<(GlesTexture, Rectangle<i32, Physical>)>>, + snapshot: LayoutElementRenderSnapshot, } #[derive(Debug)] @@ -167,8 +161,6 @@ impl<W: LayoutElement> Tile<W> { anim, size_from, snapshot: animate_from, - snapshot_texture: OnceCell::new(), - snapshot_blocked_out_texture: OnceCell::new(), }); } else { self.resize_animation = None; @@ -499,7 +491,7 @@ impl<W: LayoutElement> Tile<W> { if let Some(resize) = &self.resize_animation { if Shaders::get(gles_renderer).crossfade.is_some() { - if let Some(texture_from) = resize.rendered_texture(gles_renderer, scale, target) { + if let Some(texture_from) = resize.snapshot.texture(gles_renderer, scale, target) { let window_elements = self.window .render(gles_renderer, Point::from((0, 0)), scale, 1., target); @@ -702,13 +694,10 @@ impl<W: LayoutElement> Tile<W> { renderer: &mut GlesRenderer, scale: Scale<f64>, view_size: Size<i32, Logical>, - ) -> RenderSnapshot<TileSnapshotRenderElement, TileSnapshotRenderElement> { - let snapshot = self.window.take_last_render(); - if snapshot.contents.is_empty() { - return RenderSnapshot::default(); - } + ) -> Option<RenderSnapshot<TileSnapshotRenderElement, TileSnapshotRenderElement>> { + let snapshot = self.window.take_unmap_snapshot()?; - RenderSnapshot { + Some(RenderSnapshot { contents: self.render_snapshot(renderer, scale, view_size, snapshot.contents), blocked_out_contents: self.render_snapshot( renderer, @@ -717,79 +706,9 @@ impl<W: LayoutElement> Tile<W> { snapshot.blocked_out_contents, ), block_out_from: snapshot.block_out_from, - } - } -} - -impl ResizeAnimation { - fn rendered_texture( - &self, - renderer: &mut GlesRenderer, - scale: Scale<f64>, - target: RenderTarget, - ) -> &Option<(GlesTexture, Rectangle<i32, Physical>)> { - let block_out = match self.snapshot.render.block_out_from { - None => false, - Some(BlockOutFrom::Screencast) => target == RenderTarget::Screencast, - Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output, - }; - - if block_out { - self.snapshot_blocked_out_texture.get_or_init(|| { - let _span = tracy_client::span!("ResizeAnimation::rendered_texture"); - - let elements: Vec<_> = self - .snapshot - .render - .blocked_out_contents - .iter() - .map(|baked| { - baked.to_render_element(Point::from((0, 0)), scale, 1., Kind::Unspecified) - }) - .collect(); - - match render_to_encompassing_texture( - renderer, - scale, - Transform::Normal, - Fourcc::Abgr8888, - &elements, - ) { - Ok((texture, _sync_point, geo)) => Some((texture, geo)), - Err(err) => { - warn!("error rendering snapshot to texture: {err:?}"); - None - } - } - }) - } else { - self.snapshot_texture.get_or_init(|| { - let _span = tracy_client::span!("ResizeAnimation::rendered_texture"); - - let elements: Vec<_> = self - .snapshot - .render - .contents - .iter() - .map(|baked| { - baked.to_render_element(Point::from((0, 0)), scale, 1., Kind::Unspecified) - }) - .collect(); - - match render_to_encompassing_texture( - renderer, - scale, - Transform::Normal, - Fourcc::Abgr8888, - &elements, - ) { - Ok((texture, _sync_point, geo)) => Some((texture, geo)), - Err(err) => { - warn!("error rendering snapshot to texture: {err:?}"); - None - } - } - }) - } + size: snapshot.size, + texture: Default::default(), + blocked_out_texture: Default::default(), + }) } } diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index 202867af..ef8548ae 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -965,8 +965,9 @@ impl<W: LayoutElement> Workspace<W> { .map(|o| Scale::from(o.current_scale().fractional_scale())) .unwrap_or(Scale::from(1.)); - let snapshot = tile.take_snapshot_for_close_anim(renderer, output_scale, self.view_size); - if snapshot.contents.is_empty() { + let Some(snapshot) = + tile.take_snapshot_for_close_anim(renderer, output_scale, self.view_size) + else { return; }; diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs index ad3e91b8..de40c274 100644 --- a/src/render_helpers/mod.rs +++ b/src/render_helpers/mod.rs @@ -1,7 +1,6 @@ use std::ptr; use anyhow::{ensure, Context}; -use niri_config::BlockOutFrom; use smithay::backend::allocator::Fourcc; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement}; @@ -27,6 +26,7 @@ pub mod render_elements; pub mod renderer; pub mod resources; pub mod shaders; +pub mod snapshot; pub mod surface; /// What we're rendering for. @@ -49,19 +49,6 @@ pub struct BakedBuffer<B> { pub dst: Option<Size<i32, Logical>>, } -/// Snapshot of a render. -#[derive(Debug)] -pub struct RenderSnapshot<C, B> { - /// Contents for a normal render. - pub contents: Vec<C>, - - /// Blocked-out contents. - pub blocked_out_contents: Vec<B>, - - /// Where the contents were blocked out from at the time of the snapshot. - pub block_out_from: Option<BlockOutFrom>, -} - pub trait ToRenderElement { type RenderElement; @@ -118,16 +105,6 @@ impl ToRenderElement for BakedBuffer<SolidColorBuffer> { } } -impl<C, B> Default for RenderSnapshot<C, B> { - fn default() -> Self { - Self { - contents: Default::default(), - blocked_out_contents: Default::default(), - block_out_from: Default::default(), - } - } -} - pub fn render_to_encompassing_texture( renderer: &mut GlesRenderer, scale: Scale<f64>, diff --git a/src/render_helpers/snapshot.rs b/src/render_helpers/snapshot.rs new file mode 100644 index 00000000..b394dcd9 --- /dev/null +++ b/src/render_helpers/snapshot.rs @@ -0,0 +1,111 @@ +use std::cell::OnceCell; + +use niri_config::BlockOutFrom; +use smithay::backend::allocator::Fourcc; +use smithay::backend::renderer::element::{Kind, RenderElement}; +use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; +use smithay::utils::{Logical, Physical, Point, Rectangle, Scale, Size, Transform}; + +use super::{render_to_encompassing_texture, RenderTarget, ToRenderElement}; + +/// Snapshot of a render. +#[derive(Debug)] +pub struct RenderSnapshot<C, B> { + /// Contents for a normal render. + /// + /// Relative to the geometry. + pub contents: Vec<C>, + + /// Blocked-out contents. + /// + /// Relative to the geometry. + pub blocked_out_contents: Vec<B>, + + /// Where the contents were blocked out from at the time of the snapshot. + pub block_out_from: Option<BlockOutFrom>, + + /// Visual size of the element at the point of the snapshot. + pub size: Size<i32, Logical>, + + /// Contents rendered into a texture (lazily). + pub texture: OnceCell<Option<(GlesTexture, Rectangle<i32, Physical>)>>, + + /// Blocked-out contents rendered into a texture (lazily). + pub blocked_out_texture: OnceCell<Option<(GlesTexture, Rectangle<i32, Physical>)>>, +} + +impl<C, B, EC, EB> RenderSnapshot<C, B> +where + C: ToRenderElement<RenderElement = EC>, + B: ToRenderElement<RenderElement = EB>, + EC: RenderElement<GlesRenderer>, + EB: RenderElement<GlesRenderer>, +{ + pub fn texture( + &self, + renderer: &mut GlesRenderer, + scale: Scale<f64>, + target: RenderTarget, + ) -> Option<&(GlesTexture, Rectangle<i32, Physical>)> { + let block_out = match self.block_out_from { + None => false, + Some(BlockOutFrom::Screencast) => target == RenderTarget::Screencast, + Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output, + }; + + if block_out { + self.blocked_out_texture.get_or_init(|| { + let _span = tracy_client::span!("RenderSnapshot::Texture"); + + let elements: Vec<_> = self + .blocked_out_contents + .iter() + .map(|baked| { + baked.to_render_element(Point::from((0, 0)), scale, 1., Kind::Unspecified) + }) + .collect(); + + match render_to_encompassing_texture( + renderer, + scale, + Transform::Normal, + Fourcc::Abgr8888, + &elements, + ) { + Ok((texture, _sync_point, geo)) => Some((texture, geo)), + Err(err) => { + warn!("error rendering blocked-out contents to texture: {err:?}"); + None + } + } + }) + } else { + self.texture.get_or_init(|| { + let _span = tracy_client::span!("RenderSnapshot::Texture"); + + let elements: Vec<_> = self + .contents + .iter() + .map(|baked| { + baked.to_render_element(Point::from((0, 0)), scale, 1., Kind::Unspecified) + }) + .collect(); + + match render_to_encompassing_texture( + renderer, + scale, + Transform::Normal, + Fourcc::Abgr8888, + &elements, + ) { + Ok((texture, _sync_point, geo)) => Some((texture, geo)), + Err(err) => { + warn!("error rendering contents to texture: {err:?}"); + None + } + } + }) + } + .as_ref() + } +} diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 2469921e..9686a15f 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -18,13 +18,12 @@ use smithay::wayland::compositor::{ use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface}; use super::{ResolvedWindowRules, WindowRef}; -use crate::layout::{ - AnimationSnapshot, LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot, -}; +use crate::layout::{LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot}; use crate::niri::WindowOffscreenId; use crate::render_helpers::renderer::NiriRenderer; +use crate::render_helpers::snapshot::RenderSnapshot; use crate::render_helpers::surface::render_snapshot_from_surface_tree; -use crate::render_helpers::{BakedBuffer, RenderSnapshot, RenderTarget}; +use crate::render_helpers::{BakedBuffer, RenderTarget}; #[derive(Debug)] pub struct Mapped { @@ -49,7 +48,7 @@ pub struct Mapped { block_out_buffer: RefCell<SolidColorBuffer>, /// Snapshot of the last render for use in the close animation. - last_render: RefCell<LayoutElementRenderSnapshot>, + unmap_snapshot: RefCell<Option<LayoutElementRenderSnapshot>>, /// Whether the next configure should be animated, if the configured state changed. animate_next_configure: bool, @@ -58,7 +57,7 @@ pub struct Mapped { animate_serials: Vec<Serial>, /// Snapshot right before an animated commit. - animation_snapshot: Option<AnimationSnapshot>, + animation_snapshot: Option<LayoutElementRenderSnapshot>, } impl Mapped { @@ -70,7 +69,7 @@ impl Mapped { need_to_recompute_rules: false, is_focused: false, block_out_buffer: RefCell::new(SolidColorBuffer::new((0, 0), [0., 0., 0., 1.])), - last_render: RefCell::new(RenderSnapshot::default()), + unmap_snapshot: RefCell::new(None), animate_next_configure: false, animate_serials: Vec::new(), animation_snapshot: None, @@ -118,14 +117,11 @@ impl Mapped { fn render_snapshot(&self, renderer: &mut GlesRenderer) -> LayoutElementRenderSnapshot { let _span = tracy_client::span!("Mapped::render_snapshot"); - let mut snapshot = RenderSnapshot { - block_out_from: self.rules.block_out_from, - ..Default::default() - }; + let size = self.size(); let mut buffer = self.block_out_buffer.borrow_mut(); - buffer.resize(self.window.geometry().size); - snapshot.blocked_out_contents = vec![BakedBuffer { + buffer.resize(size); + let blocked_out_contents = vec![BakedBuffer { buffer: buffer.clone(), location: Point::from((0, 0)), src: None, @@ -134,6 +130,8 @@ impl Mapped { let buf_pos = self.window.geometry().loc.upscale(-1); + let mut contents = vec![]; + let surface = self.toplevel().wl_surface(); for (popup, popup_offset) in PopupManager::popups_for_surface(surface) { let offset = self.window.geometry().loc + popup_offset - popup.geometry().loc; @@ -142,22 +140,29 @@ impl Mapped { renderer, popup.wl_surface(), buf_pos + offset, - &mut snapshot.contents, + &mut contents, ); } - render_snapshot_from_surface_tree(renderer, surface, buf_pos, &mut snapshot.contents); + render_snapshot_from_surface_tree(renderer, surface, buf_pos, &mut contents); - snapshot + RenderSnapshot { + contents, + blocked_out_contents, + block_out_from: self.rules().block_out_from, + size, + texture: Default::default(), + blocked_out_texture: Default::default(), + } } - pub fn render_and_store_snapshot(&self, renderer: &mut GlesRenderer) { - let mut snapshot = self.last_render.borrow_mut(); - if !snapshot.contents.is_empty() { + pub fn store_unmap_snapshot_if_empty(&self, renderer: &mut GlesRenderer) { + let mut snapshot = self.unmap_snapshot.borrow_mut(); + if snapshot.is_some() { return; } - *snapshot = self.render_snapshot(renderer); + *snapshot = Some(self.render_snapshot(renderer)); } pub fn should_animate_commit(&mut self, commit_serial: Serial) -> bool { @@ -174,10 +179,7 @@ impl Mapped { } pub fn store_animation_snapshot(&mut self, renderer: &mut GlesRenderer) { - self.animation_snapshot = Some(AnimationSnapshot { - render: self.render_snapshot(renderer), - size: self.size(), - }); + self.animation_snapshot = Some(self.render_snapshot(renderer)); } } @@ -239,10 +241,6 @@ impl LayoutElement for Mapped { } } - fn take_last_render(&self) -> LayoutElementRenderSnapshot { - self.last_render.take() - } - fn request_size(&mut self, size: Size<i32, Logical>, animate: bool) { let changed = self.toplevel().with_pending_state(|state| { let changed = state.size != Some(size); @@ -382,11 +380,15 @@ impl LayoutElement for Mapped { &self.rules } - fn animation_snapshot(&self) -> Option<&AnimationSnapshot> { + fn take_unmap_snapshot(&self) -> Option<LayoutElementRenderSnapshot> { + self.unmap_snapshot.take() + } + + fn animation_snapshot(&self) -> Option<&LayoutElementRenderSnapshot> { self.animation_snapshot.as_ref() } - fn take_animation_snapshot(&mut self) -> Option<AnimationSnapshot> { + fn take_animation_snapshot(&mut self) -> Option<LayoutElementRenderSnapshot> { self.animation_snapshot.take() } } |
