aboutsummaryrefslogtreecommitdiff
path: root/src/render_helpers
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-04-09 22:37:10 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-04-09 23:42:01 +0400
commitdd011f1012e10b1e3a1dbe100cb603a457bba12a (patch)
tree2fb853be8bbe1ee5afdf3dea4974768874a5e793 /src/render_helpers
parent301a2c06613c76d2c16a85ab21ad132e5618454b (diff)
downloadniri-dd011f1012e10b1e3a1dbe100cb603a457bba12a.tar.gz
niri-dd011f1012e10b1e3a1dbe100cb603a457bba12a.tar.bz2
niri-dd011f1012e10b1e3a1dbe100cb603a457bba12a.zip
Implement window closing animations
Diffstat (limited to 'src/render_helpers')
-rw-r--r--src/render_helpers/mod.rs25
-rw-r--r--src/render_helpers/surface.rs116
2 files changed, 141 insertions, 0 deletions
diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs
index 238ad8ec..c6c9fed1 100644
--- a/src/render_helpers/mod.rs
+++ b/src/render_helpers/mod.rs
@@ -1,6 +1,7 @@
use std::ptr;
use anyhow::{ensure, Context};
+use niri_config::BlockOutFrom;
use smithay::backend::allocator::Fourcc;
use smithay::backend::renderer::element::RenderElement;
use smithay::backend::renderer::gles::{GlesMapping, GlesRenderer, GlesTexture};
@@ -18,6 +19,7 @@ pub mod primary_gpu_texture;
pub mod render_elements;
pub mod renderer;
pub mod shaders;
+pub mod surface;
/// What we're rendering for.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -30,6 +32,29 @@ pub enum RenderTarget {
ScreenCapture,
}
+/// Snapshot of a render.
+#[derive(Debug)]
+pub struct RenderSnapshot<E> {
+ /// Contents for a normal render.
+ pub contents: Vec<E>,
+
+ /// Blocked-out contents.
+ pub blocked_out_contents: Vec<E>,
+
+ /// Where the contents were blocked out from at the time of the snapshot.
+ pub block_out_from: Option<BlockOutFrom>,
+}
+
+impl<E> Default for RenderSnapshot<E> {
+ fn default() -> Self {
+ Self {
+ contents: Default::default(),
+ blocked_out_contents: Default::default(),
+ block_out_from: Default::default(),
+ }
+ }
+}
+
pub fn render_to_texture(
renderer: &mut GlesRenderer,
size: Size<i32, Physical>,
diff --git a/src/render_helpers/surface.rs b/src/render_helpers/surface.rs
new file mode 100644
index 00000000..ae7ffc32
--- /dev/null
+++ b/src/render_helpers/surface.rs
@@ -0,0 +1,116 @@
+use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
+use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement};
+use smithay::backend::renderer::element::Kind;
+use smithay::backend::renderer::gles::GlesRenderer;
+use smithay::backend::renderer::utils::{import_surface, RendererSurfaceStateUserData};
+use smithay::backend::renderer::Renderer as _;
+use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
+use smithay::utils::{Physical, Point, Scale};
+use smithay::wayland::compositor::{with_surface_tree_downward, TraversalAction};
+
+use super::primary_gpu_texture::PrimaryGpuTextureRenderElement;
+use super::renderer::NiriRenderer;
+use crate::layout::{LayoutElementRenderElement, LayoutElementSnapshotRenderElements};
+
+/// Renders elements from a surface tree, as well as saves them as textures into `storage`.
+///
+/// Saved textures are based at (0, 0) to facilitate later offscreening. This is why the location
+/// argument is split into `location` and `offset`: the former is ignored for saved textures, but
+/// the latter isn't (for things like popups).
+#[allow(clippy::too_many_arguments)]
+pub fn render_and_save_from_surface_tree<R: NiriRenderer>(
+ renderer: &mut R,
+ surface: &WlSurface,
+ location: Point<f64, Physical>,
+ offset: Point<f64, Physical>,
+ scale: Scale<f64>,
+ alpha: f32,
+ kind: Kind,
+ elements: &mut Vec<LayoutElementRenderElement<R>>,
+ storage: &mut Option<&mut Vec<LayoutElementSnapshotRenderElements>>,
+) {
+ let _span = tracy_client::span!("render_and_save_from_surface_tree");
+
+ let base_pos = location;
+
+ with_surface_tree_downward(
+ surface,
+ location + offset,
+ |_, states, location| {
+ let mut location = *location;
+ let data = states.data_map.get::<RendererSurfaceStateUserData>();
+
+ if let Some(data) = data {
+ let data = &*data.borrow();
+
+ if let Some(view) = data.view() {
+ location += view.offset.to_f64().to_physical(scale);
+ TraversalAction::DoChildren(location)
+ } else {
+ TraversalAction::SkipChildren
+ }
+ } else {
+ TraversalAction::SkipChildren
+ }
+ },
+ |surface, states, location| {
+ let mut location = *location;
+ let data = states.data_map.get::<RendererSurfaceStateUserData>();
+
+ if let Some(data) = data {
+ if let Some(view) = data.borrow().view() {
+ location += view.offset.to_f64().to_physical(scale);
+ } else {
+ return;
+ }
+
+ let elem = match WaylandSurfaceRenderElement::from_surface(
+ renderer, surface, states, location, alpha, kind,
+ ) {
+ Ok(elem) => elem,
+ Err(err) => {
+ warn!("failed to import surface: {err:?}");
+ return;
+ }
+ };
+
+ elements.push(elem.into());
+
+ if let Some(storage) = storage {
+ let renderer = renderer.as_gles_renderer();
+ // FIXME (possibly in Smithay): this causes a re-upload for shm textures.
+ if let Err(err) = import_surface(renderer, states) {
+ warn!("failed to import surface: {err:?}");
+ return;
+ }
+
+ let data = data.borrow();
+ let view = data.view().unwrap();
+ let Some(texture) = data.texture::<GlesRenderer>(renderer.id()) else {
+ return;
+ };
+
+ let buffer = TextureBuffer::from_texture(
+ renderer,
+ texture.clone(),
+ data.buffer_scale(),
+ data.buffer_transform(),
+ None,
+ );
+
+ let elem = TextureRenderElement::from_texture_buffer(
+ location - base_pos,
+ &buffer,
+ Some(alpha),
+ Some(view.src),
+ Some(view.dst),
+ kind,
+ );
+
+ storage.push(PrimaryGpuTextureRenderElement(elem).into());
+ }
+ }
+ },
+ |_, _, _| true,
+ );
+}