aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/layout/opening_window.rs29
-rw-r--r--src/render_helpers/offscreen.rs305
-rw-r--r--src/render_helpers/texture.rs11
3 files changed, 109 insertions, 236 deletions
diff --git a/src/layout/opening_window.rs b/src/layout/opening_window.rs
index f64aef88..860c8101 100644
--- a/src/layout/opening_window.rs
+++ b/src/layout/opening_window.rs
@@ -2,27 +2,27 @@ use std::collections::HashMap;
use anyhow::Context as _;
use glam::{Mat3, Vec2};
-use smithay::backend::allocator::Fourcc;
use smithay::backend::renderer::element::utils::{
Relocate, RelocateRenderElement, RescaleRenderElement,
};
use smithay::backend::renderer::element::{Kind, RenderElement};
use smithay::backend::renderer::gles::{GlesRenderer, Uniform};
use smithay::backend::renderer::Texture;
-use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
+use smithay::utils::{Logical, Point, Rectangle, Scale, Size};
use crate::animation::Animation;
use crate::niri_render_elements;
+use crate::render_helpers::offscreen::OffscreenBuffer;
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
-use crate::render_helpers::render_to_encompassing_texture;
use crate::render_helpers::shader_element::ShaderRenderElement;
use crate::render_helpers::shaders::{mat3_uniform, ProgramType, Shaders};
-use crate::render_helpers::texture::{TextureBuffer, TextureRenderElement};
+use crate::render_helpers::texture::TextureRenderElement;
#[derive(Debug)]
pub struct OpenAnimation {
anim: Animation,
random_seed: f32,
+ buffer: OffscreenBuffer,
}
niri_render_elements! {
@@ -37,6 +37,7 @@ impl OpenAnimation {
Self {
anim,
random_seed: fastrand::f32(),
+ buffer: OffscreenBuffer::default(),
}
}
@@ -59,17 +60,15 @@ impl OpenAnimation {
let progress = self.anim.value();
let clamped_progress = self.anim.clamped_value().clamp(0., 1.);
- let (texture, _sync_point, geo) = render_to_encompassing_texture(
- renderer,
- scale,
- Transform::Normal,
- Fourcc::Abgr8888,
- elements,
- )
- .context("error rendering to texture")?;
+ let (buffer, _sync_point, offset) = self
+ .buffer
+ .render(renderer, scale, elements)
+ .context("error rendering to offscreen buffer")?;
- let offset = geo.loc.to_f64().to_logical(scale);
- let texture_size = geo.size.to_f64().to_logical(scale);
+ // OffscreenBuffer renders with Transform::Normal and the scale that we passed, so we can
+ // assume that below.
+ let texture = buffer.texture();
+ let texture_size = buffer.logical_size();
if Shaders::get(renderer).program(ProgramType::Open).is_some() {
let mut area = Rectangle::new(location + offset, texture_size);
@@ -120,8 +119,6 @@ impl OpenAnimation {
.into());
}
- let buffer =
- TextureBuffer::from_texture(renderer, texture, scale, Transform::Normal, Vec::new());
let elem = TextureRenderElement::from_texture_buffer(
buffer,
Point::from((0., 0.)),
diff --git a/src/render_helpers/offscreen.rs b/src/render_helpers/offscreen.rs
index 9005e80c..9f4857af 100644
--- a/src/render_helpers/offscreen.rs
+++ b/src/render_helpers/offscreen.rs
@@ -1,251 +1,116 @@
+use std::cell::RefCell;
+
+use anyhow::Context as _;
use smithay::backend::allocator::Fourcc;
-use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
-use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
-use smithay::backend::renderer::gles::{GlesError, GlesFrame, GlesRenderer};
-use smithay::backend::renderer::utils::{CommitCounter, DamageSet, OpaqueRegions};
-use smithay::utils::{Buffer, Physical, Rectangle, Scale, Transform};
-
-use super::primary_gpu_texture::PrimaryGpuTextureRenderElement;
-use super::render_to_texture;
-use super::renderer::AsGlesFrame;
-use super::texture::{TextureBuffer, TextureRenderElement};
-use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
-
-/// Renders elements into an off-screen buffer.
+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::utils::{Logical, Point, Scale, Transform};
+
+use super::texture::TextureBuffer;
+use super::{encompassing_geo, render_elements};
+
+/// Buffer for offscreen rendering.
#[derive(Debug)]
-pub struct OffscreenRenderElement {
- // The texture, if rendering succeeded.
- texture: Option<PrimaryGpuTextureRenderElement>,
- // The fallback buffer in case the rendering fails.
- fallback: SolidColorRenderElement,
+pub struct OffscreenBuffer {
+ /// The cached texture buffer.
+ ///
+ /// Lazily created when `render` is called. Recreated when necessary.
+ buffer: RefCell<Option<TextureBuffer<GlesTexture>>>,
}
-impl OffscreenRenderElement {
- pub fn new(
+impl OffscreenBuffer {
+ pub fn render(
+ &self,
renderer: &mut GlesRenderer,
- scale: i32,
+ scale: Scale<f64>,
elements: &[impl RenderElement<GlesRenderer>],
- result_alpha: f32,
- ) -> Self {
- let _span = tracy_client::span!("OffscreenRenderElement::new");
-
- let geo = elements
- .iter()
- .map(|ele| ele.geometry(Scale::from(f64::from(scale))))
- .reduce(|a, b| a.merge(b))
- .unwrap_or_default();
- let logical_size = geo.size.to_logical(scale);
-
- let fallback_buffer = SolidColorBuffer::new(logical_size, [1., 0., 0., 1.]);
- let fallback = SolidColorRenderElement::from_buffer(
- &fallback_buffer,
- geo.loc,
- Scale::from(scale as f64),
- result_alpha,
- Kind::Unspecified,
- );
+ ) -> anyhow::Result<(TextureBuffer<GlesTexture>, SyncPoint, Point<f64, Logical>)> {
+ let _span = tracy_client::span!("OffscreenBuffer::render");
+ let geo = encompassing_geo(scale, elements.iter());
let elements = elements.iter().rev().map(|ele| {
- RelocateRenderElement::from_element(ele, (-geo.loc.x, -geo.loc.y), Relocate::Relative)
+ RelocateRenderElement::from_element(ele, geo.loc.upscale(-1), Relocate::Relative)
});
- match render_to_texture(
- renderer,
- geo.size,
- Scale::from(scale as f64),
- Transform::Normal,
- Fourcc::Abgr8888,
- elements,
- ) {
- Ok((texture, _sync_point)) => {
- let buffer = TextureBuffer::from_texture(
- renderer,
- texture,
- scale as f64,
- Transform::Normal,
- Vec::new(),
- );
- let element = TextureRenderElement::from_texture_buffer(
- buffer,
- geo.loc.to_f64().to_logical(scale as f64),
- result_alpha,
- None,
- None,
- Kind::Unspecified,
- );
- Self {
- texture: Some(PrimaryGpuTextureRenderElement(element)),
- fallback,
- }
- }
- Err(err) => {
- warn!("error off-screening elements: {err:?}");
- Self {
- texture: None,
- fallback,
- }
- }
- }
- }
-}
+ let buffer_size = geo.size.to_logical(1).to_buffer(1, Transform::Normal);
+ let offset = geo.loc.to_f64().to_logical(scale);
-impl Element for OffscreenRenderElement {
- fn id(&self) -> &Id {
- if let Some(texture) = &self.texture {
- texture.id()
- } else {
- self.fallback.id()
- }
- }
+ let mut buffer = self.buffer.borrow_mut();
- fn current_commit(&self) -> CommitCounter {
- if let Some(texture) = &self.texture {
- texture.current_commit()
- } else {
- self.fallback.current_commit()
- }
- }
+ // 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 old_size != buffer_size {
+ size_string = format!(
+ "size changed from {} × {} to {} × {}",
+ old_size.w, old_size.h, buffer_size.w, buffer_size.h
+ );
+ reason = &size_string;
- fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
- if let Some(texture) = &self.texture {
- texture.geometry(scale)
- } else {
- self.fallback.geometry(scale)
- }
- }
+ *buffer = None;
+ } else if !buf.is_texture_reference_unique() {
+ reason = "not unique";
- fn transform(&self) -> Transform {
- if let Some(texture) = &self.texture {
- texture.transform()
+ *buffer = None;
+ }
} else {
- self.fallback.transform()
+ reason = "first render";
}
- }
- fn src(&self) -> Rectangle<f64, Buffer> {
- if let Some(texture) = &self.texture {
- texture.src()
+ let buffer = if let Some(buffer) = buffer.as_mut() {
+ buffer
} else {
- self.fallback.src()
- }
- }
+ trace!("creating new texture: {reason}");
+ let span = tracy_client::span!("creating offscreen buffer");
+ span.emit_text(reason);
- fn damage_since(
- &self,
- scale: Scale<f64>,
- commit: Option<CommitCounter>,
- ) -> DamageSet<i32, Physical> {
- if let Some(texture) = &self.texture {
- texture.damage_since(scale, commit)
- } else {
- self.fallback.damage_since(scale, commit)
- }
- }
+ let texture: GlesTexture = renderer
+ .create_buffer(Fourcc::Abgr8888, buffer_size)
+ .context("error creating texture")?;
- fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> {
- if let Some(texture) = &self.texture {
- texture.opaque_regions(scale)
- } else {
- self.fallback.opaque_regions(scale)
- }
- }
+ buffer.insert(TextureBuffer::from_texture(
+ renderer,
+ texture,
+ scale,
+ Transform::Normal,
+ Vec::new(),
+ ))
+ };
- fn alpha(&self) -> f32 {
- if let Some(texture) = &self.texture {
- texture.alpha()
- } else {
- self.fallback.alpha()
- }
- }
+ // Update the texture scale.
+ buffer.set_texture_scale(scale);
- fn kind(&self) -> Kind {
- if let Some(texture) = &self.texture {
- texture.kind()
- } else {
- self.fallback.kind()
- }
- }
-}
+ // Increment the commit counter since we're rendering new contents to the buffer.
+ buffer.increment_commit_counter();
-impl RenderElement<GlesRenderer> for OffscreenRenderElement {
- fn draw(
- &self,
- frame: &mut GlesFrame<'_, '_>,
- src: Rectangle<f64, Buffer>,
- dst: Rectangle<i32, Physical>,
- damage: &[Rectangle<i32, Physical>],
- opaque_regions: &[Rectangle<i32, Physical>],
- ) -> Result<(), GlesError> {
- let gles_frame = frame.as_gles_frame();
- if let Some(texture) = &self.texture {
- RenderElement::<GlesRenderer>::draw(
- texture,
- gles_frame,
- src,
- dst,
- damage,
- opaque_regions,
- )?;
- } else {
- RenderElement::<GlesRenderer>::draw(
- &self.fallback,
- gles_frame,
- src,
- dst,
- damage,
- opaque_regions,
- )?;
- }
- Ok(())
- }
+ // Render to the buffer.
+ let mut texture = buffer.texture().clone();
+ let mut target = renderer
+ .bind(&mut texture)
+ .context("error binding texture")?;
- fn underlying_storage(&self, renderer: &mut GlesRenderer) -> Option<UnderlyingStorage> {
- if let Some(texture) = &self.texture {
- texture.underlying_storage(renderer)
- } else {
- self.fallback.underlying_storage(renderer)
- }
- }
-}
+ let sync_point = render_elements(
+ renderer,
+ &mut target,
+ geo.size,
+ scale,
+ Transform::Normal,
+ elements,
+ )?;
-impl<'render> RenderElement<TtyRenderer<'render>> for OffscreenRenderElement {
- fn draw(
- &self,
- frame: &mut TtyFrame<'_, '_, '_>,
- src: Rectangle<f64, Buffer>,
- dst: Rectangle<i32, Physical>,
- damage: &[Rectangle<i32, Physical>],
- opaque_regions: &[Rectangle<i32, Physical>],
- ) -> Result<(), TtyRendererError<'render>> {
- let gles_frame = frame.as_gles_frame();
- if let Some(texture) = &self.texture {
- RenderElement::<GlesRenderer>::draw(
- texture,
- gles_frame,
- src,
- dst,
- damage,
- opaque_regions,
- )?;
- } else {
- RenderElement::<GlesRenderer>::draw(
- &self.fallback,
- gles_frame,
- src,
- dst,
- damage,
- opaque_regions,
- )?;
- }
- Ok(())
+ Ok((buffer.clone(), sync_point, offset))
}
+}
- fn underlying_storage(&self, renderer: &mut TtyRenderer<'render>) -> Option<UnderlyingStorage> {
- if let Some(texture) = &self.texture {
- texture.underlying_storage(renderer)
- } else {
- self.fallback.underlying_storage(renderer)
+impl Default for OffscreenBuffer {
+ fn default() -> Self {
+ OffscreenBuffer {
+ buffer: RefCell::new(None),
}
}
}
diff --git a/src/render_helpers/texture.rs b/src/render_helpers/texture.rs
index a5d38a6f..e88ac0e3 100644
--- a/src/render_helpers/texture.rs
+++ b/src/render_helpers/texture.rs
@@ -1,5 +1,6 @@
use smithay::backend::allocator::Fourcc;
use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement, UnderlyingStorage};
+use smithay::backend::renderer::gles::GlesTexture;
use smithay::backend::renderer::utils::{CommitCounter, OpaqueRegions};
use smithay::backend::renderer::{Frame as _, ImportMem, Renderer, Texture};
use smithay::utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Size, Transform};
@@ -104,6 +105,10 @@ impl<T> TextureBuffer<T> {
pub fn set_texture_transform(&mut self, transform: Transform) {
self.transform = transform;
}
+
+ pub fn increment_commit_counter(&mut self) {
+ self.commit_counter.increment();
+ }
}
impl<T: Texture> TextureBuffer<T> {
@@ -115,6 +120,12 @@ impl<T: Texture> TextureBuffer<T> {
}
}
+impl TextureBuffer<GlesTexture> {
+ pub fn is_texture_reference_unique(&mut self) -> bool {
+ self.texture.is_unique_reference()
+ }
+}
+
impl<T> TextureRenderElement<T> {
pub fn from_texture_buffer(
buffer: TextureBuffer<T>,