From 9309b3be61bb1e7d4ef3f9350b2646413850119b Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 1 May 2024 19:02:22 +0400 Subject: Split rendering between popups and window surface --- src/layout/mod.rs | 32 +++++++++++-- src/layout/tile.rs | 29 +++++++++--- src/render_helpers/mod.rs | 37 ++++++++++++++++ src/window/mapped.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 194 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 5ca48ad6..83715364 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -51,7 +51,7 @@ use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Works use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::snapshot::RenderSnapshot; -use crate::render_helpers::{BakedBuffer, RenderTarget}; +use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements}; use crate::utils::output_size; use crate::window::ResolvedWindowRules; @@ -108,7 +108,31 @@ pub trait LayoutElement { scale: Scale, alpha: f32, target: RenderTarget, - ) -> Vec>; + ) -> SplitElements>; + + /// Renders the non-popup parts of the element. + fn render_normal( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + alpha: f32, + target: RenderTarget, + ) -> Vec> { + self.render(renderer, location, scale, alpha, target).normal + } + + /// Renders the popups of the element. + fn render_popups( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + alpha: f32, + target: RenderTarget, + ) -> Vec> { + self.render(renderer, location, scale, alpha, target).popups + } fn request_size(&mut self, size: Size, animate: bool); fn request_fullscreen(&self, size: Size); @@ -1984,8 +2008,8 @@ mod tests { _scale: Scale, _alpha: f32, _target: RenderTarget, - ) -> Vec> { - vec![] + ) -> SplitElements> { + SplitElements::default() } fn request_size(&mut self, size: Size, _animate: bool) { diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 0e06dd1b..b1790df5 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -536,18 +536,31 @@ impl Tile { let window_render_loc = location + window_loc; let area = Rectangle::from_loc_and_size(window_render_loc, animated_window_size); - let gles_renderer = renderer.as_gles_renderer(); - // If we're resizing, try to render a shader, or a fallback. let mut resize_shader = None; + let mut resize_popups = None; let mut resize_fallback = None; if let Some(resize) = &self.resize_animation { - if let Some(shader) = ResizeRenderElement::shader(gles_renderer) { + resize_popups = Some( + self.window + .render_popups(renderer, window_render_loc, scale, alpha, target) + .into_iter() + .map(Into::into), + ); + + if let Some(shader) = ResizeRenderElement::shader(renderer) { + let gles_renderer = renderer.as_gles_renderer(); + 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); + let window_elements = self.window.render_normal( + gles_renderer, + Point::from((0, 0)), + scale, + 1., + target, + ); + let current = render_to_encompassing_texture( gles_renderer, scale, @@ -605,8 +618,10 @@ impl Tile { ); } - let rv = resize_shader + let rv = resize_popups .into_iter() + .flatten() + .chain(resize_shader) .chain(resize_fallback) .chain(window.into_iter().flatten()); diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs index 0be48bc6..16abe1ae 100644 --- a/src/render_helpers/mod.rs +++ b/src/render_helpers/mod.rs @@ -49,6 +49,13 @@ pub struct BakedBuffer { pub dst: Option>, } +/// Render elements split into normal and popup. +#[derive(Debug)] +pub struct SplitElements { + pub normal: Vec, + pub popups: Vec, +} + pub trait ToRenderElement { type RenderElement; @@ -61,6 +68,36 @@ pub trait ToRenderElement { ) -> Self::RenderElement; } +impl Default for SplitElements { + fn default() -> Self { + Self { + normal: Vec::new(), + popups: Vec::new(), + } + } +} + +impl IntoIterator for SplitElements { + type Item = E; + type IntoIter = std::iter::Chain, std::vec::IntoIter>; + + fn into_iter(self) -> Self::IntoIter { + self.popups.into_iter().chain(self.normal) + } +} + +impl SplitElements { + pub fn iter(&self) -> std::iter::Chain, std::slice::Iter> { + self.popups.iter().chain(&self.normal) + } + + pub fn into_vec(self) -> Vec { + let Self { normal, mut popups } = self; + popups.extend(normal); + popups + } +} + impl ToRenderElement for BakedBuffer> { type RenderElement = PrimaryGpuTextureRenderElement; diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 90598431..6ebb7a32 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::{AsRenderElements, Id, Kind}; +use smithay::backend::renderer::element::surface::render_elements_from_surface_tree; +use smithay::backend::renderer::element::{Id, Kind}; use smithay::backend::renderer::gles::GlesRenderer; use smithay::desktop::space::SpaceElement as _; use smithay::desktop::{PopupManager, Window}; @@ -23,7 +24,7 @@ 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, RenderTarget}; +use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements}; #[derive(Debug)] pub struct Mapped { @@ -203,6 +204,63 @@ impl LayoutElement for Mapped { scale: Scale, alpha: f32, target: RenderTarget, + ) -> SplitElements> { + let mut rv = SplitElements::default(); + + let block_out = match self.rules.block_out_from { + None => false, + Some(BlockOutFrom::Screencast) => target == RenderTarget::Screencast, + Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output, + }; + + 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), + scale, + alpha, + Kind::Unspecified, + ); + rv.normal.push(elem.into()); + } else { + let buf_pos = location - self.window.geometry().loc; + + 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; + + rv.popups.extend(render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + (buf_pos + offset).to_physical_precise_round(scale), + scale, + alpha, + Kind::Unspecified, + )); + } + + rv.normal = render_elements_from_surface_tree( + renderer, + surface, + buf_pos.to_physical_precise_round(scale), + scale, + alpha, + Kind::Unspecified, + ); + } + + rv + } + + fn render_normal( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + alpha: f32, + target: RenderTarget, ) -> Vec> { let block_out = match self.rules.block_out_from { None => false, @@ -223,8 +281,53 @@ impl LayoutElement for Mapped { vec![elem.into()] } else { let buf_pos = location - self.window.geometry().loc; - let buf_pos = buf_pos.to_physical_precise_round(scale); - self.window.render_elements(renderer, buf_pos, scale, alpha) + let surface = self.toplevel().wl_surface(); + render_elements_from_surface_tree( + renderer, + surface, + buf_pos.to_physical_precise_round(scale), + scale, + alpha, + Kind::Unspecified, + ) + } + } + + fn render_popups( + &self, + renderer: &mut R, + location: Point, + scale: Scale, + alpha: f32, + target: RenderTarget, + ) -> Vec> { + let block_out = match self.rules.block_out_from { + None => false, + Some(BlockOutFrom::Screencast) => target == RenderTarget::Screencast, + Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output, + }; + + if block_out { + vec![] + } else { + let mut rv = vec![]; + + let buf_pos = location - self.window.geometry().loc; + 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; + + rv.extend(render_elements_from_surface_tree( + renderer, + popup.wl_surface(), + (buf_pos + offset).to_physical_precise_round(scale), + scale, + alpha, + Kind::Unspecified, + )); + } + + rv } } -- cgit