mirror of
https://github.com/YaLTeR/niri.git
synced 2024-11-09 19:47:34 +03:00
Split rendering between popups and window surface
This commit is contained in:
parent
c5be2dd549
commit
9309b3be61
@ -4,7 +4,7 @@ use std::rc::Rc;
|
||||
|
||||
use niri::layout::{LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot};
|
||||
use niri::render_helpers::renderer::NiriRenderer;
|
||||
use niri::render_helpers::RenderTarget;
|
||||
use niri::render_helpers::{RenderTarget, SplitElements};
|
||||
use niri::window::ResolvedWindowRules;
|
||||
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||
use smithay::backend::renderer::element::{Id, Kind};
|
||||
@ -149,28 +149,31 @@ impl LayoutElement for TestWindow {
|
||||
scale: Scale<f64>,
|
||||
alpha: f32,
|
||||
_target: RenderTarget,
|
||||
) -> Vec<LayoutElementRenderElement<R>> {
|
||||
) -> SplitElements<LayoutElementRenderElement<R>> {
|
||||
let inner = self.inner.borrow();
|
||||
|
||||
vec![
|
||||
SolidColorRenderElement::from_buffer(
|
||||
&inner.buffer,
|
||||
location.to_physical_precise_round(scale),
|
||||
scale,
|
||||
alpha,
|
||||
Kind::Unspecified,
|
||||
)
|
||||
.into(),
|
||||
SolidColorRenderElement::from_buffer(
|
||||
&inner.csd_shadow_buffer,
|
||||
(location - Point::from((inner.csd_shadow_width, inner.csd_shadow_width)))
|
||||
.to_physical_precise_round(scale),
|
||||
scale,
|
||||
alpha,
|
||||
Kind::Unspecified,
|
||||
)
|
||||
.into(),
|
||||
]
|
||||
SplitElements {
|
||||
normal: vec![
|
||||
SolidColorRenderElement::from_buffer(
|
||||
&inner.buffer,
|
||||
location.to_physical_precise_round(scale),
|
||||
scale,
|
||||
alpha,
|
||||
Kind::Unspecified,
|
||||
)
|
||||
.into(),
|
||||
SolidColorRenderElement::from_buffer(
|
||||
&inner.csd_shadow_buffer,
|
||||
(location - Point::from((inner.csd_shadow_width, inner.csd_shadow_width)))
|
||||
.to_physical_precise_round(scale),
|
||||
scale,
|
||||
alpha,
|
||||
Kind::Unspecified,
|
||||
)
|
||||
.into(),
|
||||
],
|
||||
popups: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) {
|
||||
|
@ -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<f64>,
|
||||
alpha: f32,
|
||||
target: RenderTarget,
|
||||
) -> Vec<LayoutElementRenderElement<R>>;
|
||||
) -> SplitElements<LayoutElementRenderElement<R>>;
|
||||
|
||||
/// Renders the non-popup parts of the element.
|
||||
fn render_normal<R: NiriRenderer>(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
location: Point<i32, Logical>,
|
||||
scale: Scale<f64>,
|
||||
alpha: f32,
|
||||
target: RenderTarget,
|
||||
) -> Vec<LayoutElementRenderElement<R>> {
|
||||
self.render(renderer, location, scale, alpha, target).normal
|
||||
}
|
||||
|
||||
/// Renders the popups of the element.
|
||||
fn render_popups<R: NiriRenderer>(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
location: Point<i32, Logical>,
|
||||
scale: Scale<f64>,
|
||||
alpha: f32,
|
||||
target: RenderTarget,
|
||||
) -> Vec<LayoutElementRenderElement<R>> {
|
||||
self.render(renderer, location, scale, alpha, target).popups
|
||||
}
|
||||
|
||||
fn request_size(&mut self, size: Size<i32, Logical>, animate: bool);
|
||||
fn request_fullscreen(&self, size: Size<i32, Logical>);
|
||||
@ -1984,8 +2008,8 @@ mod tests {
|
||||
_scale: Scale<f64>,
|
||||
_alpha: f32,
|
||||
_target: RenderTarget,
|
||||
) -> Vec<LayoutElementRenderElement<R>> {
|
||||
vec![]
|
||||
) -> SplitElements<LayoutElementRenderElement<R>> {
|
||||
SplitElements::default()
|
||||
}
|
||||
|
||||
fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) {
|
||||
|
@ -536,18 +536,31 @@ impl<W: LayoutElement> Tile<W> {
|
||||
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<W: LayoutElement> Tile<W> {
|
||||
);
|
||||
}
|
||||
|
||||
let rv = resize_shader
|
||||
let rv = resize_popups
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.chain(resize_shader)
|
||||
.chain(resize_fallback)
|
||||
.chain(window.into_iter().flatten());
|
||||
|
||||
|
@ -49,6 +49,13 @@ pub struct BakedBuffer<B> {
|
||||
pub dst: Option<Size<i32, Logical>>,
|
||||
}
|
||||
|
||||
/// Render elements split into normal and popup.
|
||||
#[derive(Debug)]
|
||||
pub struct SplitElements<E> {
|
||||
pub normal: Vec<E>,
|
||||
pub popups: Vec<E>,
|
||||
}
|
||||
|
||||
pub trait ToRenderElement {
|
||||
type RenderElement;
|
||||
|
||||
@ -61,6 +68,36 @@ pub trait ToRenderElement {
|
||||
) -> Self::RenderElement;
|
||||
}
|
||||
|
||||
impl<E> Default for SplitElements<E> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
normal: Vec::new(),
|
||||
popups: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> IntoIterator for SplitElements<E> {
|
||||
type Item = E;
|
||||
type IntoIter = std::iter::Chain<std::vec::IntoIter<E>, std::vec::IntoIter<E>>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.popups.into_iter().chain(self.normal)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> SplitElements<E> {
|
||||
pub fn iter(&self) -> std::iter::Chain<std::slice::Iter<E>, std::slice::Iter<E>> {
|
||||
self.popups.iter().chain(&self.normal)
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<E> {
|
||||
let Self { normal, mut popups } = self;
|
||||
popups.extend(normal);
|
||||
popups
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRenderElement for BakedBuffer<TextureBuffer<GlesTexture>> {
|
||||
type RenderElement = PrimaryGpuTextureRenderElement;
|
||||
|
||||
|
@ -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<f64>,
|
||||
alpha: f32,
|
||||
target: RenderTarget,
|
||||
) -> SplitElements<LayoutElementRenderElement<R>> {
|
||||
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<R: NiriRenderer>(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
location: Point<i32, Logical>,
|
||||
scale: Scale<f64>,
|
||||
alpha: f32,
|
||||
target: RenderTarget,
|
||||
) -> Vec<LayoutElementRenderElement<R>> {
|
||||
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<R: NiriRenderer>(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
location: Point<i32, Logical>,
|
||||
scale: Scale<f64>,
|
||||
alpha: f32,
|
||||
target: RenderTarget,
|
||||
) -> Vec<LayoutElementRenderElement<R>> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user