Merge pull request #816 from Smithay/feature/gat_renderer

This commit is contained in:
Victoria Brekenfeld 2022-11-23 23:39:48 +01:00 committed by GitHub
commit a4b836f9f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 974 additions and 861 deletions

View file

@ -51,7 +51,7 @@ impl<T: Texture> PointerElement<T> {
render_elements! {
pub PointerRenderElement<R> where
R: ImportAll;
Surface=WaylandSurfaceRenderElement,
Surface=WaylandSurfaceRenderElement<R>,
Texture=TextureRenderElement<<R as Renderer>::TextureId>,
}
@ -60,7 +60,12 @@ where
R: Renderer<TextureId = T> + ImportAll,
{
type RenderElement = PointerRenderElement<R>;
fn render_elements<E>(&self, location: Point<i32, Physical>, scale: Scale<f64>) -> Vec<E>
fn render_elements<E>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
) -> Vec<E>
where
E: From<PointerRenderElement<R>>,
{
@ -85,7 +90,7 @@ where
CursorImageStatus::Surface(surface) => {
let elements: Vec<PointerRenderElement<R>> =
smithay::backend::renderer::element::surface::render_elements_from_surface_tree(
surface, location, scale,
renderer, surface, location, scale, None,
);
elements.into_iter().map(E::from).collect()
}
@ -172,8 +177,7 @@ where
{
fn draw(
&self,
_renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
frame: &mut <R as Renderer>::Frame<'_>,
location: Point<i32, Physical>,
scale: Scale<f64>,
damage: &[Rectangle<i32, Physical>],

View file

@ -20,7 +20,7 @@ smithay::backend::renderer::element::render_elements! {
pub CustomRenderElements<R> where
R: ImportAll;
Pointer=PointerRenderElement<R>,
Surface=WaylandSurfaceRenderElement,
Surface=WaylandSurfaceRenderElement<R>,
#[cfg(feature = "debug")]
// Note: We would like to borrow this element instead, but that would introduce
// a feature-dependent lifetime, which introduces a lot more feature bounds
@ -53,7 +53,8 @@ where
}
let scale = output.current_scale().fractional_scale().into();
let window_render_elements = AsRenderElements::<R>::render_elements(&window, (0, 0).into(), scale);
let window_render_elements =
AsRenderElements::<R>::render_elements(&window, renderer, (0, 0).into(), scale);
let render_elements = custom_elements
.iter()

View file

@ -1027,6 +1027,7 @@ fn render_surface<'a>(
input_method.with_surface(|surface| {
elements.extend(AsRenderElements::<UdevRenderer<'a>>::render_elements(
&SurfaceTree::from_surface(surface),
renderer,
position.to_physical_precise_round(scale),
scale,
));
@ -1066,7 +1067,7 @@ fn render_surface<'a>(
pointer_element.set_status(cursor_status.clone());
}
elements.extend(pointer_element.render_elements(cursor_pos_scaled, scale));
elements.extend(pointer_element.render_elements(renderer, cursor_pos_scaled, scale));
// draw the dnd icon if applicable
{
@ -1074,6 +1075,7 @@ fn render_surface<'a>(
if wl_surface.alive() {
elements.extend(AsRenderElements::<UdevRenderer<'a>>::render_elements(
&SurfaceTree::from_surface(wl_surface),
renderer,
cursor_pos_scaled,
scale,
));
@ -1153,14 +1155,11 @@ fn initial_render(
let (dmabuf, _) = surface.next_buffer()?;
renderer.bind(dmabuf)?;
// Does not matter if we render an empty frame
renderer
.render((1, 1).into(), Transform::Normal, |_, frame| {
frame
.clear(CLEAR_COLOR, &[Rectangle::from_loc_and_size((0, 0), (1, 1))])
.map_err(Into::<SwapBuffersError>::into)
})
.map_err(Into::<SwapBuffersError>::into)
.and_then(|x| x.map_err(Into::<SwapBuffersError>::into))?;
let mut frame = renderer
.render((1, 1).into(), Transform::Normal)
.map_err(Into::<SwapBuffersError>::into)?;
frame.clear(CLEAR_COLOR, &[Rectangle::from_loc_and_size((0, 0), (1, 1))])?;
frame.finish().map_err(Into::<SwapBuffersError>::into)?;
surface.queue_buffer(None)?;
surface.reset_buffers();
Ok(())

View file

@ -252,7 +252,7 @@ pub fn run_winit(log: Logger) {
let mut elements = Vec::<CustomRenderElements<Gles2Renderer>>::new();
elements.extend(pointer_element.render_elements(cursor_pos_scaled, scale));
elements.extend(pointer_element.render_elements(renderer, cursor_pos_scaled, scale));
// draw input method surface if any
let rectangle = input_method.coordinates();
@ -263,6 +263,7 @@ pub fn run_winit(log: Logger) {
input_method.with_surface(|surface| {
elements.extend(AsRenderElements::<Gles2Renderer>::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(surface),
renderer,
position.to_physical_precise_round(scale),
scale,
));
@ -273,6 +274,7 @@ pub fn run_winit(log: Logger) {
if surface.alive() {
elements.extend(AsRenderElements::<Gles2Renderer>::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(surface),
renderer,
cursor_pos_scaled,
scale,
));

View file

@ -280,7 +280,11 @@ pub fn run_x11(log: Logger) {
let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round();
pointer_element.set_status(cursor_guard.clone());
elements.extend(pointer_element.render_elements(cursor_pos_scaled, scale));
elements.extend(pointer_element.render_elements(
&mut backend_data.renderer,
cursor_pos_scaled,
scale,
));
// draw input method surface if any
let input_method = state.seat.input_method().unwrap();
@ -292,6 +296,7 @@ pub fn run_x11(log: Logger) {
input_method.with_surface(|surface| {
elements.extend(AsRenderElements::<Gles2Renderer>::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(surface),
&mut backend_data.renderer,
position.to_physical_precise_round(scale),
scale,
));
@ -302,6 +307,7 @@ pub fn run_x11(log: Logger) {
if surface.alive() {
elements.extend(AsRenderElements::<Gles2Renderer>::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(surface),
&mut backend_data.renderer,
cursor_pos_scaled,
scale,
));

View file

@ -4,8 +4,9 @@ use smithay::{
backend::{
input::{InputEvent, KeyboardKeyEvent},
renderer::{
element::surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
gles2::Gles2Renderer,
utils::{draw_surface_tree, on_commit_buffer_handler},
utils::{draw_render_elements, on_commit_buffer_handler},
Frame, Renderer,
},
winit::{self, WinitEvent},
@ -188,21 +189,31 @@ pub fn run_winit() -> Result<(), Box<dyn std::error::Error>> {
let size = backend.window_size().physical_size;
let damage = Rectangle::from_loc_and_size((0, 0), size);
backend
.renderer()
.render(size, Transform::Flipped180, |renderer, frame| {
frame.clear([0.1, 0.0, 0.0, 1.0], &[damage]).unwrap();
let elements = state.xdg_shell_state.toplevel_surfaces(|surfaces| {
surfaces
.iter()
.flat_map(|surface| {
render_elements_from_surface_tree(
backend.renderer(),
surface.wl_surface(),
(0, 0),
1.0,
log.clone(),
)
})
.collect::<Vec<WaylandSurfaceRenderElement<Gles2Renderer>>>()
});
state.xdg_shell_state.toplevel_surfaces(|surfaces| {
for surface in surfaces {
let surface = surface.wl_surface();
draw_surface_tree(renderer, frame, surface, 1.0, (0.0, 0.0).into(), &[damage], &log)
.unwrap();
let mut frame = backend.renderer().render(size, Transform::Flipped180).unwrap();
frame.clear([0.1, 0.0, 0.0, 1.0], &[damage]).unwrap();
draw_render_elements(&mut frame, 1.0, &elements, &[damage], &log).unwrap();
frame.finish().unwrap();
send_frames_surface_tree(surface, start_time.elapsed().as_millis() as u32);
}
});
})?;
state.xdg_shell_state.toplevel_surfaces(|surfaces| {
for surface in surfaces {
send_frames_surface_tree(surface.wl_surface(), start_time.elapsed().as_millis() as u32);
}
});
if let Some(stream) = listener.accept()? {
println!("Got a client: {:?}", stream);

View file

@ -118,7 +118,7 @@ pub fn winit_dispatch(
let damage = Rectangle::from_loc_and_size((0, 0), size);
backend.bind()?;
smithay::desktop::space::render_output::<_, WaylandSurfaceRenderElement, _, _, _>(
smithay::desktop::space::render_output::<_, WaylandSurfaceRenderElement<Gles2Renderer>, _, _, _>(
output,
backend.renderer(),
0,

View file

@ -42,6 +42,7 @@
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! #
//! # fn id(&self) -> usize { unimplemented!() }
//! # fn clear(&mut self, _: [f32; 4], _: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
@ -59,6 +60,7 @@
//! # fn transformation(&self) -> Transform {
//! # unimplemented!()
//! # }
//! # fn finish(self) -> Result<(), Self::Error> { unimplemented!() }
//! # }
//! #
//! # struct FakeRenderer;
@ -66,7 +68,7 @@
//! # impl Renderer for FakeRenderer {
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! # type Frame = FakeFrame;
//! # type Frame<'a> = FakeFrame;
//! #
//! # fn id(&self) -> usize {
//! # unimplemented!()
@ -77,9 +79,7 @@
//! # fn upscale_filter(&mut self, _: TextureFilter) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
//! # fn render<F, R>(&mut self, _: Size<i32, Physical>, _: Transform, _: F) -> Result<R, Self::Error>
//! # where
//! # F: FnOnce(&mut Self, &mut Self::Frame) -> R,
//! # fn render(&mut self, _: Size<i32, Physical>, _: Transform) -> Result<Self::Frame<'_>, Self::Error>
//! # {
//! # unimplemented!()
//! # }
@ -144,7 +144,8 @@
//! // Create a render element from the buffer
//! let location = Point::from((100.0, 100.0));
//! let render_element =
//! MemoryRenderBufferRenderElement::from_buffer(location, &memory_buffer, None, None, None);
//! MemoryRenderBufferRenderElement::from_buffer(&mut renderer, location, &memory_buffer, None, None, None, None)
//! .expect("Failed to upload memory to gpu");
//!
//! // Render the output
//! damage_tracked_renderer
@ -325,7 +326,9 @@ impl DamageTrackedRenderer {
&mut opaque_regions,
);
let render_res = renderer.render(output_size, output_transform, |renderer, frame| {
let render_res = (|| {
let mut frame = renderer.render(output_size, output_transform)?;
let clear_damage = opaque_regions.iter().flat_map(|(_, regions)| regions).fold(
damage.clone(),
|damage, region| {
@ -375,8 +378,7 @@ impl DamageTrackedRenderer {
}
element.draw(
renderer,
frame,
&mut frame,
element.location(output_scale),
output_scale,
&element_damage,
@ -385,7 +387,7 @@ impl DamageTrackedRenderer {
}
Result::<(), R::Error>::Ok(())
});
})();
if let Err(err) = render_res {
// if the rendering errors on us, we need to be prepared, that this whole buffer was partially updated and thus now unusable.

View file

@ -46,6 +46,7 @@
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! #
//! # fn id(&self) -> usize { unimplemented!() }
//! # fn clear(&mut self, _: [f32; 4], _: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
@ -63,6 +64,7 @@
//! # fn transformation(&self) -> Transform {
//! # unimplemented!()
//! # }
//! # fn finish(self) -> Result<(), Self::Error> { unimplemented!() }
//! # }
//! #
//! # struct FakeRenderer;
@ -70,7 +72,7 @@
//! # impl Renderer for FakeRenderer {
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! # type Frame = FakeFrame;
//! # type Frame<'a> = FakeFrame;
//! #
//! # fn id(&self) -> usize {
//! # unimplemented!()
@ -81,9 +83,7 @@
//! # fn upscale_filter(&mut self, _: TextureFilter) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
//! # fn render<F, R>(&mut self, _: Size<i32, Physical>, _: Transform, _: F) -> Result<R, Self::Error>
//! # where
//! # F: FnOnce(&mut Self, &mut Self::Frame) -> R,
//! # fn render(&mut self, _: Size<i32, Physical>, _: Transform) -> Result<Self::Frame<'_>, Self::Error>
//! # {
//! # unimplemented!()
//! # }
@ -170,7 +170,8 @@
//!
//! // Create a render element from the buffer
//! let location = Point::from((100.0, 100.0));
//! let render_element = MemoryRenderBufferRenderElement::from_buffer(location, &buffer, None, None, None);
//! let render_element = MemoryRenderBufferRenderElement::from_buffer(&mut renderer, location, &buffer, None, None, None, None)
//! .expect("Failed to upload from memory to gpu");
//!
//! // Render the element(s)
//! damage_tracked_renderer
@ -182,10 +183,11 @@
use std::{
any::TypeId,
collections::{hash_map::Entry, HashMap},
marker::PhantomData,
sync::{Arc, Mutex, MutexGuard},
};
use slog::trace;
use slog::{trace, warn};
use crate::{
backend::renderer::{
@ -272,7 +274,7 @@ impl MemoryRenderBufferInner {
&mut self,
renderer: &mut R,
log: &slog::Logger,
) -> Result<&<R as Renderer>::TextureId, <R as Renderer>::Error>
) -> Result<(), <R as Renderer>::Error>
where
R: Renderer + ImportMem,
<R as Renderer>::TextureId: 'static,
@ -301,13 +303,18 @@ impl MemoryRenderBufferInner {
};
self.renderer_seen.insert(texture_id, current_commit);
Ok(())
}
Ok(self
.textures
fn get_texture<R>(&mut self, renderer_id: usize) -> Option<&<R as Renderer>::TextureId>
where
R: Renderer,
<R as Renderer>::TextureId: 'static,
{
let texture_id = (TypeId::of::<<R as Renderer>::TextureId>(), renderer_id);
self.textures
.get(&texture_id)
.unwrap()
.downcast_ref::<<R as Renderer>::TextureId>()
.unwrap())
.and_then(|boxed| boxed.downcast_ref::<<R as Renderer>::TextureId>())
}
}
@ -424,31 +431,41 @@ impl<'a> Drop for RenderContext<'a> {
/// A render element for [`MemoryRenderBuffer`]
#[derive(Debug)]
pub struct MemoryRenderBufferRenderElement {
pub struct MemoryRenderBufferRenderElement<R: Renderer> {
location: Point<f64, Physical>,
buffer: MemoryRenderBuffer,
alpha: f32,
src: Option<Rectangle<f64, Logical>>,
size: Option<Size<i32, Logical>>,
renderer_type: PhantomData<R>,
}
impl MemoryRenderBufferRenderElement {
impl<R: Renderer> MemoryRenderBufferRenderElement<R> {
/// Create a new [`MemoryRenderBufferRenderElement`] for
/// a [`MemoryRenderBuffer`]
pub fn from_buffer(
renderer: &mut R,
location: impl Into<Point<f64, Physical>>,
buffer: &MemoryRenderBuffer,
alpha: Option<f32>,
src: Option<Rectangle<f64, Logical>>,
size: Option<Size<i32, Logical>>,
) -> Self {
MemoryRenderBufferRenderElement {
log: impl Into<Option<slog::Logger>>,
) -> Result<Self, <R as Renderer>::Error>
where
R: ImportMem,
<R as Renderer>::TextureId: 'static,
{
let logger = crate::slog_or_fallback(log);
buffer.inner.lock().unwrap().import_texture(renderer, &logger)?;
Ok(MemoryRenderBufferRenderElement {
location: location.into(),
buffer: buffer.clone(),
alpha: alpha.unwrap_or(1.0),
src,
size,
}
renderer_type: PhantomData,
})
}
fn logical_size(&self) -> Size<i32, Logical> {
@ -551,7 +568,7 @@ impl MemoryRenderBufferRenderElement {
}
}
impl Element for MemoryRenderBufferRenderElement {
impl<R: Renderer> Element for MemoryRenderBufferRenderElement<R> {
fn id(&self) -> &super::Id {
&self.buffer.id
}
@ -589,15 +606,14 @@ impl Element for MemoryRenderBufferRenderElement {
}
}
impl<R> RenderElement<R> for MemoryRenderBufferRenderElement
impl<R> RenderElement<R> for MemoryRenderBufferRenderElement<R>
where
R: Renderer + ImportMem,
<R as Renderer>::TextureId: 'static,
{
fn draw(
fn draw<'a>(
&self,
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
frame: &mut <R as Renderer>::Frame<'a>,
location: Point<i32, Physical>,
scale: Scale<f64>,
damage: &[Rectangle<i32, Physical>],
@ -607,7 +623,10 @@ where
let mut guard = self.buffer.inner.lock().unwrap();
let texture_scale = guard.scale;
let transform = guard.transform;
let texture = guard.import_texture(renderer, log)?;
let Some(texture) = guard.get_texture::<R>(frame.id()) else {
warn!(log, "trying to render texture from different renderer");
return Ok(());
};
let src = self
.src

View file

@ -340,10 +340,9 @@ pub trait Element {
/// A single render element
pub trait RenderElement<R: Renderer>: Element {
/// Draw this element
fn draw(
fn draw<'a>(
&self,
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
frame: &mut <R as Renderer>::Frame<'a>,
location: Point<i32, Physical>,
scale: Scale<f64>,
damage: &[Rectangle<i32, Physical>],
@ -351,7 +350,8 @@ pub trait RenderElement<R: Renderer>: Element {
) -> Result<(), R::Error>;
/// Get the underlying storage of this element, may be used to optimize rendering (eg. drm planes)
fn underlying_storage(&self, _renderer: &R) -> Option<UnderlyingStorage<'_, R>> {
fn underlying_storage(&self, renderer: &R) -> Option<UnderlyingStorage<'_, R>> {
let _ = renderer;
None
}
}
@ -366,6 +366,7 @@ where
/// Returns render elements for a given position and scale
fn render_elements<C: From<Self::RenderElement>>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
) -> Vec<C>;
@ -421,16 +422,15 @@ where
(*self).underlying_storage(renderer)
}
fn draw(
fn draw<'a>(
&self,
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
frame: &mut <R as Renderer>::Frame<'a>,
location: Point<i32, Physical>,
scale: Scale<f64>,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), R::Error> {
(*self).draw(renderer, frame, location, scale, damage, log)
(*self).draw(frame, location, scale, damage, log)
}
}
@ -680,10 +680,9 @@ macro_rules! render_elements_internal {
}
};
(@draw <$renderer:ty>; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
fn draw(
fn draw<'frame>(
&self,
renderer: &mut $renderer,
frame: &mut <$renderer as $crate::backend::renderer::Renderer>::Frame,
frame: &mut <$renderer as $crate::backend::renderer::Renderer>::Frame<'frame>,
location: $crate::utils::Point<i32, $crate::utils::Physical>,
scale: $crate::utils::Scale<f64>,
damage: &[$crate::utils::Rectangle<i32, $crate::utils::Physical>],
@ -704,7 +703,7 @@ macro_rules! render_elements_internal {
$(
#[$meta]
)*
Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; draw; x, renderer, frame, location, scale, damage, log)
Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; draw; x, frame, location, scale, damage, log)
),*,
Self::_GenericCatcher(_) => unreachable!(),
}
@ -725,10 +724,9 @@ macro_rules! render_elements_internal {
}
};
(@draw $renderer:ty; $($(#[$meta:meta])* $body:ident=$field:ty $(as <$other_renderer:ty>)?),* $(,)?) => {
fn draw(
fn draw<'frame>(
&self,
renderer: &mut $renderer,
frame: &mut <$renderer as $crate::backend::renderer::Renderer>::Frame,
frame: &mut <$renderer as $crate::backend::renderer::Renderer>::Frame<'frame>,
location: $crate::utils::Point<i32, $crate::utils::Physical>,
scale: $crate::utils::Scale<f64>,
damage: &[$crate::utils::Rectangle<i32, $crate::utils::Physical>],
@ -741,7 +739,7 @@ macro_rules! render_elements_internal {
$(
#[$meta]
)*
Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; draw; x, renderer, frame, location, scale, damage, log)
Self::$body(x) => $crate::render_elements_internal!(@call $renderer $(as $other_renderer)?; draw; x, frame, location, scale, damage, log)
),*,
Self::_GenericCatcher(_) => unreachable!(),
}
@ -1061,8 +1059,7 @@ macro_rules! render_elements_internal {
/// # impl<R: Renderer> RenderElement<R> for MyRenderElement1 {
/// # fn draw(
/// # &self,
/// # _renderer: &mut R,
/// # _frame: &mut <R as Renderer>::Frame,
/// # _frame: &mut <R as Renderer>::Frame<'_>,
/// # _location: Point<i32, Physical>,
/// # _scale: Scale<f64>,
/// # _damage: &[Rectangle<i32, Physical>],
@ -1091,10 +1088,9 @@ macro_rules! render_elements_internal {
/// # }
/// #
/// # impl<R: Renderer> RenderElement<R> for MyRenderElement2 {
/// # fn draw(
/// # fn draw<'a>(
/// # &self,
/// # _renderer: &mut R,
/// # _frame: &mut <R as Renderer>::Frame,
/// # _frame: &mut <R as Renderer>::Frame<'a>,
/// # _location: Point<i32, Physical>,
/// # _scale: Scale<f64>,
/// # _damage: &[Rectangle<i32, Physical>],
@ -1126,7 +1122,7 @@ macro_rules! render_elements_internal {
///
/// render_elements! {
/// MyRenderElements<R> where R: ImportMem;
/// Memory=MemoryRenderBufferRenderElement,
/// Memory=MemoryRenderBufferRenderElement<R>,
/// }
/// ```
///
@ -1141,7 +1137,7 @@ macro_rules! render_elements_internal {
///
/// render_elements! {
/// MyRenderElements<'a, R> where R: ImportMem;
/// Memory=&'a MemoryRenderBufferRenderElement,
/// Memory=&'a MemoryRenderBufferRenderElement<R>,
/// }
/// ```
///
@ -1155,7 +1151,7 @@ macro_rules! render_elements_internal {
///
/// render_elements! {
/// MyRenderElements<'a, R, A, B> where R: ImportMem;
/// Memory=&'a MemoryRenderBufferRenderElement,
/// Memory=&'a MemoryRenderBufferRenderElement<R>,
/// Owned=A,
/// Borrowed=&'a B,
/// }
@ -1188,6 +1184,7 @@ macro_rules! render_elements_internal {
/// # type Error = std::convert::Infallible;
/// # type TextureId = MyRendererTextureId;
/// #
/// # fn id(&self) -> usize { unimplemented!() }
/// # fn clear(&mut self, _: [f32; 4], _: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
/// # unimplemented!()
/// # }
@ -1205,6 +1202,7 @@ macro_rules! render_elements_internal {
/// # fn transformation(&self) -> Transform {
/// # unimplemented!()
/// # }
/// # fn finish(self) -> Result<(), Self::Error> { unimplemented!() }
/// # }
/// #
/// # struct MyRenderer;
@ -1212,7 +1210,7 @@ macro_rules! render_elements_internal {
/// # impl Renderer for MyRenderer {
/// # type Error = std::convert::Infallible;
/// # type TextureId = MyRendererTextureId;
/// # type Frame = MyRendererFrame;
/// # type Frame<'a> = MyRendererFrame;
/// #
/// # fn id(&self) -> usize {
/// # unimplemented!()
@ -1223,9 +1221,7 @@ macro_rules! render_elements_internal {
/// # fn upscale_filter(&mut self, _: TextureFilter) -> Result<(), Self::Error> {
/// # unimplemented!()
/// # }
/// # fn render<F, R>(&mut self, _: Size<i32, Physical>, _: Transform, _: F) -> Result<R, Self::Error>
/// # where
/// # F: FnOnce(&mut Self, &mut Self::Frame) -> R,
/// # fn render(&mut self, _: Size<i32, Physical>, _: Transform) -> Result<Self::Frame<'_>, Self::Error>
/// # {
/// # unimplemented!()
/// # }
@ -1362,16 +1358,15 @@ where
R: Renderer,
C: RenderElement<R>,
{
fn draw(
fn draw<'a>(
&self,
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
frame: &mut <R as Renderer>::Frame<'a>,
location: Point<i32, Physical>,
scale: Scale<f64>,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error> {
self.0.draw(renderer, frame, location, scale, damage, log)
self.0.draw(frame, location, scale, damage, log)
}
fn underlying_storage(&self, renderer: &R) -> Option<UnderlyingStorage<'_, R>> {

View file

@ -49,6 +49,7 @@
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! #
//! # fn id(&self) -> usize { unimplemented!() }
//! # fn clear(&mut self, _: [f32; 4], _: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
@ -66,6 +67,7 @@
//! # fn transformation(&self) -> Transform {
//! # unimplemented!()
//! # }
//! # fn finish(self) -> Result<(), Self::Error> { unimplemented!() }
//! # }
//! #
//! # struct FakeRenderer;
@ -73,7 +75,7 @@
//! # impl Renderer for FakeRenderer {
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! # type Frame = FakeFrame;
//! # type Frame<'a> = FakeFrame;
//! #
//! # fn id(&self) -> usize {
//! # unimplemented!()
@ -84,9 +86,7 @@
//! # fn upscale_filter(&mut self, _: TextureFilter) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
//! # fn render<F, R>(&mut self, _: Size<i32, Physical>, _: Transform, _: F) -> Result<R, Self::Error>
//! # where
//! # F: FnOnce(&mut Self, &mut Self::Frame) -> R,
//! # fn render(&mut self, _: Size<i32, Physical>, _: Transform) -> Result<Self::Frame<'_>, Self::Error>
//! # {
//! # unimplemented!()
//! # }
@ -183,8 +183,8 @@
//! loop {
//! // Create the render elements from the surface
//! let location = Point::from((100, 100));
//! let render_elements: Vec<WaylandSurfaceRenderElement> =
//! render_elements_from_surface_tree(&surface, location, 1.0);
//! let render_elements: Vec<WaylandSurfaceRenderElement<FakeRenderer>> =
//! render_elements_from_surface_tree(&mut renderer, &surface, location, 1.0, log.clone());
//!
//! // Render the element(s)
//! damage_tracked_renderer
@ -193,28 +193,36 @@
//! }
//! ```
use std::{fmt, marker::PhantomData};
use slog::warn;
use wayland_server::protocol::wl_surface;
use crate::{
backend::renderer::{utils::RendererSurfaceStateUserData, Frame, ImportAll, Renderer, Texture},
utils::{Buffer, Physical, Point, Rectangle, Scale, Size, Transform},
wayland::compositor::{self, TraversalAction},
wayland::compositor::{self, SurfaceData, TraversalAction},
};
use super::{CommitCounter, Element, Id, RenderElement, UnderlyingStorage};
/// Retrieve the [`WaylandSurfaceRenderElement`]s for a surface tree
pub fn render_elements_from_surface_tree<E>(
pub fn render_elements_from_surface_tree<R, E>(
renderer: &mut R,
surface: &wl_surface::WlSurface,
location: impl Into<Point<i32, Physical>>,
scale: impl Into<Scale<f64>>,
log: impl Into<Option<::slog::Logger>>,
) -> Vec<E>
where
E: From<WaylandSurfaceRenderElement>,
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
E: From<WaylandSurfaceRenderElement<R>>,
{
let location = location.into().to_f64();
let scale = scale.into();
let mut surfaces: Vec<E> = Vec::new();
let logger = crate::slog_or_fallback(log);
compositor::with_surface_tree_downward(
surface,
@ -241,13 +249,26 @@ where
let data = states.data_map.get::<RendererSurfaceStateUserData>();
if let Some(data) = data {
let data = &*data.borrow();
if let Some(view) = data.view() {
let has_view = if let Some(view) = data.borrow().view() {
location += view.offset.to_f64().to_physical(scale);
true
} else {
false
};
let surface = WaylandSurfaceRenderElement::from_surface(surface, location);
surfaces.push(surface.into());
if has_view {
match WaylandSurfaceRenderElement::from_surface(
renderer,
surface,
states,
location,
logger.clone(),
) {
Ok(surface) => surfaces.push(surface.into()),
Err(err) => {
warn!(logger, "Failed to import surface: {}", err);
}
};
}
}
},
@ -258,23 +279,45 @@ where
}
/// A single surface render element
#[derive(Debug)]
pub struct WaylandSurfaceRenderElement {
pub struct WaylandSurfaceRenderElement<R> {
id: Id,
location: Point<f64, Physical>,
surface: wl_surface::WlSurface,
renderer_type: PhantomData<R>,
}
impl WaylandSurfaceRenderElement {
/// Create a render element from a surface
pub fn from_surface(surface: &wl_surface::WlSurface, location: Point<f64, Physical>) -> Self {
let id = Id::from_wayland_resource(surface);
impl<R> fmt::Debug for WaylandSurfaceRenderElement<R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WaylandSurfaceRenderElement")
.field("id", &self.id)
.field("location", &self.location)
.field("surface", &self.surface)
.finish()
}
}
Self {
impl<R: Renderer + ImportAll> WaylandSurfaceRenderElement<R> {
/// Create a render element from a surface
pub fn from_surface(
renderer: &mut R,
surface: &wl_surface::WlSurface,
states: &SurfaceData,
location: Point<f64, Physical>,
log: impl Into<Option<::slog::Logger>>,
) -> Result<Self, <R as Renderer>::Error>
where
<R as Renderer>::TextureId: 'static,
{
let id = Id::from_wayland_resource(surface);
let logger = crate::slog_or_fallback(log);
crate::backend::renderer::utils::import_surface(renderer, states, &logger)?;
Ok(Self {
id,
location,
surface: surface.clone(),
}
renderer_type: PhantomData,
})
}
fn size(&self, scale: impl Into<Scale<f64>>) -> Size<i32, Physical> {
@ -290,7 +333,7 @@ impl WaylandSurfaceRenderElement {
}
}
impl Element for WaylandSurfaceRenderElement {
impl<R: Renderer + ImportAll> Element for WaylandSurfaceRenderElement<R> {
fn id(&self) -> &Id {
&self.id
}
@ -408,7 +451,7 @@ impl Element for WaylandSurfaceRenderElement {
}
}
impl<R> RenderElement<R> for WaylandSurfaceRenderElement
impl<R> RenderElement<R> for WaylandSurfaceRenderElement<R>
where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: Texture + 'static,
@ -421,24 +464,21 @@ where
})
}
fn draw(
fn draw<'a>(
&self,
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
frame: &mut <R as Renderer>::Frame<'a>,
location: Point<i32, Physical>,
scale: Scale<f64>,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), R::Error> {
crate::backend::renderer::utils::import_surface_tree(renderer, &self.surface, log)?;
let dst_size = self.size(scale);
compositor::with_states(&self.surface, |states| {
let data = states.data_map.get::<RendererSurfaceStateUserData>();
if let Some(data) = data {
let data = data.borrow();
if let Some(texture) = data.texture(renderer) {
if let Some(texture) = data.texture::<R>(frame.id()) {
if let Some(surface_view) = data.view() {
let src = surface_view.src.to_buffer(
data.buffer_scale as f64,
@ -457,6 +497,8 @@ where
1.0f32,
)?;
}
} else {
warn!(log, "trying to render texture from different renderer");
}
}

View file

@ -143,10 +143,9 @@ impl<R> RenderElement<R> for ImportMemRenderElement
where
R: Renderer + ImportMem,
{
fn draw(
fn draw<'a>(
&self,
_renderer: &mut R,
_frame: &mut <R as Renderer>::Frame,
_frame: &mut <R as Renderer>::Frame<'a>,
_location: Point<i32, Physical>,
_scale: Scale<f64>,
_damage: &[Rectangle<i32, Physical>],
@ -182,10 +181,9 @@ impl<R> RenderElement<R> for Empty
where
R: Renderer,
{
fn draw(
fn draw<'a>(
&self,
_renderer: &mut R,
_frame: &mut <R as Renderer>::Frame,
_frame: &mut <R as Renderer>::Frame<'a>,
_location: Point<i32, Physical>,
_scale: Scale<f64>,
_damage: &[Rectangle<i32, Physical>],
@ -230,10 +228,9 @@ impl<R> RenderElement<R> for TestRenderElement2<R>
where
R: Renderer,
{
fn draw(
fn draw<'a>(
&self,
_renderer: &mut R,
_frame: &mut <R as Renderer>::Frame,
_frame: &mut <R as Renderer>::Frame<'a>,
_location: Point<i32, Physical>,
_scale: Scale<f64>,
_damage: &[Rectangle<i32, Physical>],
@ -277,10 +274,9 @@ impl<'a, R> RenderElement<R> for TestRenderElement<'a, R>
where
R: Renderer,
{
fn draw(
fn draw<'b>(
&self,
_renderer: &mut R,
_frame: &mut <R as Renderer>::Frame,
_frame: &mut <R as Renderer>::Frame<'b>,
_location: Point<i32, Physical>,
_scale: Scale<f64>,
_damage: &[Rectangle<i32, Physical>],

View file

@ -64,6 +64,7 @@
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! #
//! # fn id(&self) -> usize { unimplemented!() }
//! # fn clear(&mut self, _: [f32; 4], _: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
@ -81,6 +82,7 @@
//! # fn transformation(&self) -> Transform {
//! # unimplemented!()
//! # }
//! # fn finish(self) -> Result<(), Self::Error> { unimplemented!() }
//! # }
//! #
//! # struct FakeRenderer;
@ -88,7 +90,7 @@
//! # impl Renderer for FakeRenderer {
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! # type Frame = FakeFrame;
//! # type Frame<'a> = FakeFrame;
//! #
//! # fn id(&self) -> usize {
//! # unimplemented!()
@ -99,9 +101,7 @@
//! # fn upscale_filter(&mut self, _: TextureFilter) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
//! # fn render<F, R>(&mut self, _: Size<i32, Physical>, _: Transform, _: F) -> Result<R, Self::Error>
//! # where
//! # F: FnOnce(&mut Self, &mut Self::Frame) -> R,
//! # fn render(&mut self, _: Size<i32, Physical>, _: Transform) -> Result<Self::Frame<'_>, Self::Error>
//! # {
//! # unimplemented!()
//! # }
@ -195,6 +195,7 @@
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! #
//! # fn id(&self) -> usize { unimplemented!() }
//! # fn clear(&mut self, _: [f32; 4], _: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
@ -212,6 +213,7 @@
//! # fn transformation(&self) -> Transform {
//! # unimplemented!()
//! # }
//! # fn finish(self) -> Result<(), Self::Error> { unimplemented!() }
//! # }
//! #
//! # struct FakeRenderer;
@ -219,7 +221,7 @@
//! # impl Renderer for FakeRenderer {
//! # type Error = std::convert::Infallible;
//! # type TextureId = FakeTexture;
//! # type Frame = FakeFrame;
//! # type Frame<'a> = FakeFrame;
//! #
//! # fn id(&self) -> usize {
//! # unimplemented!()
@ -230,9 +232,7 @@
//! # fn upscale_filter(&mut self, _: TextureFilter) -> Result<(), Self::Error> {
//! # unimplemented!()
//! # }
//! # fn render<F, R>(&mut self, _: Size<i32, Physical>, _: Transform, _: F) -> Result<R, Self::Error>
//! # where
//! # F: FnOnce(&mut Self, &mut Self::Frame) -> R,
//! # fn render(&mut self, _: Size<i32, Physical>, _: Transform) -> Result<Self::Frame<'_>, Self::Error>
//! # {
//! # unimplemented!()
//! # }
@ -801,16 +801,15 @@ where
R: Renderer<TextureId = T>,
T: Texture,
{
fn draw(
fn draw<'a>(
&self,
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
frame: &mut <R as Renderer>::Frame<'a>,
location: Point<i32, Physical>,
scale: Scale<f64>,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error> {
if renderer.id() != self.renderer_id {
if frame.id() != self.renderer_id {
warn!(log, "trying to render texture from different renderer");
return Ok(());
}

View file

@ -12,7 +12,7 @@ use std::{
ptr,
rc::Rc,
sync::{
atomic::{AtomicPtr, Ordering},
atomic::{AtomicBool, AtomicPtr, Ordering},
mpsc::{channel, Receiver, Sender},
},
};
@ -298,29 +298,28 @@ impl Drop for RendererId {
}
}
/// Handle to the currently rendered frame during [`Gles2Renderer::render`](Renderer::render)
pub struct Gles2Frame {
/// Handle to the currently rendered frame during [`Gles2Renderer::render`](Renderer::render).
///
/// Leaking this frame will prevent it from synchronizing the rendered framebuffer,
/// which might cause glitches. Additionally parts of the GL state might not be reset correctly,
/// causing unexpected results for later render commands.
/// The internal GL context and framebuffer will remain valid, no re-creation will be necessary.
pub struct Gles2Frame<'frame> {
renderer: &'frame mut Gles2Renderer,
current_projection: Matrix3<f32>,
transform: Transform,
gl: ffi::Gles2,
tex_programs: [Gles2TexProgram; shaders::FRAGMENT_COUNT],
solid_program: Gles2SolidProgram,
vbos: [ffi::types::GLuint; 2],
size: Size<i32, Physical>,
min_filter: TextureFilter,
max_filter: TextureFilter,
supports_instancing: bool,
finished: AtomicBool,
}
impl fmt::Debug for Gles2Frame {
impl<'frame> fmt::Debug for Gles2Frame<'frame> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Gles2Frame")
.field("renderer", &self.renderer)
.field("current_projection", &self.current_projection)
.field("tex_programs", &self.tex_programs)
.field("solid_program", &self.solid_program)
.field("transform", &self.transform)
.field("size", &self.size)
.field("min_filter", &self.min_filter)
.field("max_filter", &self.max_filter)
.field("finished", &self.finished)
.finish_non_exhaustive()
}
}
@ -333,10 +332,14 @@ impl fmt::Debug for Gles2Renderer {
.field("extensions", &self.extensions)
.field("tex_programs", &self.tex_programs)
.field("solid_program", &self.solid_program)
// ffi::Gles2 does not implement Debug
.field("dmabuf_cache", &self.dmabuf_cache)
.field("egl", &self.egl)
.field("gl_version", &self.gl_version)
// ffi::Gles2 does not implement Debug
.field("vbos", &self.vbos)
.field("min_filter", &self.min_filter)
.field("max_filter", &self.max_filter)
.field("supports_instancing", &self.supports_instancing)
.field("logger", &self.logger)
.finish()
}
@ -1681,7 +1684,9 @@ impl Gles2Renderer {
pub fn egl_context(&self) -> &EGLContext {
&self.egl
}
}
impl<'frame> Gles2Frame<'frame> {
/// Run custom code in the GL context owned by this renderer.
///
/// The OpenGL state of the renderer is considered an implementation detail
@ -1692,18 +1697,16 @@ impl Gles2Renderer {
/// Doing otherwise can lead to rendering errors while using other functions of this renderer.
pub fn with_context<F, R>(&mut self, func: F) -> Result<R, Gles2Error>
where
F: FnOnce(&mut Self, &ffi::Gles2) -> R,
F: FnOnce(&ffi::Gles2) -> R,
{
self.make_current()?;
let gl = self.gl.clone();
Ok(func(self, &gl))
Ok(func(&self.renderer.gl))
}
}
impl Renderer for Gles2Renderer {
type Error = Gles2Error;
type TextureId = Gles2Texture;
type Frame = Gles2Frame;
type Frame<'frame> = Gles2Frame<'frame>;
fn id(&self) -> usize {
self.egl.user_data().get::<RendererId>().unwrap().0
@ -1718,15 +1721,11 @@ impl Renderer for Gles2Renderer {
Ok(())
}
fn render<F, R>(
fn render(
&mut self,
mut output_size: Size<i32, Physical>,
transform: Transform,
rendering: F,
) -> Result<R, Self::Error>
where
F: FnOnce(&mut Self, &mut Self::Frame) -> R,
{
) -> Result<Gles2Frame<'_>, Self::Error> {
self.make_current()?;
unsafe {
@ -1764,43 +1763,14 @@ impl Renderer for Gles2Renderer {
// We account for OpenGLs coordinate system here
let flip180 = Matrix3::new(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0);
let mut frame = Gles2Frame {
gl: self.gl.clone(),
tex_programs: self.tex_programs.clone(),
solid_program: self.solid_program.clone(),
Ok(Gles2Frame {
renderer: self,
// output transformation passed in by the user
current_projection: flip180 * transform.matrix() * renderer,
transform,
vbos: self.vbos,
size: output_size,
min_filter: self.min_filter,
max_filter: self.max_filter,
supports_instancing: self.supports_instancing,
};
let result = rendering(self, &mut frame);
unsafe {
self.gl.Flush();
// We need to wait for the previously submitted GL commands to complete
// or otherwise the buffer could be submitted to the drm surface while
// still writing to the buffer which results in flickering on the screen.
// The proper solution would be to create a fence just before calling
// glFlush that the backend can use to wait for the commands to be finished.
// In case of a drm atomic backend the fence could be supplied by using the
// IN_FENCE_FD property.
// See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#explicit-fencing-properties for
// the topic on submitting a IN_FENCE_FD and the mesa kmskube example
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c
// especially here
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L147
// and here
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L235
self.gl.Finish();
self.gl.Disable(ffi::BLEND);
}
Ok(result)
finished: AtomicBool::new(false),
})
}
}
@ -1851,11 +1821,15 @@ const fn triangle_verts() -> [ffi::types::GLfloat; 12 * MAX_RECTS_PER_DRAW] {
verts
}
impl Frame for Gles2Frame {
type Error = Gles2Error;
impl<'frame> Frame for Gles2Frame<'frame> {
type TextureId = Gles2Texture;
type Error = Gles2Error;
fn clear(&mut self, color: [f32; 4], at: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
fn id(&self) -> usize {
self.renderer.id()
}
fn clear(&mut self, color: [f32; 4], at: &[Rectangle<i32, Physical>]) -> Result<(), Gles2Error> {
if at.is_empty() {
return Ok(());
}
@ -1875,24 +1849,28 @@ impl Frame for Gles2Frame {
})
.collect::<Vec<_>>();
let gl = &self.renderer.gl;
unsafe {
self.gl.Disable(ffi::BLEND);
self.gl.UseProgram(self.solid_program.program);
self.gl.Uniform4f(
self.solid_program.uniform_color,
gl.Disable(ffi::BLEND);
gl.UseProgram(self.renderer.solid_program.program);
gl.Uniform4f(
self.renderer.solid_program.uniform_color,
color[0],
color[1],
color[2],
color[3],
);
self.gl
.UniformMatrix3fv(self.solid_program.uniform_matrix, 1, ffi::FALSE, mat.as_ptr());
gl.UniformMatrix3fv(
self.renderer.solid_program.uniform_matrix,
1,
ffi::FALSE,
mat.as_ptr(),
);
self.gl
.EnableVertexAttribArray(self.solid_program.attrib_vert as u32);
self.gl.BindBuffer(ffi::ARRAY_BUFFER, self.vbos[0]);
self.gl.VertexAttribPointer(
self.solid_program.attrib_vert as u32,
gl.EnableVertexAttribArray(self.renderer.solid_program.attrib_vert as u32);
gl.BindBuffer(ffi::ARRAY_BUFFER, self.renderer.vbos[0]);
gl.VertexAttribPointer(
self.renderer.solid_program.attrib_vert as u32,
2,
ffi::FLOAT,
ffi::FALSE,
@ -1901,7 +1879,7 @@ impl Frame for Gles2Frame {
);
// Damage vertices.
let vertices = if self.supports_instancing {
let vertices = if self.renderer.supports_instancing {
damage
} else {
// Add the 4 f32s per damage rectangle for each of the 6 vertices.
@ -1914,18 +1892,17 @@ impl Frame for Gles2Frame {
vertices
};
self.gl
.EnableVertexAttribArray(self.solid_program.attrib_position as u32);
self.gl.BindBuffer(ffi::ARRAY_BUFFER, self.vbos[1]);
self.gl.BufferData(
gl.EnableVertexAttribArray(self.renderer.solid_program.attrib_position as u32);
gl.BindBuffer(ffi::ARRAY_BUFFER, self.renderer.vbos[1]);
gl.BufferData(
ffi::ARRAY_BUFFER,
(std::mem::size_of::<ffi::types::GLfloat>() * vertices.len()) as isize,
vertices.as_ptr() as *const _,
ffi::STREAM_DRAW,
);
self.gl.VertexAttribPointer(
self.solid_program.attrib_position as u32,
gl.VertexAttribPointer(
self.renderer.solid_program.attrib_position as u32,
4,
ffi::FLOAT,
ffi::FALSE,
@ -1934,23 +1911,21 @@ impl Frame for Gles2Frame {
);
let damage_len = at.len() as i32;
if self.supports_instancing {
self.gl
.VertexAttribDivisor(self.solid_program.attrib_vert as u32, 0);
if self.renderer.supports_instancing {
gl.VertexAttribDivisor(self.renderer.solid_program.attrib_vert as u32, 0);
self.gl
.VertexAttribDivisor(self.solid_program.attrib_position as u32, 1);
gl.VertexAttribDivisor(self.renderer.solid_program.attrib_position as u32, 1);
self.gl.DrawArraysInstanced(ffi::TRIANGLE_STRIP, 0, 4, damage_len);
gl.DrawArraysInstanced(ffi::TRIANGLE_STRIP, 0, 4, damage_len);
} else {
// When we have more than 10 rectangles, draw them in batches of 10.
for i in 0..(damage_len - 1) / 10 {
self.gl.DrawArrays(ffi::TRIANGLES, 0, 60);
gl.DrawArrays(ffi::TRIANGLES, 0, 60);
// Set damage pointer to the next 10 rectangles.
let offset = (i + 1) as usize * 60 * 4 * std::mem::size_of::<ffi::types::GLfloat>();
self.gl.VertexAttribPointer(
self.solid_program.attrib_position as u32,
gl.VertexAttribPointer(
self.renderer.solid_program.attrib_position as u32,
4,
ffi::FLOAT,
ffi::FALSE,
@ -1961,16 +1936,14 @@ impl Frame for Gles2Frame {
// Draw the up to 10 remaining rectangles.
let count = ((damage_len - 1) % 10 + 1) * 6;
self.gl.DrawArrays(ffi::TRIANGLES, 0, count);
gl.DrawArrays(ffi::TRIANGLES, 0, count);
}
self.gl.BindBuffer(ffi::ARRAY_BUFFER, 0);
self.gl
.DisableVertexAttribArray(self.solid_program.attrib_vert as u32);
self.gl
.DisableVertexAttribArray(self.solid_program.attrib_position as u32);
self.gl.Enable(ffi::BLEND);
self.gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
gl.BindBuffer(ffi::ARRAY_BUFFER, 0);
gl.DisableVertexAttribArray(self.renderer.solid_program.attrib_vert as u32);
gl.DisableVertexAttribArray(self.renderer.solid_program.attrib_position as u32);
gl.Enable(ffi::BLEND);
gl.BlendFunc(ffi::ONE, ffi::ONE_MINUS_SRC_ALPHA);
}
Ok(())
@ -1978,13 +1951,13 @@ impl Frame for Gles2Frame {
fn render_texture_from_to(
&mut self,
texture: &Self::TextureId,
texture: &Gles2Texture,
src: Rectangle<f64, BufferCoord>,
dest: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
transform: Transform,
alpha: f32,
) -> Result<(), Self::Error> {
) -> Result<(), Gles2Error> {
let mut mat = Matrix3::<f32>::identity();
// dest position and scale
@ -2059,9 +2032,40 @@ impl Frame for Gles2Frame {
fn transformation(&self) -> Transform {
self.transform
}
fn finish(mut self) -> Result<(), Self::Error> {
self.finish_internal()
}
}
impl Gles2Frame {
impl<'frame> Gles2Frame<'frame> {
fn finish_internal(&mut self) -> Result<(), Gles2Error> {
if self.finished.swap(true, Ordering::SeqCst) {
return Ok(());
}
unsafe {
self.renderer.gl.Flush();
// We need to wait for the previously submitted GL commands to complete
// or otherwise the buffer could be submitted to the drm surface while
// still writing to the buffer which results in flickering on the screen.
// The proper solution would be to create a fence just before calling
// glFlush that the backend can use to wait for the commands to be finished.
// In case of a drm atomic backend the fence could be supplied by using the
// IN_FENCE_FD property.
// See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#explicit-fencing-properties for
// the topic on submitting a IN_FENCE_FD and the mesa kmskube example
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c
// especially here
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L147
// and here
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L235
self.renderer.gl.Finish();
self.renderer.gl.Disable(ffi::BLEND);
}
Ok(())
}
/// Render a texture to the current target using given projection matrix and alpha.
///
/// The instances are used to define the regions which should get drawn.
@ -2097,49 +2101,50 @@ impl Gles2Frame {
};
// render
let gl = &self.renderer.gl;
unsafe {
self.gl.ActiveTexture(ffi::TEXTURE0);
self.gl.BindTexture(target, tex.0.texture);
self.gl.TexParameteri(
gl.ActiveTexture(ffi::TEXTURE0);
gl.BindTexture(target, tex.0.texture);
gl.TexParameteri(
target,
ffi::TEXTURE_MIN_FILTER,
match self.min_filter {
match self.renderer.min_filter {
TextureFilter::Nearest => ffi::NEAREST as i32,
TextureFilter::Linear => ffi::LINEAR as i32,
},
);
self.gl.TexParameteri(
gl.TexParameteri(
target,
ffi::TEXTURE_MAG_FILTER,
match self.max_filter {
match self.renderer.max_filter {
TextureFilter::Nearest => ffi::NEAREST as i32,
TextureFilter::Linear => ffi::LINEAR as i32,
},
);
self.gl.UseProgram(self.tex_programs[tex.0.texture_kind].program);
gl.UseProgram(self.renderer.tex_programs[tex.0.texture_kind].program);
self.gl
.Uniform1i(self.tex_programs[tex.0.texture_kind].uniform_tex, 0);
self.gl.UniformMatrix3fv(
self.tex_programs[tex.0.texture_kind].uniform_matrix,
gl.Uniform1i(self.renderer.tex_programs[tex.0.texture_kind].uniform_tex, 0);
gl.UniformMatrix3fv(
self.renderer.tex_programs[tex.0.texture_kind].uniform_matrix,
1,
ffi::FALSE,
matrix.as_ptr(),
);
self.gl.UniformMatrix3fv(
self.tex_programs[tex.0.texture_kind].uniform_tex_matrix,
gl.UniformMatrix3fv(
self.renderer.tex_programs[tex.0.texture_kind].uniform_tex_matrix,
1,
ffi::FALSE,
tex_matrix.as_ptr(),
);
self.gl
.Uniform1f(self.tex_programs[tex.0.texture_kind].uniform_alpha, alpha);
gl.Uniform1f(
self.renderer.tex_programs[tex.0.texture_kind].uniform_alpha,
alpha,
);
self.gl
.EnableVertexAttribArray(self.tex_programs[tex.0.texture_kind].attrib_vert as u32);
self.gl.BindBuffer(ffi::ARRAY_BUFFER, self.vbos[0]);
self.gl.VertexAttribPointer(
self.solid_program.attrib_vert as u32,
gl.EnableVertexAttribArray(self.renderer.tex_programs[tex.0.texture_kind].attrib_vert as u32);
gl.BindBuffer(ffi::ARRAY_BUFFER, self.renderer.vbos[0]);
gl.VertexAttribPointer(
self.renderer.solid_program.attrib_vert as u32,
2,
ffi::FLOAT,
ffi::FALSE,
@ -2148,7 +2153,7 @@ impl Gles2Frame {
);
// Damage vertices.
let vertices = if self.supports_instancing {
let vertices = if self.renderer.supports_instancing {
Cow::Borrowed(damage)
} else {
let mut vertices = Vec::with_capacity(damage.len() * 6);
@ -2162,18 +2167,19 @@ impl Gles2Frame {
};
// vert_position
self.gl
.EnableVertexAttribArray(self.tex_programs[tex.0.texture_kind].attrib_vert_position as u32);
self.gl.BindBuffer(ffi::ARRAY_BUFFER, self.vbos[1]);
self.gl.BufferData(
gl.EnableVertexAttribArray(
self.renderer.tex_programs[tex.0.texture_kind].attrib_vert_position as u32,
);
gl.BindBuffer(ffi::ARRAY_BUFFER, self.renderer.vbos[1]);
gl.BufferData(
ffi::ARRAY_BUFFER,
(std::mem::size_of::<ffi::types::GLfloat>() * vertices.len()) as isize,
vertices.as_ptr() as *const _,
ffi::STREAM_DRAW,
);
self.gl.VertexAttribPointer(
self.tex_programs[tex.0.texture_kind].attrib_vert_position as u32,
gl.VertexAttribPointer(
self.renderer.tex_programs[tex.0.texture_kind].attrib_vert_position as u32,
4,
ffi::FLOAT,
ffi::FALSE,
@ -2182,24 +2188,26 @@ impl Gles2Frame {
);
let damage_len = (damage.len() / 4) as i32;
if self.supports_instancing {
self.gl
.VertexAttribDivisor(self.tex_programs[tex.0.texture_kind].attrib_vert as u32, 0);
self.gl.VertexAttribDivisor(
self.tex_programs[tex.0.texture_kind].attrib_vert_position as u32,
if self.renderer.supports_instancing {
gl.VertexAttribDivisor(
self.renderer.tex_programs[tex.0.texture_kind].attrib_vert as u32,
0,
);
gl.VertexAttribDivisor(
self.renderer.tex_programs[tex.0.texture_kind].attrib_vert_position as u32,
1,
);
self.gl.DrawArraysInstanced(ffi::TRIANGLE_STRIP, 0, 4, damage_len);
gl.DrawArraysInstanced(ffi::TRIANGLE_STRIP, 0, 4, damage_len);
} else {
// When we have more than 10 rectangles, draw them in batches of 10.
for i in 0..(damage_len - 1) / 10 {
self.gl.DrawArrays(ffi::TRIANGLES, 0, 6);
gl.DrawArrays(ffi::TRIANGLES, 0, 6);
// Set damage pointer to the next 10 rectangles.
let offset = (i + 1) as usize * 6 * 4 * std::mem::size_of::<ffi::types::GLfloat>();
self.gl.VertexAttribPointer(
self.solid_program.attrib_position as u32,
gl.VertexAttribPointer(
self.renderer.solid_program.attrib_position as u32,
4,
ffi::FLOAT,
ffi::FALSE,
@ -2210,15 +2218,15 @@ impl Gles2Frame {
// Draw the up to 10 remaining rectangles.
let count = ((damage_len - 1) % 10 + 1) * 6;
self.gl.DrawArrays(ffi::TRIANGLES, 0, count);
gl.DrawArrays(ffi::TRIANGLES, 0, count);
}
self.gl.BindBuffer(ffi::ARRAY_BUFFER, 0);
self.gl.BindTexture(target, 0);
self.gl
.DisableVertexAttribArray(self.tex_programs[tex.0.texture_kind].attrib_vert as u32);
self.gl
.DisableVertexAttribArray(self.tex_programs[tex.0.texture_kind].attrib_vert_position as u32);
gl.BindBuffer(ffi::ARRAY_BUFFER, 0);
gl.BindTexture(target, 0);
gl.DisableVertexAttribArray(self.renderer.tex_programs[tex.0.texture_kind].attrib_vert as u32);
gl.DisableVertexAttribArray(
self.renderer.tex_programs[tex.0.texture_kind].attrib_vert_position as u32,
);
}
Ok(())
@ -2229,3 +2237,15 @@ impl Gles2Frame {
self.current_projection.as_ref()
}
}
impl<'frame> Drop for Gles2Frame<'frame> {
fn drop(&mut self) {
if let Err(err) = self.finish_internal() {
slog::warn!(
self.renderer.logger,
"Ignored error finishing Gles2Frame on drop: {}",
err
);
}
}
}

View file

@ -27,53 +27,28 @@ use glow::Context;
use std::{
borrow::{Borrow, BorrowMut},
collections::HashSet,
fmt,
ops::{Deref, DerefMut},
rc::Rc,
sync::Arc,
};
use super::Frame;
#[derive(Debug)]
/// A renderer utilizing OpenGL ES 2 and [`glow`] on top for easier custom rendering.
pub struct GlowRenderer {
gl: Gles2Hack,
gl: Gles2Renderer,
glow: Arc<Context>,
logger: slog::Logger,
}
#[allow(clippy::large_enum_variant)]
enum Gles2Hack {
Owned(Gles2Renderer),
Borrowed(*mut Gles2Renderer),
}
impl fmt::Debug for Gles2Hack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Gles2Hack::Owned(renderer) => renderer.fmt(f),
Gles2Hack::Borrowed(renderer) => unsafe { &**renderer }.fmt(f),
}
}
}
impl Deref for Gles2Hack {
type Target = Gles2Renderer;
fn deref(&self) -> &Gles2Renderer {
match self {
Gles2Hack::Owned(renderer) => renderer,
Gles2Hack::Borrowed(renderer) => unsafe { &**renderer },
}
}
}
impl DerefMut for Gles2Hack {
fn deref_mut(&mut self) -> &mut Gles2Renderer {
match self {
Gles2Hack::Owned(renderer) => renderer,
Gles2Hack::Borrowed(renderer) => unsafe { &mut **renderer },
}
}
#[derive(Debug)]
/// [`Frame`](super::Frame) implementation of a [`GlowRenderer`].
///
/// Leaking the frame will cause the same problems as leaking a [`Gles2Frame`].
pub struct GlowFrame<'a> {
frame: Option<Gles2Frame<'a>>,
glow: Arc<Context>,
log: slog::Logger,
}
impl GlowRenderer {
@ -105,7 +80,7 @@ impl GlowRenderer {
let gl = Gles2Renderer::new(context, log.clone())?;
Ok(GlowRenderer {
gl: Gles2Hack::Owned(gl),
gl,
glow: Arc::new(glow),
logger: log,
})
@ -121,7 +96,9 @@ impl GlowRenderer {
pub fn egl_context(&self) -> &EGLContext {
self.gl.egl_context()
}
}
impl<'frame> GlowFrame<'frame> {
/// Run custom code in the GL context owned by this renderer.
///
/// The OpenGL state of the renderer is considered an implementation detail
@ -132,11 +109,9 @@ impl GlowRenderer {
/// Doing otherwise can lead to rendering errors while using other functions of this renderer.
pub fn with_context<F, R>(&mut self, func: F) -> Result<R, Gles2Error>
where
F: FnOnce(&mut Self, &Arc<Context>) -> R,
F: FnOnce(&Arc<Context>) -> R,
{
self.gl.make_current()?;
let glow = self.glow.clone();
Ok(func(self, &glow))
Ok(func(&self.glow))
}
}
@ -152,7 +127,7 @@ impl From<Gles2Renderer> for GlowRenderer {
};
GlowRenderer {
gl: Gles2Hack::Owned(renderer),
gl: renderer,
glow: Arc::new(glow),
logger: log,
}
@ -174,7 +149,7 @@ impl BorrowMut<Gles2Renderer> for GlowRenderer {
impl Renderer for GlowRenderer {
type Error = Gles2Error;
type TextureId = Gles2Texture;
type Frame = Gles2Frame;
type Frame<'frame> = GlowFrame<'frame>;
fn id(&self) -> usize {
self.gl.id()
@ -187,28 +162,96 @@ impl Renderer for GlowRenderer {
self.gl.upscale_filter(filter)
}
fn render<F, R>(
fn render(
&mut self,
output_size: Size<i32, Physical>,
transform: Transform,
rendering: F,
) -> Result<R, Self::Error>
where
F: FnOnce(&mut Self, &mut Self::Frame) -> R,
{
self.gl.render(output_size, transform, |gl, frame| {
rendering(
&mut GlowRenderer {
gl: Gles2Hack::Borrowed(gl as *mut _),
glow: self.glow.clone(),
logger: self.logger.clone(),
},
frame,
)
) -> Result<GlowFrame<'_>, Self::Error> {
let glow = self.glow.clone();
let frame = self.gl.render(output_size, transform)?;
Ok(GlowFrame {
frame: Some(frame),
glow,
log: self.logger.clone(),
})
}
}
impl<'frame> Frame for GlowFrame<'frame> {
type TextureId = Gles2Texture;
type Error = Gles2Error;
fn id(&self) -> usize {
self.frame.as_ref().unwrap().id()
}
fn clear(&mut self, color: [f32; 4], at: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
self.frame.as_mut().unwrap().clear(color, at)
}
fn render_texture_from_to(
&mut self,
texture: &Self::TextureId,
src: Rectangle<f64, BufferCoord>,
dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
src_transform: Transform,
alpha: f32,
) -> Result<(), Self::Error> {
self.frame
.as_mut()
.unwrap()
.render_texture_from_to(texture, src, dst, damage, src_transform, alpha)
}
fn transformation(&self) -> Transform {
self.frame.as_ref().unwrap().transformation()
}
fn render_texture_at(
&mut self,
texture: &Self::TextureId,
pos: crate::utils::Point<i32, Physical>,
texture_scale: i32,
output_scale: impl Into<crate::utils::Scale<f64>>,
src_transform: Transform,
damage: &[Rectangle<i32, Physical>],
alpha: f32,
) -> Result<(), Self::Error> {
self.frame.as_mut().unwrap().render_texture_at(
texture,
pos,
texture_scale,
output_scale,
src_transform,
damage,
alpha,
)
}
fn finish(mut self) -> Result<(), Self::Error> {
self.finish_internal()
}
}
impl<'frame> GlowFrame<'frame> {
fn finish_internal(&mut self) -> Result<(), Gles2Error> {
if let Some(frame) = self.frame.take() {
frame.finish()
} else {
Ok(())
}
}
}
impl<'frame> Drop for GlowFrame<'frame> {
fn drop(&mut self) {
if let Err(err) = self.finish_internal() {
slog::warn!(self.log, "Ignored error finishing GlowFrame on drop: {}", err);
}
}
}
#[cfg(feature = "wayland_frontend")]
impl ImportMemWl for GlowRenderer {
fn import_shm_buffer(
@ -328,7 +371,7 @@ impl Bind<Rc<EGLSurface>> for GlowRenderer {
self.gl.bind(surface)
}
fn supported_formats(&self) -> Option<HashSet<Format>> {
Bind::<Rc<EGLSurface>>::supported_formats(&*self.gl)
Bind::<Rc<EGLSurface>>::supported_formats(&self.gl)
}
}
@ -337,7 +380,7 @@ impl Bind<Dmabuf> for GlowRenderer {
self.gl.bind(dmabuf)
}
fn supported_formats(&self) -> Option<HashSet<Format>> {
Bind::<Dmabuf>::supported_formats(&*self.gl)
Bind::<Dmabuf>::supported_formats(&self.gl)
}
}
@ -346,7 +389,7 @@ impl Bind<Gles2Texture> for GlowRenderer {
self.gl.bind(texture)
}
fn supported_formats(&self) -> Option<HashSet<Format>> {
Bind::<Gles2Texture>::supported_formats(&*self.gl)
Bind::<Gles2Texture>::supported_formats(&self.gl)
}
}
@ -361,7 +404,7 @@ impl Bind<Gles2Renderbuffer> for GlowRenderer {
self.gl.bind(renderbuffer)
}
fn supported_formats(&self) -> Option<HashSet<Format>> {
Bind::<Gles2Renderbuffer>::supported_formats(&*self.gl)
Bind::<Gles2Renderbuffer>::supported_formats(&self.gl)
}
}

View file

@ -135,6 +135,10 @@ pub trait Frame {
/// Texture Handle type used by this renderer.
type TextureId: Texture;
/// Returns an id, that is unique to all renderers, that can use
/// `TextureId`s originating from any of these renderers.
fn id(&self) -> usize;
/// Clear the complete current target with a single given color.
///
/// The `at` parameter specifies a set of rectangles to clear in the current target. This allows partially
@ -189,6 +193,18 @@ pub trait Frame {
/// Output transformation that is applied to this frame
fn transformation(&self) -> Transform;
/// Finish this [`Frame`] returning any error that may happen during any cleanup.
///
/// Dropping the frame instead may result in any of the following and is implementation dependent:
/// - All actions done to the frame vanish and are never executed
/// - A partial renderer with undefined framebuffer contents occurs
/// - All actions are performed as normal without errors being returned.
///
/// Leaking the frame instead will leak resources and can cause any of the previous effects.
/// Leaking might make the renderer return Errors and force it's recreation.
/// Leaking may not cause otherwise undefined behavior and program execution will always continue normally.
fn finish(self) -> Result<(), Self::Error>;
}
/// Abstraction of commonly used rendering operations for compositors.
@ -198,7 +214,9 @@ pub trait Renderer {
/// Texture Handle type used by this renderer.
type TextureId: Texture;
/// Type representing a currently in-progress frame during the [`Renderer::render`]-call
type Frame: Frame<Error = Self::Error, TextureId = Self::TextureId>;
type Frame<'frame>: Frame<Error = Self::Error, TextureId = Self::TextureId> + 'frame
where
Self: 'frame;
/// Returns an id, that is unique to all renderers, that can use
/// `TextureId`s originating from any of these renderers.
@ -219,14 +237,11 @@ pub trait Renderer {
/// - The given Transformation is not supported by the renderer (`Transform::Normal` is always supported).
/// - This renderer implements `Bind`, no target was bound *and* has no default target.
/// - (Renderers not implementing `Bind` always have a default target.)
fn render<F, R>(
fn render(
&mut self,
output_size: Size<i32, Physical>,
dst_transform: Transform,
rendering: F,
) -> Result<R, Self::Error>
where
F: FnOnce(&mut Self, &mut Self::Frame) -> R;
) -> Result<Self::Frame<'_>, Self::Error>;
}
/// Trait for renderers that support creating offscreen framebuffers to render into.

View file

@ -183,11 +183,11 @@ impl<A: GraphicsApi> GpuManager<A> {
/// transferring the data to the `target_device`. Referr to [`Offscreen`](super::Offscreen)-implementations
/// to find supported options and referr to the documentations of the used `GraphicsApi` for possible
/// (performance) implication of selecting a specific `Target`.
pub fn renderer<'a, Target>(
&'a mut self,
pub fn renderer<'api, Target>(
&'api mut self,
render_device: &DrmNode,
target_device: &DrmNode,
) -> Result<MultiRenderer<'a, 'a, A, A, Target>, Error<A, A>>
) -> Result<MultiRenderer<'api, 'api, A, A, Target>, Error<A, A>>
where
<A::Device as ApiDevice>::Renderer: Offscreen<Target>,
{
@ -217,7 +217,7 @@ impl<A: GraphicsApi> GpuManager<A> {
Ok(MultiRenderer {
dma_source: Some(&mut self.dma_source),
render: RenderDevice::Device(render.remove(0)),
render: render.remove(0),
target: Some(target.remove(0)),
other_renderers: others,
proxy_framebuffer: std::marker::PhantomData,
@ -226,7 +226,7 @@ impl<A: GraphicsApi> GpuManager<A> {
} else {
Ok(MultiRenderer {
dma_source: Some(&mut self.dma_source),
render: RenderDevice::Device(render.remove(0)),
render: render.remove(0),
target: None,
other_renderers: others,
proxy_framebuffer: std::marker::PhantomData,
@ -246,12 +246,12 @@ impl<A: GraphicsApi> GpuManager<A> {
/// transferring the data to the `target_device`. Referr to [`Offscreen`](super::Offscreen)-implementations
/// to find supported options and referr to the documentations of the used `GraphicsApi` for possible
/// (performance) implication of selecting a specific `Target`.
pub fn cross_renderer<'a, 'b, B: GraphicsApi, Target>(
render_api: &'a mut Self,
target_api: &'b mut GpuManager<B>,
pub fn cross_renderer<'render, 'target, B: GraphicsApi, Target>(
render_api: &'render mut Self,
target_api: &'target mut GpuManager<B>,
render_device: &DrmNode,
target_device: &DrmNode,
) -> Result<MultiRenderer<'a, 'b, A, B, Target>, Error<A, B>>
) -> Result<MultiRenderer<'render, 'target, A, B, Target>, Error<A, B>>
where
<A::Device as ApiDevice>::Renderer: Offscreen<Target>,
{
@ -304,7 +304,7 @@ impl<A: GraphicsApi> GpuManager<A> {
Ok(MultiRenderer {
dma_source: Some(&mut render_api.dma_source),
render: RenderDevice::Device(render.remove(0)),
render: render.remove(0),
target: Some(target),
other_renderers: others,
proxy_framebuffer: std::marker::PhantomData,
@ -313,7 +313,7 @@ impl<A: GraphicsApi> GpuManager<A> {
} else {
Ok(MultiRenderer {
dma_source: Some(&mut render_api.dma_source),
render: RenderDevice::Device(render.remove(0)),
render: render.remove(0),
target: None,
other_renderers: others,
proxy_framebuffer: std::marker::PhantomData,
@ -593,103 +593,126 @@ pub trait ApiDevice {
/// Renderer, that transparently copies rendering results to another gpu,
/// as well as transparently importing client buffers residing on different gpus.
#[derive(Debug)]
pub struct MultiRenderer<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> {
dma_source: Option<&'a mut HashMap<WeakDmabuf, DrmNode>>,
render: RenderDevice<'a, R>,
target: Option<&'b mut T::Device>,
other_renderers: Vec<&'a mut R::Device>,
pub struct MultiRenderer<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> {
dma_source: Option<&'render mut HashMap<WeakDmabuf, DrmNode>>,
render: &'render mut R::Device,
target: Option<&'target mut T::Device>,
other_renderers: Vec<&'render mut R::Device>,
proxy_framebuffer: std::marker::PhantomData<Target>,
log: ::slog::Logger,
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> AsRef<<R::Device as ApiDevice>::Renderer>
for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> AsRef<<R::Device as ApiDevice>::Renderer>
for MultiRenderer<'render, 'target, R, T, Target>
{
fn as_ref(&self) -> &<R::Device as ApiDevice>::Renderer {
self.render.renderer()
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> AsMut<<R::Device as ApiDevice>::Renderer>
for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> AsMut<<R::Device as ApiDevice>::Renderer>
for MultiRenderer<'render, 'target, R, T, Target>
{
fn as_mut(&mut self) -> &mut <R::Device as ApiDevice>::Renderer {
self.render.renderer_mut()
}
}
// Hack for implementing Renderer::render..
#[derive(Debug)]
enum RenderDevice<'a, A: GraphicsApi> {
Device(&'a mut A::Device),
// Hack to avoid lifetime problems in Renderer::render
Renderer(*mut <A::Device as ApiDevice>::Renderer, DrmNode),
}
impl<'a, A: GraphicsApi> RenderDevice<'a, A> {
/*
fn unwrap_device(&mut self) -> &mut A::Device {
match self {
RenderDevice::Device(dev) => *dev,
RenderDevice::Renderer(_, _) => panic!("unwrap called on RenderDevice::Renderer"),
}
}
*/
fn node(&self) -> &DrmNode {
match self {
RenderDevice::Device(dev) => dev.node(),
RenderDevice::Renderer(_, node) => node,
}
}
fn renderer(&self) -> &<A::Device as ApiDevice>::Renderer {
match self {
RenderDevice::Device(dev) => dev.renderer(),
RenderDevice::Renderer(renderer, _) => unsafe { &**renderer },
}
}
fn renderer_mut(&mut self) -> &mut <A::Device as ApiDevice>::Renderer {
match self {
RenderDevice::Device(dev) => dev.renderer_mut(),
RenderDevice::Renderer(renderer, _) => unsafe { &mut **renderer },
}
}
}
/// [`Frame`](super::Frame) implementation of a [`MultiRenderer`].
#[derive(Debug)]
pub struct MultiFrame<R: GraphicsApi, T: GraphicsApi> {
///
/// Leaking the frame will potentially keep it from doing necessary copies
/// of the internal framebuffer for some multi-gpu configurations. The result would
/// be no updated framebuffer contents.
/// Additionally all problems related to the Frame-implementation of the underlying
/// [`GraphicsApi`] will be present.
pub struct MultiFrame<'render, 'target, 'frame, R: GraphicsApi + 'frame, T: GraphicsApi, Target>
where
R: 'static,
R::Error: 'static,
T::Error: 'static,
<R::Device as ApiDevice>::Renderer: Offscreen<Target> + ExportDma + ExportMem + ImportDma + ImportMem,
<T::Device as ApiDevice>::Renderer: ImportDma + ImportMem,
<<R::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
<<T::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
{
node: DrmNode,
// FIXME: With GAT this would not need to be a raw-pointer
frame: *mut <<R::Device as ApiDevice>::Renderer as Renderer>::Frame,
frame: Option<<<R::Device as ApiDevice>::Renderer as Renderer>::Frame<'frame>>,
render: *mut &'render mut R::Device,
target: &'frame mut Option<&'target mut T::Device>,
dst_transform: Transform,
size: Size<i32, Physical>,
damage: Vec<Rectangle<i32, Physical>>,
// We need this for the associated Error type of the Frame implementation
_target: std::marker::PhantomData<T>,
_types: std::marker::PhantomData<(T, Target)>,
log: ::slog::Logger,
}
impl<'render, 'target, 'frame, R: GraphicsApi + 'frame, T: GraphicsApi, Target> fmt::Debug
for MultiFrame<'render, 'target, 'frame, R, T, Target>
where
R: 'static,
R::Error: 'static,
T::Error: 'static,
<R::Device as ApiDevice>::Renderer: Offscreen<Target> + ExportDma + ExportMem + ImportDma + ImportMem,
<T::Device as ApiDevice>::Renderer: ImportDma + ImportMem,
<<R::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
<<T::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
R::Device: fmt::Debug,
T::Device: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MultiFrame")
.field("node", &self.node)
.field("render", unsafe { &*self.render })
.field("target", &self.target)
.field("dst_transform", &self.dst_transform)
.field("size", &self.size)
.field("damage", &self.damage)
.field("log", &self.log)
.finish()
}
}
// These casts are ok, because the frame cannot outlive the MultiFrame,
// see MultiRenderer::render for how this hack works and why it is necessary.
impl<R: GraphicsApi, T: GraphicsApi> AsRef<<<R::Device as ApiDevice>::Renderer as Renderer>::Frame>
for MultiFrame<R, T>
impl<'render, 'target, 'frame, R: GraphicsApi, T: GraphicsApi, Target>
AsRef<<<R::Device as ApiDevice>::Renderer as Renderer>::Frame<'frame>>
for MultiFrame<'render, 'target, 'frame, R, T, Target>
where
R: 'static,
R::Error: 'static,
T::Error: 'static,
<R::Device as ApiDevice>::Renderer: Offscreen<Target> + ExportDma + ExportMem + ImportDma + ImportMem,
<T::Device as ApiDevice>::Renderer: ImportDma + ImportMem,
<<R::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
<<T::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
{
fn as_ref(&self) -> &<<R::Device as ApiDevice>::Renderer as Renderer>::Frame {
unsafe { &*self.frame }
fn as_ref(&self) -> &<<R::Device as ApiDevice>::Renderer as Renderer>::Frame<'frame> {
self.frame.as_ref().unwrap()
}
}
impl<R: GraphicsApi, T: GraphicsApi> AsMut<<<R::Device as ApiDevice>::Renderer as Renderer>::Frame>
for MultiFrame<R, T>
impl<'render, 'target, 'frame, R: GraphicsApi, T: GraphicsApi, Target>
AsMut<<<R::Device as ApiDevice>::Renderer as Renderer>::Frame<'frame>>
for MultiFrame<'render, 'target, 'frame, R, T, Target>
where
R: 'static,
R::Error: 'static,
T::Error: 'static,
<R::Device as ApiDevice>::Renderer: Offscreen<Target> + ExportDma + ExportMem + ImportDma + ImportMem,
<T::Device as ApiDevice>::Renderer: ImportDma + ImportMem,
<<R::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
<<T::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
{
fn as_mut(&mut self) -> &mut <<R::Device as ApiDevice>::Renderer as Renderer>::Frame {
unsafe { &mut *self.frame }
fn as_mut(&mut self) -> &mut <<R::Device as ApiDevice>::Renderer as Renderer>::Frame<'frame> {
self.frame.as_mut().unwrap()
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> Unbind for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> Unbind
for MultiRenderer<'render, 'target, R, T, Target>
where
<T::Device as ApiDevice>::Renderer: Unbind,
<R::Device as ApiDevice>::Renderer: Unbind,
@ -711,8 +734,8 @@ where
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target, Other> Offscreen<Target>
for MultiRenderer<'a, 'b, R, T, Other>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target, Other> Offscreen<Target>
for MultiRenderer<'render, 'target, R, T, Other>
where
<T::Device as ApiDevice>::Renderer: Offscreen<Target>,
<R::Device as ApiDevice>::Renderer: Offscreen<Target>,
@ -743,8 +766,8 @@ where
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target, Other> Bind<Target>
for MultiRenderer<'a, 'b, R, T, Other>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target, Other> Bind<Target>
for MultiRenderer<'render, 'target, R, T, Other>
where
<T::Device as ApiDevice>::Renderer: Bind<Target>,
<R::Device as ApiDevice>::Renderer: Bind<Target>,
@ -779,7 +802,8 @@ where
static MAX_CPU_COPIES: usize = 3; // TODO, benchmark this
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> Renderer for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> Renderer
for MultiRenderer<'render, 'target, R, T, Target>
where
R: 'static,
R::Error: 'static,
@ -791,7 +815,7 @@ where
{
type Error = Error<R, T>;
type TextureId = MultiTexture;
type Frame = MultiFrame<R, T>;
type Frame<'frame> = MultiFrame<'render, 'target, 'frame, R, T, Target> where Self: 'frame;
fn id(&self) -> usize {
self.render.renderer().id()
@ -810,17 +834,13 @@ where
.map_err(Error::Render)
}
fn render<F, Res>(
&mut self,
fn render<'frame>(
&'frame mut self,
size: Size<i32, Physical>,
dst_transform: Transform,
rendering: F,
) -> Result<Res, Self::Error>
where
F: FnOnce(&mut Self, &mut Self::Frame) -> Res,
{
let buffer_size = size.to_logical(1).to_buffer(1, dst_transform);
) -> Result<MultiFrame<'render, 'target, 'frame, R, T, Target>, Self::Error> {
if self.target.is_some() {
let buffer_size = size.to_logical(1).to_buffer(1, dst_transform);
let render_buffer = Offscreen::<Target>::create_buffer(self.render.renderer_mut(), buffer_size)
.map_err(Error::Render)?;
self.render
@ -831,188 +851,202 @@ where
let node = *self.render.node();
// we need to move some stuff into the closure temporarily
let mut dma_source = self.dma_source.take();
let mut target = self.target.take();
let mut other_renderers = self.other_renderers.drain(..).collect::<Vec<_>>();
let dma_source_ref = &mut dma_source;
let target_ref = &mut target;
let other_renderers_ref = &mut other_renderers;
let log = self.log.clone();
let res = self
let ptr = &mut self.render as *mut _;
let frame = self
.render
.renderer_mut()
.render(size, dst_transform, move |render, frame| {
let mut new_renderer = MultiRenderer {
dma_source: dma_source_ref.take(),
render: RenderDevice::Renderer(render, node),
target: target_ref.take(),
other_renderers: other_renderers_ref.drain(..).collect(),
proxy_framebuffer: std::marker::PhantomData,
log: log.clone(),
};
let mut frame = MultiFrame {
node,
frame, // we cheat here and use a raw-ptr, because otherwise your associated type would gain an uncostraint lifetime parameter
damage: Vec::new(),
_target: std::marker::PhantomData::<T>,
log,
};
.render(size, dst_transform)
.map_err(Error::Render)?;
let res = rendering(&mut new_renderer, &mut frame);
Ok(MultiFrame {
node,
frame: Some(frame),
render: ptr, // this is fine, as long as we have the frame, this ptr is valid
target: &mut self.target,
dst_transform,
size,
damage: Vec::new(),
_types: std::marker::PhantomData::<(T, Target)>,
log,
})
}
}
// don't return yet, but first reset the references, so we can restore self on error
*dma_source_ref = new_renderer.dma_source.take();
*target_ref = new_renderer.target.take();
*other_renderers_ref = new_renderer.other_renderers.drain(..).collect();
impl<'render, 'target, 'frame, R: GraphicsApi, T: GraphicsApi, Target>
MultiFrame<'render, 'target, 'frame, R, T, Target>
where
R: 'static,
R::Error: 'static,
T::Error: 'static,
<R::Device as ApiDevice>::Renderer: Offscreen<Target> + ExportDma + ExportMem + ImportDma + ImportMem,
<T::Device as ApiDevice>::Renderer: ImportDma + ImportMem,
<<R::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
<<T::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
{
fn finish_internal(&mut self) -> Result<(), Error<R, T>> {
if let Some(frame) = self.frame.take() {
frame.finish().map_err(Error::Render)?;
(res, frame.damage)
})
.map_err(Error::Render);
// now the frame is gone, lets use our unholy ptr till the end of this call:
// SAFETY:
// - The renderer will never be invalid because the lifetime of the frame must be shorter than the renderer.
// - The pointer can't be aliased because of the following:
// - Creating a frame requires an `&mut` reference to the renderer, making the mutable borrow safe.
// - The mutable reference is used in a function which mutably borrows the frame, that either being `.finish()`
// (which takes ownership of the frame) or dropping the frame.
let render = unsafe { &mut *self.render };
// restore self
self.dma_source = dma_source;
self.target = target;
self.other_renderers = other_renderers;
let mut damage = std::mem::take(&mut self.damage)
.into_iter()
.map(|rect| {
rect.to_logical(1)
.to_buffer(1, self.dst_transform, &self.size.to_logical(1))
})
.collect::<Vec<_>>();
// then possibly return the error
let (res, damage) = res?;
let mut damage = damage
.into_iter()
.map(|rect| {
rect.to_logical(1)
.to_buffer(1, dst_transform, &size.to_logical(1))
})
.collect::<Vec<_>>();
if let Some(target) = self.target.as_mut() {
{
let mut can_import = CAN_IMPORT.lock().unwrap();
let dmabuf = self
.render
.renderer_mut()
.export_framebuffer(buffer_size)
.map_err(Error::Render)?;
let might_import = *can_import
.get(&(*self.render.node(), *target.node(), dmabuf.format()))
.unwrap_or(&true);
if might_import {
// try gpu copy
match target.renderer_mut().import_dmabuf(&dmabuf, Some(&damage)) {
Ok(texture) => {
// import successful
let damage = damage
.iter()
.map(|rect| rect.to_logical(1, dst_transform, &buffer_size).to_physical(1))
.collect::<Vec<_>>();
target
.renderer_mut()
.render(size, dst_transform, |_renderer, frame| {
frame.render_texture_from_to(
let buffer_size = self.size.to_logical(1).to_buffer(1, self.dst_transform);
if let Some(target) = self.target.as_mut() {
{
let mut can_import = CAN_IMPORT.lock().unwrap();
let dmabuf = render
.renderer_mut()
.export_framebuffer(buffer_size)
.map_err(Error::Render)?;
let might_import = *can_import
.get(&(*render.node(), *target.node(), dmabuf.format()))
.unwrap_or(&true);
if might_import {
// try gpu copy
match target.renderer_mut().import_dmabuf(&dmabuf, Some(&damage)) {
Ok(texture) => {
// import successful
let damage = damage
.iter()
.map(|rect| {
rect.to_logical(1, self.dst_transform, &buffer_size)
.to_physical(1)
})
.collect::<Vec<_>>();
let mut frame = target
.renderer_mut()
.render(self.size, self.dst_transform)
.map_err(Error::Target)?;
frame
.render_texture_from_to(
&texture,
Rectangle::from_loc_and_size((0, 0), buffer_size).to_f64(),
Rectangle::from_loc_and_size((0, 0), size),
Rectangle::from_loc_and_size((0, 0), self.size),
&damage,
dst_transform.invert(),
self.dst_transform.invert(),
1.0,
)
})
.and_then(std::convert::identity)
.map_err(Error::Target)?;
.map_err(Error::Target)?;
frame.finish().map_err(Error::Target)?;
can_import.insert((*self.render.node(), *target.node(), dmabuf.format()), true);
return Ok(res);
}
Err(err) => {
let (source, target, format) =
(*self.render.node(), *target.node(), dmabuf.format());
slog::warn!(
self.log,
"Error importing dmabuf (format: {:?}) from {} to {}: {}",
format,
source,
target,
err
);
slog::info!(self.log, "Falling back to cpu-copy.");
can_import.insert((source, target, format), false);
can_import.insert((*render.node(), *target.node(), dmabuf.format()), true);
return Ok(());
}
Err(err) => {
let (source, target, format) =
(*render.node(), *target.node(), dmabuf.format());
slog::warn!(
self.log,
"Error importing dmabuf (format: {:?}) from {} to {}: {}",
format,
source,
target,
err
);
slog::info!(self.log, "Falling back to cpu-copy.");
can_import.insert((source, target, format), false);
}
}
}
}
}
// cpu copy
if damage.len() > MAX_CPU_COPIES {
damage = Vec::from([Rectangle::from_loc_and_size((0, 0), buffer_size)]);
}
damage.dedup();
damage.retain(|rect| rect.overlaps(Rectangle::from_loc_and_size((0, 0), buffer_size)));
damage.retain(|rect| rect.size.h > 0 && rect.size.w > 0);
// merge overlapping rectangles
damage = damage.into_iter().fold(Vec::new(), |new_damage, mut rect| {
// replace with drain_filter, when that becomes stable to reuse the original Vec's memory
let (overlapping, mut new_damage): (Vec<_>, Vec<_>) =
new_damage.into_iter().partition(|other| other.overlaps(rect));
for overlap in overlapping {
rect = rect.merge(overlap);
// cpu copy
if damage.len() > MAX_CPU_COPIES {
damage = Vec::from([Rectangle::from_loc_and_size((0, 0), buffer_size)]);
}
new_damage.push(rect);
new_damage
});
damage.dedup();
damage.retain(|rect| rect.overlaps(Rectangle::from_loc_and_size((0, 0), buffer_size)));
damage.retain(|rect| rect.size.h > 0 && rect.size.w > 0);
// merge overlapping rectangles
damage = damage.into_iter().fold(Vec::new(), |new_damage, mut rect| {
// replace with drain_filter, when that becomes stable to reuse the original Vec's memory
let (overlapping, mut new_damage): (Vec<_>, Vec<_>) =
new_damage.into_iter().partition(|other| other.overlaps(rect));
let mut mappings = Vec::new();
for rect in damage {
let mapping = (
self.render
.renderer_mut()
.copy_framebuffer(rect)
.map_err(Error::Render)?,
rect,
);
mappings.push(mapping);
}
mappings.sort_by(|map1, map2| {
let size1 = map1.1.size;
let size2 = map2.1.size;
(size1.w * size1.h).cmp(&(size2.w * size2.h))
});
let render = &mut self.render;
target
.renderer_mut()
.render(size, dst_transform, move |target, frame| {
for mapping in mappings {
let slice = render
.renderer_mut()
.map_texture(&mapping.0)
.map_err(Error::Render::<R, T>)?;
let texture = target
.import_memory(slice, mapping.1.size, false)
.map_err(Error::Target)?;
let dst = mapping
.1
.to_logical(1, Transform::Normal, &buffer_size)
.to_physical(1);
frame
.render_texture_from_to(
&texture,
Rectangle::from_loc_and_size((0, 0), mapping.1.size).to_f64(),
dst,
&[Rectangle::from_loc_and_size((0, 0), dst.size)],
Transform::Normal,
1.0,
)
.map_err(Error::Target)?;
for overlap in overlapping {
rect = rect.merge(overlap);
}
Ok(())
})
.map_err(Error::Target)
.and_then(std::convert::identity)?;
new_damage.push(rect);
new_damage
});
let mut textures = Vec::new();
for rect in damage {
let texture = (
{
let mapping = render
.renderer_mut()
.copy_framebuffer(rect)
.map_err(Error::Render)?;
let slice = render
.renderer_mut()
.map_texture(&mapping)
.map_err(Error::Render::<R, T>)?;
target
.renderer_mut()
.import_memory(slice, rect.size, false)
.map_err(Error::Target)?
},
rect,
);
textures.push(texture);
}
let mut frame = target
.renderer_mut()
.render(self.size, self.dst_transform)
.map_err(Error::Target)?;
for (texture, rect) in textures {
let dst = rect.to_logical(1, Transform::Normal, &buffer_size).to_physical(1);
frame
.render_texture_from_to(
&texture,
Rectangle::from_loc_and_size((0, 0), rect.size).to_f64(),
dst,
&[Rectangle::from_loc_and_size((0, 0), dst.size)],
Transform::Normal,
1.0,
)
.map_err(Error::Target)?;
}
frame.finish().map_err(Error::Target)?;
}
}
Ok(res)
Ok(())
}
}
impl<'render, 'target, 'frame, R: GraphicsApi, T: GraphicsApi, Target> Drop
for MultiFrame<'render, 'target, 'frame, R, T, Target>
where
R: 'static,
R::Error: 'static,
T::Error: 'static,
<R::Device as ApiDevice>::Renderer: Offscreen<Target> + ExportDma + ExportMem + ImportDma + ImportMem,
<T::Device as ApiDevice>::Renderer: ImportDma + ImportMem,
<<R::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
<<T::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
{
fn drop(&mut self) {
if let Err(err) = self.finish_internal() {
slog::warn!(self.log, "Ignored error finishing MultiFrame on drop: {}", err);
}
}
}
@ -1076,29 +1110,18 @@ impl MultiTexture {
<<A::Device as ApiDevice>::Renderer as Renderer>::TextureId: 'static,
{
let tex = self.0.borrow();
// TODO: use Ref::filter_map when stabilized
if tex
.textures
.get(&TypeId::of::<A>())
.and_then(|textures| textures.get(render))
.and_then(|texture| texture.texture.as_ref())
.and_then(|texture| {
<dyn Any>::downcast_ref::<<<A::Device as ApiDevice>::Renderer as Renderer>::TextureId>(
&**texture,
)
})
.is_some()
{
Some(Ref::map(tex, |tex| {
tex.textures.get(&TypeId::of::<A>())
.and_then(|textures| textures.get(render))
.and_then(|texture| texture.texture.as_ref())
.and_then(|texture| <dyn Any>::downcast_ref::<<<A::Device as ApiDevice>::Renderer as Renderer>::TextureId>(&**texture))
.unwrap()
}))
} else {
None
}
Ref::filter_map(tex, |tex| {
tex.textures
.get(&TypeId::of::<A>())
.and_then(|textures| textures.get(render))
.and_then(|texture| texture.texture.as_ref())
.and_then(|texture| {
<dyn Any>::downcast_ref::<<<A::Device as ApiDevice>::Renderer as Renderer>::TextureId>(
&**texture,
)
})
})
.ok()
}
fn insert_texture<A: GraphicsApi + 'static>(
@ -1194,33 +1217,42 @@ impl Texture for MultiTexture {
}
}
impl<R: GraphicsApi, T: GraphicsApi> Frame for MultiFrame<R, T>
impl<'render, 'target, 'frame, R: GraphicsApi, T: GraphicsApi, Target> Frame
for MultiFrame<'render, 'target, 'frame, R, T, Target>
where
R: 'static,
R::Error: 'static,
T::Error: 'static,
<R::Device as ApiDevice>::Renderer: Offscreen<Target> + ExportDma + ExportMem + ImportDma + ImportMem,
<T::Device as ApiDevice>::Renderer: ImportDma + ImportMem,
<<R::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
<<T::Device as ApiDevice>::Renderer as Renderer>::Error: 'static,
{
type Error = Error<R, T>;
type TextureId = MultiTexture;
type Error = Error<R, T>;
fn clear(&mut self, color: [f32; 4], at: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
fn id(&self) -> usize {
self.frame.as_ref().unwrap().id()
}
fn clear(&mut self, color: [f32; 4], at: &[Rectangle<i32, Physical>]) -> Result<(), Error<R, T>> {
self.damage.extend(at);
unsafe { &mut *self.frame }
self.frame
.as_mut()
.unwrap()
.clear(color, at)
.map_err(Error::Render)
}
fn render_texture_from_to(
&mut self,
texture: &Self::TextureId,
texture: &MultiTexture,
src: Rectangle<f64, BufferCoords>,
dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
src_transform: Transform,
alpha: f32,
) -> Result<(), Self::Error> {
) -> Result<(), Error<R, T>> {
if let Some(texture) = texture.get::<R>(&self.node) {
self.damage.extend(damage.iter().map(|rect| {
let rect = rect.to_f64();
@ -1235,7 +1267,9 @@ where
)
.to_i32_up()
}));
unsafe { &mut *self.frame }
self.frame
.as_mut()
.unwrap()
.render_texture_from_to(&texture, src, dst, damage, src_transform, alpha)
.map_err(Error::Render)
} else {
@ -1251,12 +1285,17 @@ where
}
fn transformation(&self) -> Transform {
unsafe { &mut *self.frame }.transformation()
self.frame.as_ref().unwrap().transformation()
}
fn finish(mut self) -> Result<(), Self::Error> {
self.finish_internal()
}
}
#[cfg(feature = "wayland_frontend")]
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> ImportMemWl for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> ImportMemWl
for MultiRenderer<'render, 'target, R, T, Target>
where
<R::Device as ApiDevice>::Renderer: ImportMemWl,
// We need this because the Renderer-impl does and ImportMem requires Renderer
@ -1291,7 +1330,8 @@ where
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> ImportMem for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> ImportMem
for MultiRenderer<'render, 'target, R, T, Target>
where
<R::Device as ApiDevice>::Renderer: ImportMem,
// We need this because the Renderer-impl does and ImportMem requires Renderer
@ -1337,7 +1377,8 @@ where
}
#[cfg(feature = "wayland_frontend")]
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> ImportDmaWl for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> ImportDmaWl
for MultiRenderer<'render, 'target, R, T, Target>
where
<R::Device as ApiDevice>::Renderer: ImportDmaWl + ImportMem + ExportMem,
<T::Device as ApiDevice>::Renderer: ExportMem,
@ -1370,7 +1411,8 @@ where
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> ImportDma for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> ImportDma
for MultiRenderer<'render, 'target, R, T, Target>
where
<R::Device as ApiDevice>::Renderer: ImportDma + ImportMem + ExportMem,
<T::Device as ApiDevice>::Renderer: ExportMem,
@ -1398,7 +1440,7 @@ where
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> MultiRenderer<'render, 'target, R, T, Target>
where
<R::Device as ApiDevice>::Renderer: ImportDma + ImportMem + ExportMem,
<T::Device as ApiDevice>::Renderer: ExportMem,
@ -1805,7 +1847,8 @@ where
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> ExportMem for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> ExportMem
for MultiRenderer<'render, 'target, R, T, Target>
where
<T::Device as ApiDevice>::Renderer: ExportMem,
<R::Device as ApiDevice>::Renderer: ExportMem,
@ -1875,7 +1918,8 @@ where
}
}
impl<'a, 'b, R: GraphicsApi, T: GraphicsApi, Target> ExportDma for MultiRenderer<'a, 'b, R, T, Target>
impl<'render, 'target, R: GraphicsApi, T: GraphicsApi, Target> ExportDma
for MultiRenderer<'render, 'target, R, T, Target>
where
<T::Device as ApiDevice>::Renderer: ExportDma,
// We need this because the Renderer-impl does and ExportDma requires Renderer

View file

@ -1,12 +1,5 @@
use crate::{
backend::renderer::{
buffer_dimensions, buffer_has_alpha,
element::{
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
RenderElement,
},
ImportAll, Renderer,
},
backend::renderer::{buffer_dimensions, buffer_has_alpha, element::RenderElement, ImportAll, Renderer},
utils::{Buffer as BufferCoord, Coordinate, Logical, Physical, Point, Rectangle, Scale, Size, Transform},
wayland::{
compositor::{
@ -230,12 +223,12 @@ impl RendererSurfaceState {
}
/// Gets a reference to the texture for the specified renderer
pub fn texture<R>(&self, renderer: &R) -> Option<&R::TextureId>
pub fn texture<R>(&self, id: usize) -> Option<&R::TextureId>
where
R: Renderer,
<R as Renderer>::TextureId: 'static,
{
let texture_id = (TypeId::of::<<R as Renderer>::TextureId>(), renderer.id());
let texture_id = (TypeId::of::<<R as Renderer>::TextureId>(), id);
self.textures.get(&texture_id).and_then(|e| e.downcast_ref())
}
@ -377,12 +370,54 @@ where
})
}
/// Imports buffers of a surface using a given [`Renderer`]
///
/// This (or `import_surface_tree`) need to be called before`draw_surface_tree`, if used later.
///
/// Note: This will do nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn import_surface<R>(
renderer: &mut R,
states: &SurfaceData,
log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error>
where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
{
if let Some(data) = states.data_map.get::<RendererSurfaceStateUserData>() {
let texture_id = (TypeId::of::<<R as Renderer>::TextureId>(), renderer.id());
let mut data_ref = data.borrow_mut();
let data = &mut *data_ref;
let last_commit = data.renderer_seen.get(&texture_id);
let buffer_damage = data.damage_since(last_commit.copied());
if let Entry::Vacant(e) = data.textures.entry(texture_id) {
if let Some(buffer) = data.buffer.as_ref() {
match renderer.import_buffer(buffer, Some(states), &buffer_damage) {
Some(Ok(m)) => {
e.insert(Box::new(m));
data.renderer_seen.insert(texture_id, data.current_commit());
}
Some(Err(err)) => {
slog::warn!(log, "Error loading buffer: {}", err);
return Err(err);
}
None => {
slog::error!(log, "Unknown buffer format for: {:?}", buffer);
}
}
}
}
}
Ok(())
}
/// Imports buffers of a surface and its subsurfaces using a given [`Renderer`].
///
/// This can be called early as an optimization, if `draw_surface_tree` is used later.
/// `draw_surface_tree` will also import buffers as necessary, but calling `import_surface_tree`
/// already may allow buffer imports to happen before compositing takes place, depending
/// on your event loop.
/// This (or `import_surface`) need to be called before`draw_surface_tree`, if used later.
///
/// Note: This will do nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
@ -396,54 +431,24 @@ where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
{
import_surface_tree_and(renderer, surface, 1.0, log, (0.0, 0.0).into(), |_, _, _| {})
}
let scale = 1.0;
let location: Point<f64, Physical> = (0.0, 0.0).into();
fn import_surface_tree_and<F, R, S>(
renderer: &mut R,
surface: &WlSurface,
scale: S,
log: &slog::Logger,
location: Point<f64, Physical>,
processor: F,
) -> Result<(), <R as Renderer>::Error>
where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
S: Into<Scale<f64>>,
F: FnMut(&WlSurface, &SurfaceData, &Point<f64, Physical>),
{
let texture_id = (TypeId::of::<<R as Renderer>::TextureId>(), renderer.id());
let mut result = Ok(());
let scale = scale.into();
with_surface_tree_downward(
surface,
location,
|_surface, states, location| {
let mut location = *location;
// Import a new buffer if necessary
if let Err(err) = import_surface(renderer, states, log) {
result = Err(err);
}
if let Some(data) = states.data_map.get::<RendererSurfaceStateUserData>() {
let mut data_ref = data.borrow_mut();
let data = &mut *data_ref;
// Import a new buffer if necessary
let last_commit = data.renderer_seen.get(&texture_id);
let buffer_damage = data.damage_since(last_commit.copied());
if let Entry::Vacant(e) = data.textures.entry(texture_id) {
if let Some(buffer) = data.buffer.as_ref() {
match renderer.import_buffer(buffer, Some(states), &buffer_damage) {
Some(Ok(m)) => {
e.insert(Box::new(m));
data.renderer_seen.insert(texture_id, data.current_commit());
}
Some(Err(err)) => {
slog::warn!(log, "Error loading buffer: {}", err);
result = Err(err);
}
None => {
slog::error!(log, "Unknown buffer format for: {:?}", buffer);
}
}
}
}
// Now, should we be drawn ?
if data.textures.contains_key(&texture_id) {
// if yes, also process the children
@ -459,46 +464,12 @@ where
TraversalAction::SkipChildren
}
},
processor,
|_, _, _| {},
|_, _, _| true,
);
result
}
/// Draws a surface and its subsurfaces using a given [`Renderer`] and [`Frame`](crate::backend::renderer::Frame).
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the surface should be drawn at.
/// - `damage` is the set of regions that should be drawn relative to the same origin as the location.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[allow(clippy::too_many_arguments)]
pub fn draw_surface_tree<R, S>(
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
surface: &WlSurface,
scale: S,
location: Point<f64, Physical>,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error>
where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
S: Into<Scale<f64>>,
{
let scale = scale.into();
let elements: Vec<WaylandSurfaceRenderElement> =
render_elements_from_surface_tree(surface, location.to_i32_round(), scale);
draw_render_elements(renderer, frame, scale, &elements, damage, log)?;
Ok(())
}
/// Draws the render elements using a given [`Renderer`] and [`Frame`](crate::backend::renderer::Frame)
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
@ -508,16 +479,15 @@ where
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn draw_render_elements<R, S, E>(
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
pub fn draw_render_elements<'a, R, S, E>(
frame: &mut <R as Renderer>::Frame<'a>,
scale: S,
elements: &[E],
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<Option<Vec<Rectangle<i32, Physical>>>, <R as Renderer>::Error>
where
R: Renderer + ImportAll,
R: Renderer,
<R as Renderer>::TextureId: 'static,
S: Into<Scale<f64>>,
E: RenderElement<R>,
@ -603,14 +573,7 @@ where
continue;
}
element.draw(
renderer,
frame,
element.location(scale),
scale,
&element_damage,
log,
)?;
element.draw(frame, element.location(scale), scale, &element_damage, log)?;
}
Ok(Some(render_damage))

View file

@ -54,7 +54,7 @@ pub use self::space::Space;
#[cfg(feature = "wayland_frontend")]
pub use self::wayland::{
layer::{draw_layer_surface, layer_map_for_output, LayerMap, LayerSurface},
layer::{layer_map_for_output, LayerMap, LayerSurface},
popup::*,
utils,
window::*,

View file

@ -167,21 +167,22 @@ where
fn render_elements<C: From<Self::RenderElement>>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
) -> Vec<C> {
match &self {
#[cfg(feature = "wayland_frontend")]
SpaceElements::Layer { surface, .. } => AsRenderElements::<R>::render_elements::<
WaylandSurfaceRenderElement,
>(surface, location, scale)
WaylandSurfaceRenderElement<R>,
>(surface, renderer, location, scale)
.into_iter()
.map(SpaceRenderElements::Surface)
.map(C::from)
.collect(),
SpaceElements::Element(element) => element
.element
.render_elements::<Wrap<<E as AsRenderElements<R>>::RenderElement>>(location, scale)
.render_elements::<Wrap<<E as AsRenderElements<R>>::RenderElement>>(renderer, location, scale)
.into_iter()
.map(SpaceRenderElements::Element)
.map(C::from)

View file

@ -31,17 +31,20 @@ where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
{
type RenderElement = WaylandSurfaceRenderElement;
type RenderElement = WaylandSurfaceRenderElement<R>;
fn render_elements<C: From<WaylandSurfaceRenderElement>>(
fn render_elements<C: From<WaylandSurfaceRenderElement<R>>>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
) -> Vec<C> {
crate::backend::renderer::element::surface::render_elements_from_surface_tree(
renderer,
&self.surface,
location,
scale,
None,
)
}
}

View file

@ -367,6 +367,7 @@ impl<E: SpaceElement + PartialEq> Space<E> {
/// Use [`Space::render_elements_for_output`], if you care about this.
pub fn render_elements_for_region<'a, R: Renderer, S: Into<Scale<f64>>>(
&'a self,
renderer: &mut R,
region: &Rectangle<i32, Logical>,
scale: S,
) -> Vec<<E as AsRenderElements<R>>::RenderElement>
@ -388,6 +389,7 @@ impl<E: SpaceElement + PartialEq> Space<E> {
let location = e.render_location() - region.loc;
e.element
.render_elements::<<E as AsRenderElements<R>>::RenderElement>(
renderer,
location.to_physical_precise_round(scale),
scale,
)
@ -402,6 +404,7 @@ impl<E: SpaceElement + PartialEq> Space<E> {
#[cfg(not(feature = "wayland_frontend"))] R: Renderer,
>(
&'a self,
renderer: &mut R,
output: &Output,
) -> Result<Vec<SpaceRenderElements<R, <E as AsRenderElements<R>>::RenderElement>>, OutputError>
where
@ -442,6 +445,7 @@ impl<E: SpaceElement + PartialEq> Space<E> {
.flat_map(|e| {
let location = e.render_location() - output_geo.loc;
e.render_elements::<SpaceRenderElements<R, <E as AsRenderElements<R>>::RenderElement>>(
renderer,
location.to_physical_precise_round(output_scale),
Scale::from(output_scale),
)
@ -496,7 +500,7 @@ crate::backend::renderer::element::render_elements! {
pub SpaceRenderElements<R, E> where
R: ImportAll;
/// A single wayland surface
Surface=WaylandSurfaceRenderElement,
Surface=WaylandSurfaceRenderElement<R>,
/// A single texture
Element=Wrap<E>,
}
@ -556,6 +560,7 @@ pub fn space_render_elements<
E: SpaceElement + PartialEq + AsRenderElements<R> + 'a,
S: IntoIterator<Item = &'a Space<E>>,
>(
renderer: &mut R,
spaces: S,
output: &Output,
) -> Result<Vec<SpaceRenderElements<R, <E as AsRenderElements<R>>::RenderElement>>, OutputNoMode>
@ -582,8 +587,9 @@ where
.into_iter()
.filter_map(|surface| layer_map.layer_geometry(surface).map(|geo| (geo.loc, surface)))
.flat_map(|(loc, surface)| {
AsRenderElements::<R>::render_elements::<WaylandSurfaceRenderElement>(
AsRenderElements::<R>::render_elements::<WaylandSurfaceRenderElement<R>>(
surface,
renderer,
loc.to_physical_precise_round(output_scale),
Scale::from(output_scale),
)
@ -599,7 +605,7 @@ where
if let Some(output_geo) = space.output_geometry(output) {
render_elements.extend(
space
.render_elements_for_region(&output_geo, output_scale)
.render_elements_for_region(renderer, &output_geo, output_scale)
.into_iter()
.map(|e| SpaceRenderElements::Element(Wrap::from(e))),
);
@ -612,8 +618,9 @@ where
.into_iter()
.filter_map(|surface| layer_map.layer_geometry(surface).map(|geo| (geo.loc, surface)))
.flat_map(|(loc, surface)| {
AsRenderElements::<R>::render_elements::<WaylandSurfaceRenderElement>(
AsRenderElements::<R>::render_elements::<WaylandSurfaceRenderElement<R>>(
surface,
renderer,
loc.to_physical_precise_round(output_scale),
Scale::from(output_scale),
)
@ -658,7 +665,7 @@ where
assert!(renderer_output == output);
}
let space_render_elements = space_render_elements(spaces, output)?;
let space_render_elements = space_render_elements(renderer, spaces, output)?;
let mut render_elements: Vec<OutputRenderElements<'a, R, <E as AsRenderElements<R>>::RenderElement, C>> =
Vec::with_capacity(custom_elements.len() + space_render_elements.len());

View file

@ -15,10 +15,11 @@ where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
{
type RenderElement = WaylandSurfaceRenderElement;
type RenderElement = WaylandSurfaceRenderElement<R>;
fn render_elements<C: From<WaylandSurfaceRenderElement>>(
fn render_elements<C: From<WaylandSurfaceRenderElement<R>>>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
) -> Vec<C> {
@ -32,12 +33,20 @@ where
.to_physical(scale)
.to_i32_round();
render_elements_from_surface_tree(popup.wl_surface(), location + offset, scale)
render_elements_from_surface_tree(
renderer,
popup.wl_surface(),
location + offset,
scale,
None,
)
});
render_elements.extend(popup_render_elements);
render_elements.extend(render_elements_from_surface_tree(surface, location, scale));
render_elements.extend(render_elements_from_surface_tree(
renderer, surface, location, scale, None,
));
render_elements
}

View file

@ -235,10 +235,11 @@ where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
{
type RenderElement = WaylandSurfaceRenderElement;
type RenderElement = WaylandSurfaceRenderElement<R>;
fn render_elements<C: From<WaylandSurfaceRenderElement>>(
fn render_elements<C: From<WaylandSurfaceRenderElement<R>>>(
&self,
renderer: &mut R,
location: Point<i32, Physical>,
scale: Scale<f64>,
) -> Vec<C> {
@ -250,12 +251,20 @@ where
let offset = (self.geometry().loc + popup_offset - popup.geometry().loc)
.to_physical_precise_round(scale);
render_elements_from_surface_tree(popup.wl_surface(), location + offset, scale)
render_elements_from_surface_tree(
renderer,
popup.wl_surface(),
location + offset,
scale,
None,
)
});
render_elements.extend(popup_render_elements);
render_elements.extend(render_elements_from_surface_tree(surface, location, scale));
render_elements.extend(render_elements_from_surface_tree(
renderer, surface, location, scale, None,
));
render_elements
}

View file

@ -1,12 +1,5 @@
use crate::{
backend::{
input::KeyState,
renderer::{
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
utils::draw_render_elements,
ImportAll, Renderer,
},
},
backend::input::KeyState,
desktop::{utils::*, PopupManager},
input::{
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
@ -14,7 +7,7 @@ use crate::{
Seat, SeatHandler,
},
output::{Output, WeakOutput},
utils::{user_data::UserDataMap, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial},
utils::{user_data::UserDataMap, IsAlive, Logical, Point, Rectangle, Serial},
wayland::{
compositor::{with_states, with_surface_tree_downward, SurfaceData, TraversalAction},
seat::WaylandFocus,
@ -656,40 +649,6 @@ impl LayerSurface {
}
}
/// Renders a given [`LayerSurface`] using a provided renderer and frame.
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the layer surface should be drawn at.
/// - `damage` is the set of regions of the layer surface that should be drawn.
///
/// Note: This function will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[allow(clippy::too_many_arguments)]
pub fn draw_layer_surface<R, P, S>(
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
layer: &LayerSurface,
scale: S,
location: P,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error>
where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
S: Into<Scale<f64>>,
P: Into<Point<i32, Physical>>,
{
let location = location.into();
let scale = scale.into();
let elements =
AsRenderElements::<R>::render_elements::<WaylandSurfaceRenderElement>(layer, location, scale);
draw_render_elements(renderer, frame, scale, &elements, damage, log)?;
Ok(())
}
impl<D: SeatHandler + 'static> PointerTarget<D> for LayerSurface {
fn enter(&self, seat: &Seat<D>, data: &mut D, event: &MotionEvent) {
if let Some((surface, loc)) = self.surface_under(event.location, WindowSurfaceType::ALL) {

View file

@ -1,12 +1,5 @@
use crate::{
backend::{
input::KeyState,
renderer::{
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
utils::draw_render_elements,
ImportAll, Renderer,
},
},
backend::input::KeyState,
desktop::{space::RenderZindex, utils::*, PopupManager},
input::{
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
@ -14,7 +7,7 @@ use crate::{
Seat, SeatHandler,
},
output::Output,
utils::{user_data::UserDataMap, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial},
utils::{user_data::UserDataMap, IsAlive, Logical, Point, Rectangle, Serial},
wayland::{
compositor::{with_states, SurfaceData},
seat::WaylandFocus,
@ -339,40 +332,6 @@ impl Window {
}
}
/// Renders a given [`Window`] using a provided renderer and frame.
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the window should be drawn at.
/// - `damage` is the set of regions of the window that should be drawn.
///
/// Note: This function will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[allow(clippy::too_many_arguments)]
pub fn draw_window<R, P, S>(
renderer: &mut R,
frame: &mut <R as Renderer>::Frame,
window: &Window,
scale: S,
location: P,
damage: &[Rectangle<i32, Physical>],
log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error>
where
R: Renderer + ImportAll,
<R as Renderer>::TextureId: 'static,
S: Into<Scale<f64>>,
P: Into<Point<i32, Physical>>,
{
let location = location.into();
let scale = scale.into();
let elements =
AsRenderElements::<R>::render_elements::<WaylandSurfaceRenderElement>(window, location, scale);
draw_render_elements(renderer, frame, scale, &elements, damage, log)?;
Ok(())
}
impl<D: SeatHandler + 'static> PointerTarget<D> for Window {
fn enter(&self, seat: &Seat<D>, data: &mut D, event: &MotionEvent) {
if let Some((surface, loc)) = self.surface_under(event.location, WindowSurfaceType::ALL) {

View file

@ -112,6 +112,7 @@ pub fn run(channel: Channel<WlcsEvent>) {
input_method.with_surface(|surface| {
elements.extend(AsRenderElements::<DummyRenderer>::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(surface),
&mut renderer,
position.to_physical_precise_round(scale),
scale,
));
@ -144,13 +145,14 @@ pub fn run(channel: Channel<WlcsEvent>) {
let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round();
pointer_element.set_status(cursor_guard.clone());
elements.extend(pointer_element.render_elements(cursor_pos_scaled, scale));
elements.extend(pointer_element.render_elements(&mut renderer, cursor_pos_scaled, scale));
// draw the dnd icon if any
if let Some(surface) = state.dnd_icon.as_ref() {
if surface.alive() {
elements.extend(AsRenderElements::<DummyRenderer>::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(surface),
&mut renderer,
cursor_pos_scaled,
scale,
));

View file

@ -25,23 +25,18 @@ impl DummyRenderer {
impl Renderer for DummyRenderer {
type Error = SwapBuffersError;
type TextureId = DummyTexture;
type Frame = DummyFrame;
type Frame<'a> = DummyFrame;
fn id(&self) -> usize {
0
}
fn render<F, R>(
fn render(
&mut self,
_size: Size<i32, Physical>,
_dst_transform: Transform,
rendering: F,
) -> Result<R, Self::Error>
where
F: FnOnce(&mut Self, &mut Self::Frame) -> R,
{
let mut frame = DummyFrame {};
Ok(rendering(self, &mut frame))
) -> Result<DummyFrame, Self::Error> {
Ok(DummyFrame {})
}
fn upscale_filter(&mut self, _filter: TextureFilter) -> Result<(), Self::Error> {
@ -153,6 +148,10 @@ impl Frame for DummyFrame {
type Error = SwapBuffersError;
type TextureId = DummyTexture;
fn id(&self) -> usize {
0
}
fn clear(&mut self, _color: [f32; 4], _damage: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
Ok(())
}
@ -172,6 +171,10 @@ impl Frame for DummyFrame {
fn transformation(&self) -> Transform {
Transform::Normal
}
fn finish(self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone)]