mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
Add OffscreenRenderElement
This commit is contained in:
@@ -6,6 +6,7 @@ use smithay::backend::renderer::sync::SyncPoint;
|
|||||||
use smithay::backend::renderer::{Bind, ExportMem, Frame, Offscreen, Renderer};
|
use smithay::backend::renderer::{Bind, ExportMem, Frame, Offscreen, Renderer};
|
||||||
use smithay::utils::{Physical, Rectangle, Scale, Size, Transform};
|
use smithay::utils::{Physical, Rectangle, Scale, Size, Transform};
|
||||||
|
|
||||||
|
pub mod offscreen;
|
||||||
pub mod primary_gpu_texture;
|
pub mod primary_gpu_texture;
|
||||||
pub mod render_elements;
|
pub mod render_elements;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
|
|||||||
@@ -0,0 +1,216 @@
|
|||||||
|
use smithay::backend::allocator::Fourcc;
|
||||||
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
|
use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement};
|
||||||
|
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;
|
||||||
|
use smithay::utils::{Buffer, Physical, Rectangle, Scale, Transform};
|
||||||
|
|
||||||
|
use super::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
||||||
|
use super::render_to_texture;
|
||||||
|
use super::renderer::AsGlesFrame;
|
||||||
|
use crate::backend::tty::{TtyFrame, TtyRenderer, TtyRendererError};
|
||||||
|
|
||||||
|
/// Renders elements into an off-screen buffer.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OffscreenRenderElement {
|
||||||
|
// The texture, if rendering succeeded.
|
||||||
|
texture: Option<PrimaryGpuTextureRenderElement>,
|
||||||
|
// The fallback buffer in case the rendering fails.
|
||||||
|
fallback: SolidColorRenderElement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OffscreenRenderElement {
|
||||||
|
pub fn new(
|
||||||
|
renderer: &mut GlesRenderer,
|
||||||
|
scale: i32,
|
||||||
|
elements: &[impl RenderElement<GlesRenderer>],
|
||||||
|
result_alpha: f32,
|
||||||
|
) -> Self {
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
|
let elements = elements.iter().rev().map(|ele| {
|
||||||
|
RelocateRenderElement::from_element(ele, (-geo.loc.x, -geo.loc.y), Relocate::Relative)
|
||||||
|
});
|
||||||
|
|
||||||
|
match render_to_texture(
|
||||||
|
renderer,
|
||||||
|
geo.size,
|
||||||
|
Scale::from(scale as f64),
|
||||||
|
Fourcc::Abgr8888,
|
||||||
|
elements,
|
||||||
|
) {
|
||||||
|
Ok((texture, _sync_point)) => {
|
||||||
|
let buffer =
|
||||||
|
TextureBuffer::from_texture(renderer, texture, scale, Transform::Normal, None);
|
||||||
|
let element = TextureRenderElement::from_texture_buffer(
|
||||||
|
geo.loc.to_f64(),
|
||||||
|
&buffer,
|
||||||
|
Some(result_alpha),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Kind::Unspecified,
|
||||||
|
);
|
||||||
|
Self {
|
||||||
|
texture: Some(PrimaryGpuTextureRenderElement(element)),
|
||||||
|
fallback,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!("error off-screening elements: {err:?}");
|
||||||
|
Self {
|
||||||
|
texture: None,
|
||||||
|
fallback,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element for OffscreenRenderElement {
|
||||||
|
fn id(&self) -> &Id {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.id()
|
||||||
|
} else {
|
||||||
|
self.fallback.id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_commit(&self) -> CommitCounter {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.current_commit()
|
||||||
|
} else {
|
||||||
|
self.fallback.current_commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.geometry(scale)
|
||||||
|
} else {
|
||||||
|
self.fallback.geometry(scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform(&self) -> Transform {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.transform()
|
||||||
|
} else {
|
||||||
|
self.fallback.transform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn src(&self) -> Rectangle<f64, Buffer> {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.src()
|
||||||
|
} else {
|
||||||
|
self.fallback.src()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn damage_since(
|
||||||
|
&self,
|
||||||
|
scale: Scale<f64>,
|
||||||
|
commit: Option<CommitCounter>,
|
||||||
|
) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.damage_since(scale, commit)
|
||||||
|
} else {
|
||||||
|
self.fallback.damage_since(scale, commit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.opaque_regions(scale)
|
||||||
|
} else {
|
||||||
|
self.fallback.opaque_regions(scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alpha(&self) -> f32 {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.alpha()
|
||||||
|
} else {
|
||||||
|
self.fallback.alpha()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kind(&self) -> Kind {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.kind()
|
||||||
|
} else {
|
||||||
|
self.fallback.kind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderElement<GlesRenderer> for OffscreenRenderElement {
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut GlesFrame<'_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[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)?;
|
||||||
|
} else {
|
||||||
|
RenderElement::<GlesRenderer>::draw(&self.fallback, gles_frame, src, dst, damage)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'render, 'alloc> RenderElement<TtyRenderer<'render, 'alloc>> for OffscreenRenderElement {
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
frame: &mut TtyFrame<'_, '_, '_>,
|
||||||
|
src: Rectangle<f64, Buffer>,
|
||||||
|
dst: Rectangle<i32, Physical>,
|
||||||
|
damage: &[Rectangle<i32, Physical>],
|
||||||
|
) -> Result<(), TtyRendererError<'render, 'alloc>> {
|
||||||
|
let gles_frame = frame.as_gles_frame();
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
RenderElement::<GlesRenderer>::draw(texture, gles_frame, src, dst, damage)?;
|
||||||
|
} else {
|
||||||
|
RenderElement::<GlesRenderer>::draw(&self.fallback, gles_frame, src, dst, damage)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underlying_storage(
|
||||||
|
&self,
|
||||||
|
renderer: &mut TtyRenderer<'render, 'alloc>,
|
||||||
|
) -> Option<UnderlyingStorage> {
|
||||||
|
if let Some(texture) = &self.texture {
|
||||||
|
texture.underlying_storage(renderer)
|
||||||
|
} else {
|
||||||
|
self.fallback.underlying_storage(renderer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user