aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/render_helpers/offscreen.rs83
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),
}
}
}