diff options
Diffstat (limited to 'src/render_helpers')
| -rw-r--r-- | src/render_helpers/mod.rs | 81 | ||||
| -rw-r--r-- | src/render_helpers/surface.rs | 108 |
2 files changed, 112 insertions, 77 deletions
diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs index c6c9fed1..e780de4e 100644 --- a/src/render_helpers/mod.rs +++ b/src/render_helpers/mod.rs @@ -3,15 +3,19 @@ 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::element::solid::{SolidColorBuffer, SolidColorRenderElement}; +use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement}; +use smithay::backend::renderer::element::{Kind, RenderElement}; use smithay::backend::renderer::gles::{GlesMapping, GlesRenderer, GlesTexture}; use smithay::backend::renderer::sync::SyncPoint; use smithay::backend::renderer::{buffer_dimensions, Bind, ExportMem, Frame, Offscreen, Renderer}; use smithay::reexports::wayland_server::protocol::wl_buffer::WlBuffer; use smithay::reexports::wayland_server::protocol::wl_shm; -use smithay::utils::{Physical, Rectangle, Scale, Size, Transform}; +use smithay::utils::{Logical, Physical, Point, Rectangle, Scale, Size, Transform}; use smithay::wayland::shm; +use self::primary_gpu_texture::PrimaryGpuTextureRenderElement; + pub mod gradient; pub mod offscreen; pub mod primary_gpu_pixel_shader; @@ -32,20 +36,85 @@ pub enum RenderTarget { ScreenCapture, } +/// Buffer with location, src and dst. +#[derive(Debug)] +pub struct BakedBuffer<B> { + pub buffer: B, + pub location: Point<i32, Logical>, + pub src: Option<Rectangle<f64, Logical>>, + pub dst: Option<Size<i32, Logical>>, +} + /// Snapshot of a render. #[derive(Debug)] -pub struct RenderSnapshot<E> { +pub struct RenderSnapshot<C, B> { /// Contents for a normal render. - pub contents: Vec<E>, + pub contents: Vec<C>, /// Blocked-out contents. - pub blocked_out_contents: Vec<E>, + 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>, } -impl<E> Default for RenderSnapshot<E> { +pub trait ToRenderElement { + type RenderElement; + + fn to_render_element( + &self, + location: Point<i32, Logical>, + scale: Scale<f64>, + alpha: f32, + kind: Kind, + ) -> Self::RenderElement; +} + +impl ToRenderElement for BakedBuffer<TextureBuffer<GlesTexture>> { + type RenderElement = PrimaryGpuTextureRenderElement; + + fn to_render_element( + &self, + location: Point<i32, Logical>, + scale: Scale<f64>, + alpha: f32, + kind: Kind, + ) -> Self::RenderElement { + let elem = TextureRenderElement::from_texture_buffer( + (location + self.location).to_physical_precise_round(scale), + &self.buffer, + Some(alpha), + self.src, + self.dst, + kind, + ); + PrimaryGpuTextureRenderElement(elem) + } +} + +impl ToRenderElement for BakedBuffer<SolidColorBuffer> { + type RenderElement = SolidColorRenderElement; + + fn to_render_element( + &self, + location: Point<i32, Logical>, + scale: Scale<f64>, + alpha: f32, + kind: Kind, + ) -> Self::RenderElement { + SolidColorRenderElement::from_buffer( + &self.buffer, + (location + self.location) + .to_physical_precise_round(scale) + .to_i32_round(), + scale, + alpha, + kind, + ) + } +} + +impl<C, B> Default for RenderSnapshot<C, B> { fn default() -> Self { Self { contents: Default::default(), diff --git a/src/render_helpers/surface.rs b/src/render_helpers/surface.rs index ae7ffc32..21141b30 100644 --- a/src/render_helpers/surface.rs +++ b/src/render_helpers/surface.rs @@ -1,41 +1,25 @@ -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::element::texture::TextureBuffer; +use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; 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::utils::{Logical, Point}; use smithay::wayland::compositor::{with_surface_tree_downward, TraversalAction}; -use super::primary_gpu_texture::PrimaryGpuTextureRenderElement; -use super::renderer::NiriRenderer; -use crate::layout::{LayoutElementRenderElement, LayoutElementSnapshotRenderElements}; +use super::BakedBuffer; -/// 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, +/// Renders elements from a surface tree as textures into `storage`. +pub fn render_snapshot_from_surface_tree( + renderer: &mut GlesRenderer, 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>>, + location: Point<i32, Logical>, + storage: &mut Vec<BakedBuffer<TextureBuffer<GlesTexture>>>, ) { - let _span = tracy_client::span!("render_and_save_from_surface_tree"); - - let base_pos = location; + let _span = tracy_client::span!("render_snapshot_from_surface_tree"); with_surface_tree_downward( surface, - location + offset, + location, |_, states, location| { let mut location = *location; let data = states.data_map.get::<RendererSurfaceStateUserData>(); @@ -44,7 +28,7 @@ pub fn render_and_save_from_surface_tree<R: NiriRenderer>( let data = &*data.borrow(); if let Some(view) = data.view() { - location += view.offset.to_f64().to_physical(scale); + location += view.offset; TraversalAction::DoChildren(location) } else { TraversalAction::SkipChildren @@ -53,62 +37,44 @@ pub fn render_and_save_from_surface_tree<R: NiriRenderer>( TraversalAction::SkipChildren } }, - |surface, states, location| { + |_, 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); + location += view.offset; } 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; - } + 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 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 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, - ); + let baked = BakedBuffer { + buffer, + location, + src: Some(view.src), + dst: Some(view.dst), + }; - storage.push(PrimaryGpuTextureRenderElement(elem).into()); - } + storage.push(baked); } }, |_, _, _| true, |
