mirror of
https://github.com/Smithay/smithay.git
synced 2024-09-28 03:21:14 +02:00
Merge pull request #816 from Smithay/feature/gat_renderer
This commit is contained in:
commit
a4b836f9f0
28 changed files with 974 additions and 861 deletions
|
@ -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>],
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>> {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>],
|
||||
|
|
|
@ -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(());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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::*,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in a new issue