mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Unify Animation- and RenderSnapshot
This commit is contained in:
@@ -2,11 +2,9 @@ use std::cell::RefCell;
|
|||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use niri::layout::{
|
use niri::layout::{LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot};
|
||||||
AnimationSnapshot, LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot,
|
|
||||||
};
|
|
||||||
use niri::render_helpers::renderer::NiriRenderer;
|
use niri::render_helpers::renderer::NiriRenderer;
|
||||||
use niri::render_helpers::{RenderSnapshot, RenderTarget};
|
use niri::render_helpers::RenderTarget;
|
||||||
use niri::window::ResolvedWindowRules;
|
use niri::window::ResolvedWindowRules;
|
||||||
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use smithay::backend::renderer::element::{Id, Kind};
|
use smithay::backend::renderer::element::{Id, Kind};
|
||||||
@@ -175,10 +173,6 @@ impl LayoutElement for TestWindow {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_last_render(&self) -> LayoutElementRenderSnapshot {
|
|
||||||
RenderSnapshot::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) {
|
fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) {
|
||||||
self.inner.borrow_mut().requested_size = Some(size);
|
self.inner.borrow_mut().requested_size = Some(size);
|
||||||
self.inner.borrow_mut().pending_fullscreen = false;
|
self.inner.borrow_mut().pending_fullscreen = false;
|
||||||
@@ -233,11 +227,15 @@ impl LayoutElement for TestWindow {
|
|||||||
&EMPTY
|
&EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
fn animation_snapshot(&self) -> Option<&AnimationSnapshot> {
|
fn take_unmap_snapshot(&self) -> Option<LayoutElementRenderSnapshot> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_animation_snapshot(&mut self) -> Option<AnimationSnapshot> {
|
fn animation_snapshot(&self) -> Option<&LayoutElementRenderSnapshot> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_animation_snapshot(&mut self) -> Option<LayoutElementRenderSnapshot> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ impl CompositorHandler for State {
|
|||||||
if let Some(root) = self.niri.root_surface.get(surface) {
|
if let Some(root) = self.niri.root_surface.get(surface) {
|
||||||
if let Some((mapped, _)) = self.niri.layout.find_window_and_output(root) {
|
if let Some((mapped, _)) = self.niri.layout.find_window_and_output(root) {
|
||||||
self.backend.with_primary_renderer(|renderer| {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
mapped.render_and_store_snapshot(renderer);
|
mapped.store_unmap_snapshot_if_empty(renderer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ impl XdgShellHandler for State {
|
|||||||
let output = output.clone();
|
let output = output.clone();
|
||||||
|
|
||||||
self.backend.with_primary_renderer(|renderer| {
|
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.backend.with_primary_renderer(|renderer| {
|
||||||
self.niri
|
self.niri
|
||||||
@@ -845,11 +845,11 @@ pub fn add_mapped_toplevel_pre_commit_hook(toplevel: &ToplevelSurface) -> HookId
|
|||||||
|
|
||||||
if got_unmapped {
|
if got_unmapped {
|
||||||
state.backend.with_primary_renderer(|renderer| {
|
state.backend.with_primary_renderer(|renderer| {
|
||||||
mapped.render_and_store_snapshot(renderer);
|
mapped.store_unmap_snapshot_if_empty(renderer);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// The toplevel remains mapped; clear any cached render snapshot.
|
// The toplevel remains mapped; clear any stored unmap snapshot.
|
||||||
let _ = mapped.take_last_render();
|
let _ = mapped.take_unmap_snapshot();
|
||||||
|
|
||||||
if animate {
|
if animate {
|
||||||
state.backend.with_primary_renderer(|renderer| {
|
state.backend.with_primary_renderer(|renderer| {
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ use smithay::utils::{Logical, Point, Scale, Transform};
|
|||||||
use crate::animation::Animation;
|
use crate::animation::Animation;
|
||||||
use crate::niri_render_elements;
|
use crate::niri_render_elements;
|
||||||
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct ClosingWindow {
|
pub struct ClosingWindow {
|
||||||
|
|||||||
+12
-20
@@ -50,7 +50,8 @@ pub use self::monitor::MonitorRenderElement;
|
|||||||
use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Workspace};
|
use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Workspace};
|
||||||
use crate::niri_render_elements;
|
use crate::niri_render_elements;
|
||||||
use crate::render_helpers::renderer::NiriRenderer;
|
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::utils::output_size;
|
||||||
use crate::window::ResolvedWindowRules;
|
use crate::window::ResolvedWindowRules;
|
||||||
|
|
||||||
@@ -73,15 +74,6 @@ niri_render_elements! {
|
|||||||
pub type LayoutElementRenderSnapshot =
|
pub type LayoutElementRenderSnapshot =
|
||||||
RenderSnapshot<BakedBuffer<TextureBuffer<GlesTexture>>, BakedBuffer<SolidColorBuffer>>;
|
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 {
|
pub trait LayoutElement {
|
||||||
/// Type that can be used as a unique ID of this element.
|
/// Type that can be used as a unique ID of this element.
|
||||||
type Id: PartialEq;
|
type Id: PartialEq;
|
||||||
@@ -118,8 +110,6 @@ pub trait LayoutElement {
|
|||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> Vec<LayoutElementRenderElement<R>>;
|
) -> Vec<LayoutElementRenderElement<R>>;
|
||||||
|
|
||||||
fn take_last_render(&self) -> LayoutElementRenderSnapshot;
|
|
||||||
|
|
||||||
fn request_size(&mut self, size: Size<i32, Logical>, animate: bool);
|
fn request_size(&mut self, size: Size<i32, Logical>, animate: bool);
|
||||||
fn request_fullscreen(&self, size: Size<i32, Logical>);
|
fn request_fullscreen(&self, size: Size<i32, Logical>);
|
||||||
fn min_size(&self) -> Size<i32, Logical>;
|
fn min_size(&self) -> Size<i32, Logical>;
|
||||||
@@ -150,8 +140,10 @@ pub trait LayoutElement {
|
|||||||
/// Runs periodic clean-up tasks.
|
/// Runs periodic clean-up tasks.
|
||||||
fn refresh(&self);
|
fn refresh(&self);
|
||||||
|
|
||||||
fn animation_snapshot(&self) -> Option<&AnimationSnapshot>;
|
fn take_unmap_snapshot(&self) -> Option<LayoutElementRenderSnapshot>;
|
||||||
fn take_animation_snapshot(&mut self) -> Option<AnimationSnapshot>;
|
|
||||||
|
fn animation_snapshot(&self) -> Option<&LayoutElementRenderSnapshot>;
|
||||||
|
fn take_animation_snapshot(&mut self) -> Option<LayoutElementRenderSnapshot>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -1966,10 +1958,6 @@ mod tests {
|
|||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_last_render(&self) -> LayoutElementRenderSnapshot {
|
|
||||||
RenderSnapshot::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) {
|
fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) {
|
||||||
self.0.requested_size.set(Some(size));
|
self.0.requested_size.set(Some(size));
|
||||||
self.0.pending_fullscreen.set(false);
|
self.0.pending_fullscreen.set(false);
|
||||||
@@ -2024,11 +2012,15 @@ mod tests {
|
|||||||
&EMPTY
|
&EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
fn animation_snapshot(&self) -> Option<&AnimationSnapshot> {
|
fn take_unmap_snapshot(&self) -> Option<LayoutElementRenderSnapshot> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_animation_snapshot(&mut self) -> Option<AnimationSnapshot> {
|
fn animation_snapshot(&self) -> Option<&LayoutElementRenderSnapshot> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_animation_snapshot(&mut self) -> Option<LayoutElementRenderSnapshot> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-95
@@ -1,19 +1,17 @@
|
|||||||
use std::cell::OnceCell;
|
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use niri_config::BlockOutFrom;
|
|
||||||
use smithay::backend::allocator::Fourcc;
|
use smithay::backend::allocator::Fourcc;
|
||||||
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use smithay::backend::renderer::element::utils::RescaleRenderElement;
|
use smithay::backend::renderer::element::utils::RescaleRenderElement;
|
||||||
use smithay::backend::renderer::element::{Element, Kind};
|
use smithay::backend::renderer::element::{Element, Kind};
|
||||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
use smithay::backend::renderer::gles::GlesRenderer;
|
||||||
use smithay::utils::{Logical, Physical, Point, Rectangle, Scale, Size, Transform};
|
use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
|
||||||
|
|
||||||
use super::focus_ring::{FocusRing, FocusRingRenderElement};
|
use super::focus_ring::{FocusRing, FocusRingRenderElement};
|
||||||
use super::{
|
use super::{
|
||||||
AnimationSnapshot, LayoutElement, LayoutElementRenderElement, Options,
|
LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot, Options,
|
||||||
RESIZE_ANIMATION_THRESHOLD,
|
RESIZE_ANIMATION_THRESHOLD,
|
||||||
};
|
};
|
||||||
use crate::animation::Animation;
|
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::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
||||||
use crate::render_helpers::renderer::NiriRenderer;
|
use crate::render_helpers::renderer::NiriRenderer;
|
||||||
use crate::render_helpers::shaders::Shaders;
|
use crate::render_helpers::shaders::Shaders;
|
||||||
use crate::render_helpers::{
|
use crate::render_helpers::snapshot::RenderSnapshot;
|
||||||
render_to_encompassing_texture, RenderSnapshot, RenderTarget, ToRenderElement,
|
use crate::render_helpers::{render_to_encompassing_texture, RenderTarget, ToRenderElement};
|
||||||
};
|
|
||||||
|
|
||||||
/// Toplevel window with decorations.
|
/// Toplevel window with decorations.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -96,10 +93,7 @@ niri_render_elements! {
|
|||||||
struct ResizeAnimation {
|
struct ResizeAnimation {
|
||||||
anim: Animation,
|
anim: Animation,
|
||||||
size_from: Size<i32, Logical>,
|
size_from: Size<i32, Logical>,
|
||||||
snapshot: AnimationSnapshot,
|
snapshot: LayoutElementRenderSnapshot,
|
||||||
/// 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>)>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -167,8 +161,6 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
anim,
|
anim,
|
||||||
size_from,
|
size_from,
|
||||||
snapshot: animate_from,
|
snapshot: animate_from,
|
||||||
snapshot_texture: OnceCell::new(),
|
|
||||||
snapshot_blocked_out_texture: OnceCell::new(),
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.resize_animation = None;
|
self.resize_animation = None;
|
||||||
@@ -499,7 +491,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
|
|
||||||
if let Some(resize) = &self.resize_animation {
|
if let Some(resize) = &self.resize_animation {
|
||||||
if Shaders::get(gles_renderer).crossfade.is_some() {
|
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 =
|
let window_elements =
|
||||||
self.window
|
self.window
|
||||||
.render(gles_renderer, Point::from((0, 0)), scale, 1., target);
|
.render(gles_renderer, Point::from((0, 0)), scale, 1., target);
|
||||||
@@ -702,13 +694,10 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
view_size: Size<i32, Logical>,
|
view_size: Size<i32, Logical>,
|
||||||
) -> RenderSnapshot<TileSnapshotRenderElement, TileSnapshotRenderElement> {
|
) -> Option<RenderSnapshot<TileSnapshotRenderElement, TileSnapshotRenderElement>> {
|
||||||
let snapshot = self.window.take_last_render();
|
let snapshot = self.window.take_unmap_snapshot()?;
|
||||||
if snapshot.contents.is_empty() {
|
|
||||||
return RenderSnapshot::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderSnapshot {
|
Some(RenderSnapshot {
|
||||||
contents: self.render_snapshot(renderer, scale, view_size, snapshot.contents),
|
contents: self.render_snapshot(renderer, scale, view_size, snapshot.contents),
|
||||||
blocked_out_contents: self.render_snapshot(
|
blocked_out_contents: self.render_snapshot(
|
||||||
renderer,
|
renderer,
|
||||||
@@ -717,79 +706,9 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
snapshot.blocked_out_contents,
|
snapshot.blocked_out_contents,
|
||||||
),
|
),
|
||||||
block_out_from: snapshot.block_out_from,
|
block_out_from: snapshot.block_out_from,
|
||||||
}
|
size: snapshot.size,
|
||||||
}
|
texture: Default::default(),
|
||||||
}
|
blocked_out_texture: Default::default(),
|
||||||
|
})
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -965,8 +965,9 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
.map(|o| Scale::from(o.current_scale().fractional_scale()))
|
.map(|o| Scale::from(o.current_scale().fractional_scale()))
|
||||||
.unwrap_or(Scale::from(1.));
|
.unwrap_or(Scale::from(1.));
|
||||||
|
|
||||||
let snapshot = tile.take_snapshot_for_close_anim(renderer, output_scale, self.view_size);
|
let Some(snapshot) =
|
||||||
if snapshot.contents.is_empty() {
|
tile.take_snapshot_for_close_anim(renderer, output_scale, self.view_size)
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use anyhow::{ensure, Context};
|
use anyhow::{ensure, Context};
|
||||||
use niri_config::BlockOutFrom;
|
|
||||||
use smithay::backend::allocator::Fourcc;
|
use smithay::backend::allocator::Fourcc;
|
||||||
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement};
|
use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement};
|
||||||
@@ -27,6 +26,7 @@ pub mod render_elements;
|
|||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
pub mod shaders;
|
pub mod shaders;
|
||||||
|
pub mod snapshot;
|
||||||
pub mod surface;
|
pub mod surface;
|
||||||
|
|
||||||
/// What we're rendering for.
|
/// What we're rendering for.
|
||||||
@@ -49,19 +49,6 @@ pub struct BakedBuffer<B> {
|
|||||||
pub dst: Option<Size<i32, Logical>>,
|
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 {
|
pub trait ToRenderElement {
|
||||||
type RenderElement;
|
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(
|
pub fn render_to_encompassing_texture(
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
-30
@@ -18,13 +18,12 @@ use smithay::wayland::compositor::{
|
|||||||
use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface};
|
use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface};
|
||||||
|
|
||||||
use super::{ResolvedWindowRules, WindowRef};
|
use super::{ResolvedWindowRules, WindowRef};
|
||||||
use crate::layout::{
|
use crate::layout::{LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot};
|
||||||
AnimationSnapshot, LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot,
|
|
||||||
};
|
|
||||||
use crate::niri::WindowOffscreenId;
|
use crate::niri::WindowOffscreenId;
|
||||||
use crate::render_helpers::renderer::NiriRenderer;
|
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::surface::render_snapshot_from_surface_tree;
|
||||||
use crate::render_helpers::{BakedBuffer, RenderSnapshot, RenderTarget};
|
use crate::render_helpers::{BakedBuffer, RenderTarget};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Mapped {
|
pub struct Mapped {
|
||||||
@@ -49,7 +48,7 @@ pub struct Mapped {
|
|||||||
block_out_buffer: RefCell<SolidColorBuffer>,
|
block_out_buffer: RefCell<SolidColorBuffer>,
|
||||||
|
|
||||||
/// Snapshot of the last render for use in the close animation.
|
/// 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.
|
/// Whether the next configure should be animated, if the configured state changed.
|
||||||
animate_next_configure: bool,
|
animate_next_configure: bool,
|
||||||
@@ -58,7 +57,7 @@ pub struct Mapped {
|
|||||||
animate_serials: Vec<Serial>,
|
animate_serials: Vec<Serial>,
|
||||||
|
|
||||||
/// Snapshot right before an animated commit.
|
/// Snapshot right before an animated commit.
|
||||||
animation_snapshot: Option<AnimationSnapshot>,
|
animation_snapshot: Option<LayoutElementRenderSnapshot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mapped {
|
impl Mapped {
|
||||||
@@ -70,7 +69,7 @@ impl Mapped {
|
|||||||
need_to_recompute_rules: false,
|
need_to_recompute_rules: false,
|
||||||
is_focused: false,
|
is_focused: false,
|
||||||
block_out_buffer: RefCell::new(SolidColorBuffer::new((0, 0), [0., 0., 0., 1.])),
|
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_next_configure: false,
|
||||||
animate_serials: Vec::new(),
|
animate_serials: Vec::new(),
|
||||||
animation_snapshot: None,
|
animation_snapshot: None,
|
||||||
@@ -118,14 +117,11 @@ impl Mapped {
|
|||||||
fn render_snapshot(&self, renderer: &mut GlesRenderer) -> LayoutElementRenderSnapshot {
|
fn render_snapshot(&self, renderer: &mut GlesRenderer) -> LayoutElementRenderSnapshot {
|
||||||
let _span = tracy_client::span!("Mapped::render_snapshot");
|
let _span = tracy_client::span!("Mapped::render_snapshot");
|
||||||
|
|
||||||
let mut snapshot = RenderSnapshot {
|
let size = self.size();
|
||||||
block_out_from: self.rules.block_out_from,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut buffer = self.block_out_buffer.borrow_mut();
|
let mut buffer = self.block_out_buffer.borrow_mut();
|
||||||
buffer.resize(self.window.geometry().size);
|
buffer.resize(size);
|
||||||
snapshot.blocked_out_contents = vec![BakedBuffer {
|
let blocked_out_contents = vec![BakedBuffer {
|
||||||
buffer: buffer.clone(),
|
buffer: buffer.clone(),
|
||||||
location: Point::from((0, 0)),
|
location: Point::from((0, 0)),
|
||||||
src: None,
|
src: None,
|
||||||
@@ -134,6 +130,8 @@ impl Mapped {
|
|||||||
|
|
||||||
let buf_pos = self.window.geometry().loc.upscale(-1);
|
let buf_pos = self.window.geometry().loc.upscale(-1);
|
||||||
|
|
||||||
|
let mut contents = vec![];
|
||||||
|
|
||||||
let surface = self.toplevel().wl_surface();
|
let surface = self.toplevel().wl_surface();
|
||||||
for (popup, popup_offset) in PopupManager::popups_for_surface(surface) {
|
for (popup, popup_offset) in PopupManager::popups_for_surface(surface) {
|
||||||
let offset = self.window.geometry().loc + popup_offset - popup.geometry().loc;
|
let offset = self.window.geometry().loc + popup_offset - popup.geometry().loc;
|
||||||
@@ -142,22 +140,29 @@ impl Mapped {
|
|||||||
renderer,
|
renderer,
|
||||||
popup.wl_surface(),
|
popup.wl_surface(),
|
||||||
buf_pos + offset,
|
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) {
|
pub fn store_unmap_snapshot_if_empty(&self, renderer: &mut GlesRenderer) {
|
||||||
let mut snapshot = self.last_render.borrow_mut();
|
let mut snapshot = self.unmap_snapshot.borrow_mut();
|
||||||
if !snapshot.contents.is_empty() {
|
if snapshot.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*snapshot = self.render_snapshot(renderer);
|
*snapshot = Some(self.render_snapshot(renderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_animate_commit(&mut self, commit_serial: Serial) -> bool {
|
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) {
|
pub fn store_animation_snapshot(&mut self, renderer: &mut GlesRenderer) {
|
||||||
self.animation_snapshot = Some(AnimationSnapshot {
|
self.animation_snapshot = Some(self.render_snapshot(renderer));
|
||||||
render: self.render_snapshot(renderer),
|
|
||||||
size: self.size(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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) {
|
fn request_size(&mut self, size: Size<i32, Logical>, animate: bool) {
|
||||||
let changed = self.toplevel().with_pending_state(|state| {
|
let changed = self.toplevel().with_pending_state(|state| {
|
||||||
let changed = state.size != Some(size);
|
let changed = state.size != Some(size);
|
||||||
@@ -382,11 +380,15 @@ impl LayoutElement for Mapped {
|
|||||||
&self.rules
|
&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()
|
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()
|
self.animation_snapshot.take()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user