diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-04-09 22:37:10 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-04-09 23:42:01 +0400 |
| commit | dd011f1012e10b1e3a1dbe100cb603a457bba12a (patch) | |
| tree | 2fb853be8bbe1ee5afdf3dea4974768874a5e793 /src/render_helpers | |
| parent | 301a2c06613c76d2c16a85ab21ad132e5618454b (diff) | |
| download | niri-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.rs | 25 | ||||
| -rw-r--r-- | src/render_helpers/surface.rs | 116 |
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, + ); +} |
