mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
offscreen: Take damage into account when rendering
Does not yet signal the damage outside, but does skip rerendering if there was no damage.
This commit is contained in:
@@ -2,15 +2,16 @@ use std::cell::RefCell;
|
|||||||
|
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use smithay::backend::allocator::Fourcc;
|
use smithay::backend::allocator::Fourcc;
|
||||||
|
use smithay::backend::renderer::damage::OutputDamageTracker;
|
||||||
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
|
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
|
||||||
use smithay::backend::renderer::element::RenderElement;
|
use smithay::backend::renderer::element::RenderElement;
|
||||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
||||||
use smithay::backend::renderer::sync::SyncPoint;
|
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 smithay::utils::{Logical, Point, Scale, Transform};
|
||||||
|
|
||||||
|
use super::encompassing_geo;
|
||||||
use super::texture::TextureBuffer;
|
use super::texture::TextureBuffer;
|
||||||
use super::{encompassing_geo, render_elements};
|
|
||||||
|
|
||||||
/// Buffer for offscreen rendering.
|
/// Buffer for offscreen rendering.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -18,7 +19,13 @@ pub struct OffscreenBuffer {
|
|||||||
/// The cached texture buffer.
|
/// The cached texture buffer.
|
||||||
///
|
///
|
||||||
/// Lazily created when `render` is called. Recreated when necessary.
|
/// 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 {
|
impl OffscreenBuffer {
|
||||||
@@ -31,20 +38,20 @@ impl OffscreenBuffer {
|
|||||||
let _span = tracy_client::span!("OffscreenBuffer::render");
|
let _span = tracy_client::span!("OffscreenBuffer::render");
|
||||||
|
|
||||||
let geo = encompassing_geo(scale, elements.iter());
|
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)
|
RelocateRenderElement::from_element(ele, geo.loc.upscale(-1), Relocate::Relative)
|
||||||
});
|
}));
|
||||||
|
|
||||||
let buffer_size = geo.size.to_logical(1).to_buffer(1, Transform::Normal);
|
let buffer_size = geo.size.to_logical(1).to_buffer(1, Transform::Normal);
|
||||||
let offset = geo.loc.to_f64().to_logical(scale);
|
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.
|
// Check if we need to create or recreate the texture.
|
||||||
let size_string;
|
let size_string;
|
||||||
let mut reason = "";
|
let mut reason = "";
|
||||||
if let Some(buf) = buffer.as_mut() {
|
if let Some(Inner { buffer, .. }) = inner.as_mut() {
|
||||||
let old_size = buf.texture().size();
|
let old_size = buffer.texture().size();
|
||||||
if old_size != buffer_size {
|
if old_size != buffer_size {
|
||||||
size_string = format!(
|
size_string = format!(
|
||||||
"size changed from {} × {} to {} × {}",
|
"size changed from {} × {} to {} × {}",
|
||||||
@@ -52,18 +59,18 @@ impl OffscreenBuffer {
|
|||||||
);
|
);
|
||||||
reason = &size_string;
|
reason = &size_string;
|
||||||
|
|
||||||
*buffer = None;
|
*inner = None;
|
||||||
} else if !buf.is_texture_reference_unique() {
|
} else if !buffer.is_texture_reference_unique() {
|
||||||
reason = "not unique";
|
reason = "not unique";
|
||||||
|
|
||||||
*buffer = None;
|
*inner = None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reason = "first render";
|
reason = "first render";
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = if let Some(buffer) = buffer.as_mut() {
|
let inner = if let Some(inner) = inner.as_mut() {
|
||||||
buffer
|
inner
|
||||||
} else {
|
} else {
|
||||||
trace!("creating new texture: {reason}");
|
trace!("creating new texture: {reason}");
|
||||||
let span = tracy_client::span!("creating offscreen buffer");
|
let span = tracy_client::span!("creating offscreen buffer");
|
||||||
@@ -73,44 +80,52 @@ impl OffscreenBuffer {
|
|||||||
.create_buffer(Fourcc::Abgr8888, buffer_size)
|
.create_buffer(Fourcc::Abgr8888, buffer_size)
|
||||||
.context("error creating texture")?;
|
.context("error creating texture")?;
|
||||||
|
|
||||||
buffer.insert(TextureBuffer::from_texture(
|
let buffer = TextureBuffer::from_texture(
|
||||||
renderer,
|
renderer,
|
||||||
texture,
|
texture,
|
||||||
scale,
|
scale,
|
||||||
Transform::Normal,
|
Transform::Normal,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
))
|
);
|
||||||
|
let damage = OutputDamageTracker::new(geo.size, scale, Transform::Normal);
|
||||||
|
|
||||||
|
inner.insert(Inner { buffer, damage })
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the texture scale.
|
// Recreate the damage tracker if the scale changes. We already recreate it for buffer size
|
||||||
buffer.set_texture_scale(scale);
|
// 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.
|
trace!("recreating damage tracker due to scale change");
|
||||||
buffer.increment_commit_counter();
|
inner.damage = OutputDamageTracker::new(geo.size, scale, Transform::Normal);
|
||||||
|
}
|
||||||
|
|
||||||
// Render to the buffer.
|
let res = {
|
||||||
let mut texture = buffer.texture().clone();
|
let mut texture = inner.buffer.texture().clone();
|
||||||
let mut target = renderer
|
let mut target = renderer.bind(&mut texture)?;
|
||||||
.bind(&mut texture)
|
inner.damage.render_output(
|
||||||
.context("error binding texture")?;
|
|
||||||
|
|
||||||
let sync_point = render_elements(
|
|
||||||
renderer,
|
renderer,
|
||||||
&mut target,
|
&mut target,
|
||||||
geo.size,
|
1,
|
||||||
scale,
|
&elements,
|
||||||
Transform::Normal,
|
Color32F::TRANSPARENT,
|
||||||
elements,
|
)?
|
||||||
)?;
|
};
|
||||||
|
|
||||||
Ok((buffer.clone(), sync_point, offset))
|
if res.damage.is_some() {
|
||||||
|
// Increment the commit counter if some contents updated.
|
||||||
|
inner.buffer.increment_commit_counter();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((inner.buffer.clone(), res.sync, offset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for OffscreenBuffer {
|
impl Default for OffscreenBuffer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
OffscreenBuffer {
|
OffscreenBuffer {
|
||||||
buffer: RefCell::new(None),
|
inner: RefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user