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 { /// Contents for a normal render. /// /// Relative to the geometry. pub contents: Vec, /// Blocked-out contents. /// /// Relative to the geometry. pub blocked_out_contents: Vec, /// Where the contents were blocked out from at the time of the snapshot. pub block_out_from: Option, /// Visual size of the element at the point of the snapshot. pub size: Size, /// Contents rendered into a texture (lazily). pub texture: OnceCell)>>, /// Blocked-out contents rendered into a texture (lazily). pub blocked_out_texture: OnceCell)>>, } impl RenderSnapshot where C: ToRenderElement, B: ToRenderElement, EC: RenderElement, EB: RenderElement, { pub fn texture( &self, renderer: &mut GlesRenderer, scale: Scale, target: RenderTarget, ) -> Option<&(GlesTexture, Rectangle)> { 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() } }