diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/render_helpers/offscreen.rs | 83 |
1 files changed, 49 insertions, 34 deletions
diff --git a/src/render_helpers/offscreen.rs b/src/render_helpers/offscreen.rs index 9f4857af..b6bbbc12 100644 --- a/src/render_helpers/offscreen.rs +++ b/src/render_helpers/offscreen.rs @@ -2,15 +2,16 @@ use std::cell::RefCell; use anyhow::Context as _; use smithay::backend::allocator::Fourcc; +use smithay::backend::renderer::damage::OutputDamageTracker; use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement}; use smithay::backend::renderer::element::RenderElement; use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; use smithay::backend::renderer::sync::SyncPoint; -use smithay::backend::renderer::{Bind as _, Offscreen as _, Texture as _}; +use smithay::backend::renderer::{Bind as _, Color32F, Offscreen as _, Texture as _}; use smithay::utils::{Logical, Point, Scale, Transform}; +use super::encompassing_geo; use super::texture::TextureBuffer; -use super::{encompassing_geo, render_elements}; /// Buffer for offscreen rendering. #[derive(Debug)] @@ -18,7 +19,13 @@ pub struct OffscreenBuffer { /// The cached texture buffer. /// /// Lazily created when `render` is called. Recreated when necessary. - buffer: RefCell<Option<TextureBuffer<GlesTexture>>>, + inner: RefCell<Option<Inner>>, +} + +#[derive(Debug)] +struct Inner { + buffer: TextureBuffer<GlesTexture>, + damage: OutputDamageTracker, } impl OffscreenBuffer { @@ -31,20 +38,20 @@ impl OffscreenBuffer { let _span = tracy_client::span!("OffscreenBuffer::render"); let geo = encompassing_geo(scale, elements.iter()); - let elements = elements.iter().rev().map(|ele| { + let elements = Vec::from_iter(elements.iter().map(|ele| { RelocateRenderElement::from_element(ele, geo.loc.upscale(-1), Relocate::Relative) - }); + })); let buffer_size = geo.size.to_logical(1).to_buffer(1, Transform::Normal); let offset = geo.loc.to_f64().to_logical(scale); - let mut buffer = self.buffer.borrow_mut(); + let mut inner = self.inner.borrow_mut(); // Check if we need to create or recreate the texture. let size_string; let mut reason = ""; - if let Some(buf) = buffer.as_mut() { - let old_size = buf.texture().size(); + if let Some(Inner { buffer, .. }) = inner.as_mut() { + let old_size = buffer.texture().size(); if old_size != buffer_size { size_string = format!( "size changed from {} × {} to {} × {}", @@ -52,18 +59,18 @@ impl OffscreenBuffer { ); reason = &size_string; - *buffer = None; - } else if !buf.is_texture_reference_unique() { + *inner = None; + } else if !buffer.is_texture_reference_unique() { reason = "not unique"; - *buffer = None; + *inner = None; } } else { reason = "first render"; } - let buffer = if let Some(buffer) = buffer.as_mut() { - buffer + let inner = if let Some(inner) = inner.as_mut() { + inner } else { trace!("creating new texture: {reason}"); let span = tracy_client::span!("creating offscreen buffer"); @@ -73,44 +80,52 @@ impl OffscreenBuffer { .create_buffer(Fourcc::Abgr8888, buffer_size) .context("error creating texture")?; - buffer.insert(TextureBuffer::from_texture( + let buffer = TextureBuffer::from_texture( renderer, texture, scale, Transform::Normal, Vec::new(), - )) + ); + let damage = OutputDamageTracker::new(geo.size, scale, Transform::Normal); + + inner.insert(Inner { buffer, damage }) }; - // Update the texture scale. - buffer.set_texture_scale(scale); + // Recreate the damage tracker if the scale changes. We already recreate it for buffer size + // changes, and transform is always Normal. + if inner.buffer.texture_scale() != scale { + inner.buffer.set_texture_scale(scale); - // Increment the commit counter since we're rendering new contents to the buffer. - buffer.increment_commit_counter(); + trace!("recreating damage tracker due to scale change"); + inner.damage = OutputDamageTracker::new(geo.size, scale, Transform::Normal); + } - // Render to the buffer. - let mut texture = buffer.texture().clone(); - let mut target = renderer - .bind(&mut texture) - .context("error binding texture")?; + let res = { + let mut texture = inner.buffer.texture().clone(); + let mut target = renderer.bind(&mut texture)?; + inner.damage.render_output( + renderer, + &mut target, + 1, + &elements, + Color32F::TRANSPARENT, + )? + }; - let sync_point = render_elements( - renderer, - &mut target, - geo.size, - scale, - Transform::Normal, - elements, - )?; + if res.damage.is_some() { + // Increment the commit counter if some contents updated. + inner.buffer.increment_commit_counter(); + } - Ok((buffer.clone(), sync_point, offset)) + Ok((inner.buffer.clone(), res.sync, offset)) } } impl Default for OffscreenBuffer { fn default() -> Self { OffscreenBuffer { - buffer: RefCell::new(None), + inner: RefCell::new(None), } } } |
