From 18886965673e3f9d5faec0bafd09f68be2d9db45 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 10 Apr 2024 08:53:35 +0400 Subject: Reimplement window closing anim in an efficient way - Keep a root surface cache to be accessible in surface destroyed() - Only snapshot during / right before closing, rather than every frame - Store textures rather than elements to handle scale and alpha properly --- src/window/mapped.rs | 111 +++++++++++++++++++++------------------------------ 1 file changed, 46 insertions(+), 65 deletions(-) (limited to 'src/window') diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 7210f8b0..58f733ba 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -3,7 +3,8 @@ use std::cmp::{max, min}; use niri_config::{BlockOutFrom, WindowRule}; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; -use smithay::backend::renderer::element::{Id, Kind}; +use smithay::backend::renderer::element::{AsRenderElements, Id, Kind}; +use smithay::backend::renderer::gles::GlesRenderer; use smithay::desktop::space::SpaceElement as _; use smithay::desktop::{PopupManager, Window}; use smithay::output::Output; @@ -15,13 +16,11 @@ use smithay::wayland::compositor::{send_surface_state, with_states}; use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface}; use super::{ResolvedWindowRules, WindowRef}; -use crate::layout::{ - LayoutElement, LayoutElementRenderElement, LayoutElementSnapshotRenderElements, -}; +use crate::layout::{LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot}; use crate::niri::WindowOffscreenId; use crate::render_helpers::renderer::NiriRenderer; -use crate::render_helpers::surface::render_and_save_from_surface_tree; -use crate::render_helpers::{RenderSnapshot, RenderTarget}; +use crate::render_helpers::surface::render_snapshot_from_surface_tree; +use crate::render_helpers::{BakedBuffer, RenderSnapshot, RenderTarget}; #[derive(Debug)] pub struct Mapped { @@ -43,7 +42,7 @@ pub struct Mapped { block_out_buffer: RefCell, /// Snapshot of the last render for use in the close animation. - last_render: RefCell>, + last_render: RefCell, } impl Mapped { @@ -95,6 +94,42 @@ impl Mapped { self.is_focused = is_focused; self.need_to_recompute_rules = true; } + + pub fn render_and_store_snapshot(&self, renderer: &mut GlesRenderer) { + let mut snapshot = self.last_render.borrow_mut(); + if !snapshot.contents.is_empty() { + return; + } + + snapshot.contents.clear(); + snapshot.blocked_out_contents.clear(); + snapshot.block_out_from = self.rules.block_out_from; + + let mut buffer = self.block_out_buffer.borrow_mut(); + buffer.resize(self.window.geometry().size); + snapshot.blocked_out_contents = vec![BakedBuffer { + buffer: buffer.clone(), + location: Point::from((0, 0)), + src: None, + dst: None, + }]; + + let buf_pos = self.window.geometry().loc.upscale(-1); + + 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; + + render_snapshot_from_surface_tree( + renderer, + popup.wl_surface(), + buf_pos + offset, + &mut snapshot.contents, + ); + } + + render_snapshot_from_surface_tree(renderer, surface, buf_pos, &mut snapshot.contents); + } } impl LayoutElement for Mapped { @@ -131,10 +166,9 @@ impl LayoutElement for Mapped { Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output, }; - let mut buffer = self.block_out_buffer.borrow_mut(); - buffer.resize(self.window.geometry().size); - if block_out { + let mut buffer = self.block_out_buffer.borrow_mut(); + buffer.resize(self.window.geometry().size); let elem = SolidColorRenderElement::from_buffer( &buffer, location.to_physical_precise_round(scale), @@ -146,64 +180,11 @@ impl LayoutElement for Mapped { } else { let buf_pos = location - self.window.geometry().loc; let buf_pos = buf_pos.to_physical_precise_round(scale); - - let mut elements = vec![]; - - // If we're rendering for output, save into last_render. - let mut last_render = self.last_render.borrow_mut(); - // FIXME: when preview-render is active, last render contents will never update. - let mut storage = if target == RenderTarget::Output { - last_render.contents.clear(); - last_render.block_out_from = self.rules.block_out_from; - last_render.blocked_out_contents = vec![SolidColorRenderElement::from_buffer( - &buffer, - (0, 0), - scale, - alpha, - Kind::Unspecified, - ) - .into()]; - - Some(&mut last_render.contents) - } else { - None - }; - - 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) - .to_physical_precise_round(scale); - - render_and_save_from_surface_tree( - renderer, - popup.wl_surface(), - buf_pos, - offset, - scale, - alpha, - Kind::Unspecified, - &mut elements, - &mut storage, - ); - } - - render_and_save_from_surface_tree( - renderer, - surface, - buf_pos, - Point::from((0., 0.)), - scale, - alpha, - Kind::Unspecified, - &mut elements, - &mut storage, - ); - - elements + self.window.render_elements(renderer, buf_pos, scale, alpha) } } - fn take_last_render(&self) -> RenderSnapshot { + fn take_last_render(&self) -> LayoutElementRenderSnapshot { self.last_render.take() } -- cgit