renderer: Closure-based api
This commit is contained in:
parent
73420b75bc
commit
978ef1b393
|
@ -6,7 +6,7 @@ use slog::Logger;
|
|||
use smithay::{
|
||||
backend::{
|
||||
egl::display::EGLBufferReader,
|
||||
renderer::{Renderer, Texture, Transform},
|
||||
renderer::{Frame, Renderer, Texture, Transform},
|
||||
SwapBuffersError,
|
||||
},
|
||||
reexports::{
|
||||
|
@ -36,8 +36,9 @@ impl<T> Drop for BufferTextures<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn draw_cursor<R, E, T>(
|
||||
pub fn draw_cursor<R, E, F, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
surface: &wl_surface::WlSurface,
|
||||
egl_buffer_reader: Option<&EGLBufferReader>,
|
||||
(x, y): (i32, i32),
|
||||
|
@ -45,7 +46,8 @@ pub fn draw_cursor<R, E, T>(
|
|||
log: &Logger,
|
||||
) -> Result<(), SwapBuffersError>
|
||||
where
|
||||
R: Renderer<Error = E, TextureId = T>,
|
||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
||||
F: Frame<Error = E, TextureId = T>,
|
||||
E: std::error::Error + Into<SwapBuffersError>,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -59,11 +61,12 @@ where
|
|||
(0, 0)
|
||||
}
|
||||
};
|
||||
draw_surface_tree(renderer, surface, egl_buffer_reader, (x - dx, y - dy), token, log)
|
||||
draw_surface_tree(renderer, frame, surface, egl_buffer_reader, (x - dx, y - dy), token, log)
|
||||
}
|
||||
|
||||
fn draw_surface_tree<R, E, T>(
|
||||
fn draw_surface_tree<R, E, F, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
root: &wl_surface::WlSurface,
|
||||
egl_buffer_reader: Option<&EGLBufferReader>,
|
||||
location: (i32, i32),
|
||||
|
@ -71,7 +74,8 @@ fn draw_surface_tree<R, E, T>(
|
|||
log: &Logger,
|
||||
) -> Result<(), SwapBuffersError>
|
||||
where
|
||||
R: Renderer<Error = E, TextureId = T>,
|
||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
||||
F: Frame<Error = E, TextureId = T>,
|
||||
E: std::error::Error + Into<SwapBuffersError>,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -79,8 +83,8 @@ where
|
|||
|
||||
compositor_token.with_surface_tree_upward(
|
||||
root,
|
||||
(),
|
||||
|_surface, attributes, _, _| {
|
||||
location,
|
||||
|_surface, attributes, role, &(mut x, mut y)| {
|
||||
// Pull a new buffer if available
|
||||
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||
let mut data = data.borrow_mut();
|
||||
|
@ -107,31 +111,7 @@ where
|
|||
}
|
||||
}
|
||||
// Now, should we be drawn ?
|
||||
if data.texture.is_some() {
|
||||
TraversalAction::DoChildren(())
|
||||
} else {
|
||||
// we are not displayed, so our children are neither
|
||||
TraversalAction::SkipChildren
|
||||
}
|
||||
} else {
|
||||
// we are not displayed, so our children are neither
|
||||
TraversalAction::SkipChildren
|
||||
}
|
||||
},
|
||||
|_, _, _, _| {},
|
||||
|_, _, _, _| true,
|
||||
);
|
||||
|
||||
compositor_token.with_surface_tree_upward(
|
||||
root,
|
||||
location,
|
||||
|_surface, attributes, role, &(mut x, mut y)| {
|
||||
// Pull a new buffer if available
|
||||
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||
let data = data.borrow();
|
||||
// Now, should we be drawn ?
|
||||
if data.texture.is_some() {
|
||||
// if yes, also process the children
|
||||
if data.texture.is_some() {// if yes, also process the children
|
||||
if Role::<SubsurfaceRole>::has(role) {
|
||||
x += data.current_state.sub_location.0;
|
||||
y += data.current_state.sub_location.1;
|
||||
|
@ -161,7 +141,7 @@ where
|
|||
x += sub_x;
|
||||
y += sub_y;
|
||||
}
|
||||
if let Err(err) = renderer.render_texture_at(
|
||||
if let Err(err) = frame.render_texture_at(
|
||||
&texture.texture,
|
||||
(x, y),
|
||||
Transform::Normal, /* TODO */
|
||||
|
@ -178,8 +158,9 @@ where
|
|||
result
|
||||
}
|
||||
|
||||
pub fn draw_windows<R, E, T>(
|
||||
pub fn draw_windows<R, E, F, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
egl_buffer_reader: Option<&EGLBufferReader>,
|
||||
window_map: &MyWindowMap,
|
||||
output_rect: Option<Rectangle>,
|
||||
|
@ -187,7 +168,8 @@ pub fn draw_windows<R, E, T>(
|
|||
log: &::slog::Logger,
|
||||
) -> Result<(), SwapBuffersError>
|
||||
where
|
||||
R: Renderer<Error = E, TextureId = T>,
|
||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
||||
F: Frame<Error = E, TextureId = T>,
|
||||
E: std::error::Error + Into<SwapBuffersError>,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -206,6 +188,7 @@ where
|
|||
// this surface is a root of a subsurface tree that needs to be drawn
|
||||
if let Err(err) = draw_surface_tree(
|
||||
renderer,
|
||||
frame,
|
||||
&wl_surface,
|
||||
egl_buffer_reader,
|
||||
initial_place,
|
||||
|
@ -220,8 +203,9 @@ where
|
|||
result
|
||||
}
|
||||
|
||||
pub fn draw_dnd_icon<R, E, T>(
|
||||
pub fn draw_dnd_icon<R, E, F, T>(
|
||||
renderer: &mut R,
|
||||
frame: &mut F,
|
||||
surface: &wl_surface::WlSurface,
|
||||
egl_buffer_reader: Option<&EGLBufferReader>,
|
||||
(x, y): (i32, i32),
|
||||
|
@ -229,7 +213,8 @@ pub fn draw_dnd_icon<R, E, T>(
|
|||
log: &::slog::Logger,
|
||||
) -> Result<(), SwapBuffersError>
|
||||
where
|
||||
R: Renderer<Error = E, TextureId = T>,
|
||||
R: Renderer<Error = E, TextureId = T, Frame=F>,
|
||||
F: Frame<Error = E, TextureId = T>,
|
||||
E: std::error::Error + Into<SwapBuffersError>,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -239,39 +224,5 @@ where
|
|||
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
||||
);
|
||||
}
|
||||
draw_surface_tree(renderer, surface, egl_buffer_reader, (x, y), token, log)
|
||||
}
|
||||
|
||||
pub fn schedule_initial_render<R: Renderer + 'static, Data: 'static>(
|
||||
renderer: Rc<RefCell<R>>,
|
||||
evt_handle: &LoopHandle<Data>,
|
||||
logger: ::slog::Logger,
|
||||
) where
|
||||
<R as Renderer>::Error: Into<SwapBuffersError>,
|
||||
{
|
||||
let result = {
|
||||
let mut renderer = renderer.borrow_mut();
|
||||
// Does not matter if we render an empty frame
|
||||
renderer
|
||||
.begin(1, 1, Transform::Normal)
|
||||
.map_err(Into::<SwapBuffersError>::into)
|
||||
.and_then(|_| {
|
||||
renderer
|
||||
.clear([0.8, 0.8, 0.9, 1.0])
|
||||
.map_err(Into::<SwapBuffersError>::into)
|
||||
})
|
||||
.and_then(|_| renderer.finish())
|
||||
};
|
||||
if let Err(err) = result {
|
||||
match err {
|
||||
SwapBuffersError::AlreadySwapped => {}
|
||||
SwapBuffersError::TemporaryFailure(err) => {
|
||||
// TODO dont reschedule after 3(?) retries
|
||||
warn!(logger, "Failed to submit page_flip: {}", err);
|
||||
let handle = evt_handle.clone();
|
||||
evt_handle.insert_idle(move |_| schedule_initial_render(renderer, &handle, logger));
|
||||
}
|
||||
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
|
||||
}
|
||||
}
|
||||
draw_surface_tree(renderer, frame, surface, egl_buffer_reader, (x, y), token, log)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use smithay::{
|
|||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||
renderer::{
|
||||
gles2::{Gles2Renderer, Gles2Texture},
|
||||
Renderer, Transform,
|
||||
Frame, Renderer, Transform,
|
||||
},
|
||||
session::{auto::AutoSession, Session, Signal as SessionSignal},
|
||||
udev::{UdevBackend, UdevEvent},
|
||||
|
@ -528,10 +528,10 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
|||
.unwrap();
|
||||
|
||||
trace!(self.logger, "Backends: {:?}", backends.borrow().keys());
|
||||
for renderer in backends.borrow_mut().values() {
|
||||
for backend in backends.borrow_mut().values() {
|
||||
// render first frame
|
||||
trace!(self.logger, "Scheduling frame");
|
||||
schedule_initial_render(renderer.clone(), &self.loop_handle, self.logger.clone());
|
||||
schedule_initial_render(backend.clone(), &self.loop_handle, self.logger.clone());
|
||||
}
|
||||
|
||||
self.backends.insert(
|
||||
|
@ -767,70 +767,108 @@ impl DrmRenderer {
|
|||
.unwrap_or((0, 0)); // in this case the output will be removed.
|
||||
|
||||
// and draw in sync with our monitor
|
||||
surface.queue_frame()?;
|
||||
surface.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||
// draw the surfaces
|
||||
draw_windows(
|
||||
surface,
|
||||
egl_buffer_reader,
|
||||
window_map,
|
||||
Some(Rectangle {
|
||||
x: x as i32,
|
||||
y: y as i32,
|
||||
width: width as i32,
|
||||
height: height as i32,
|
||||
}),
|
||||
*compositor_token,
|
||||
logger,
|
||||
)?;
|
||||
surface.render(|renderer, frame| {
|
||||
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||
// draw the surfaces
|
||||
draw_windows(
|
||||
renderer,
|
||||
frame,
|
||||
egl_buffer_reader,
|
||||
window_map,
|
||||
Some(Rectangle {
|
||||
x: x as i32,
|
||||
y: y as i32,
|
||||
width: width as i32,
|
||||
height: height as i32,
|
||||
}),
|
||||
*compositor_token,
|
||||
logger,
|
||||
)?;
|
||||
|
||||
// get pointer coordinates
|
||||
let (ptr_x, ptr_y) = *pointer_location;
|
||||
let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
|
||||
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
|
||||
// get pointer coordinates
|
||||
let (ptr_x, ptr_y) = *pointer_location;
|
||||
let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
|
||||
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
|
||||
|
||||
// set cursor
|
||||
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
|
||||
// draw the dnd icon if applicable
|
||||
{
|
||||
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
||||
if wl_surface.as_ref().is_alive() {
|
||||
draw_dnd_icon(
|
||||
surface,
|
||||
// set cursor
|
||||
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
|
||||
// draw the dnd icon if applicable
|
||||
{
|
||||
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
||||
if wl_surface.as_ref().is_alive() {
|
||||
draw_dnd_icon(
|
||||
renderer,
|
||||
frame,
|
||||
wl_surface,
|
||||
egl_buffer_reader,
|
||||
(ptr_x, ptr_y),
|
||||
*compositor_token,
|
||||
logger,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw the cursor as relevant
|
||||
{
|
||||
// reset the cursor if the surface is no longer alive
|
||||
let mut reset = false;
|
||||
if let CursorImageStatus::Image(ref surface) = *cursor_status {
|
||||
reset = !surface.as_ref().is_alive();
|
||||
}
|
||||
if reset {
|
||||
*cursor_status = CursorImageStatus::Default;
|
||||
}
|
||||
|
||||
if let CursorImageStatus::Image(ref wl_surface) = *cursor_status {
|
||||
draw_cursor(
|
||||
renderer,
|
||||
frame,
|
||||
wl_surface,
|
||||
egl_buffer_reader,
|
||||
(ptr_x, ptr_y),
|
||||
*compositor_token,
|
||||
logger,
|
||||
)?;
|
||||
} else {
|
||||
frame.render_texture_at(pointer_image, (ptr_x, ptr_y), Transform::Normal, 1.0)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw the cursor as relevant
|
||||
{
|
||||
// reset the cursor if the surface is no longer alive
|
||||
let mut reset = false;
|
||||
if let CursorImageStatus::Image(ref surface) = *cursor_status {
|
||||
reset = !surface.as_ref().is_alive();
|
||||
}
|
||||
if reset {
|
||||
*cursor_status = CursorImageStatus::Default;
|
||||
}
|
||||
|
||||
if let CursorImageStatus::Image(ref wl_surface) = *cursor_status {
|
||||
draw_cursor(
|
||||
surface,
|
||||
wl_surface,
|
||||
egl_buffer_reader,
|
||||
(ptr_x, ptr_y),
|
||||
*compositor_token,
|
||||
logger,
|
||||
)?;
|
||||
} else {
|
||||
surface.render_texture_at(pointer_image, (ptr_x, ptr_y), Transform::Normal, 1.0)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
surface.finish()
|
||||
Ok(())
|
||||
}).map_err(Into::<SwapBuffersError>::into)
|
||||
.and_then(|x| x)
|
||||
.map_err(Into::<SwapBuffersError>::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn schedule_initial_render<Data: 'static>(
|
||||
renderer: Rc<RefCell<RenderSurface>>,
|
||||
evt_handle: &LoopHandle<Data>,
|
||||
logger: ::slog::Logger,
|
||||
) {
|
||||
let result = {
|
||||
let mut renderer = renderer.borrow_mut();
|
||||
// Does not matter if we render an empty frame
|
||||
renderer
|
||||
.render(|_, frame| {
|
||||
frame
|
||||
.clear([0.8, 0.8, 0.9, 1.0])
|
||||
.map_err(Into::<SwapBuffersError>::into)
|
||||
})
|
||||
.map_err(Into::<SwapBuffersError>::into)
|
||||
.and_then(|x| x.map_err(Into::<SwapBuffersError>::into))
|
||||
};
|
||||
if let Err(err) = result {
|
||||
match err {
|
||||
SwapBuffersError::AlreadySwapped => {}
|
||||
SwapBuffersError::TemporaryFailure(err) => {
|
||||
// TODO dont reschedule after 3(?) retries
|
||||
warn!(logger, "Failed to submit page_flip: {}", err);
|
||||
let handle = evt_handle.clone();
|
||||
evt_handle.insert_idle(move |_| schedule_initial_render(renderer, &handle, logger));
|
||||
}
|
||||
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
|
||||
|
||||
use smithay::{
|
||||
backend::{input::InputBackend, renderer::Renderer, winit, SwapBuffersError},
|
||||
backend::{input::InputBackend, renderer::Frame, winit, SwapBuffersError},
|
||||
reexports::{
|
||||
calloop::EventLoop,
|
||||
wayland_server::{protocol::wl_output, Display},
|
||||
|
@ -82,6 +82,7 @@ pub fn run_winit(
|
|||
});
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
let mut cursor_visible = true;
|
||||
|
||||
info!(log, "Initialization completed, starting the main loop.");
|
||||
|
||||
|
@ -98,70 +99,75 @@ pub fn run_winit(
|
|||
{
|
||||
let mut renderer = renderer.borrow_mut();
|
||||
|
||||
renderer.begin().expect("Failed to render frame");
|
||||
renderer
|
||||
.clear([0.8, 0.8, 0.9, 1.0])
|
||||
.expect("Failed to clear frame");
|
||||
|
||||
// draw the windows
|
||||
draw_windows(
|
||||
&mut *renderer,
|
||||
reader.as_ref(),
|
||||
&*state.window_map.borrow(),
|
||||
None,
|
||||
state.ctoken,
|
||||
&log,
|
||||
)
|
||||
.expect("Failed to renderer windows");
|
||||
let result = renderer.render(|renderer, frame| {
|
||||
frame.clear([0.8, 0.8, 0.9, 1.0])?;
|
||||
|
||||
let (x, y) = *state.pointer_location.borrow();
|
||||
// draw the dnd icon if any
|
||||
{
|
||||
let guard = state.dnd_icon.lock().unwrap();
|
||||
if let Some(ref surface) = *guard {
|
||||
if surface.as_ref().is_alive() {
|
||||
draw_dnd_icon(
|
||||
&mut *renderer,
|
||||
// draw the windows
|
||||
draw_windows(
|
||||
renderer,
|
||||
frame,
|
||||
reader.as_ref(),
|
||||
&*state.window_map.borrow(),
|
||||
None,
|
||||
state.ctoken,
|
||||
&log,
|
||||
)?;
|
||||
|
||||
let (x, y) = *state.pointer_location.borrow();
|
||||
// draw the dnd icon if any
|
||||
{
|
||||
let guard = state.dnd_icon.lock().unwrap();
|
||||
if let Some(ref surface) = *guard {
|
||||
if surface.as_ref().is_alive() {
|
||||
draw_dnd_icon(
|
||||
renderer,
|
||||
frame,
|
||||
surface,
|
||||
reader.as_ref(),
|
||||
(x as i32, y as i32),
|
||||
state.ctoken,
|
||||
&log,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw the cursor as relevant
|
||||
{
|
||||
let mut guard = state.cursor_status.lock().unwrap();
|
||||
// reset the cursor if the surface is no longer alive
|
||||
let mut reset = false;
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
reset = !surface.as_ref().is_alive();
|
||||
}
|
||||
if reset {
|
||||
*guard = CursorImageStatus::Default;
|
||||
}
|
||||
|
||||
// draw as relevant
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
cursor_visible = false;
|
||||
draw_cursor(
|
||||
renderer,
|
||||
frame,
|
||||
surface,
|
||||
reader.as_ref(),
|
||||
(x as i32, y as i32),
|
||||
state.ctoken,
|
||||
&log,
|
||||
)
|
||||
.expect("Failed to render dnd icon");
|
||||
)?;
|
||||
} else {
|
||||
cursor_visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw the cursor as relevant
|
||||
{
|
||||
let mut guard = state.cursor_status.lock().unwrap();
|
||||
// reset the cursor if the surface is no longer alive
|
||||
let mut reset = false;
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
reset = !surface.as_ref().is_alive();
|
||||
}
|
||||
if reset {
|
||||
*guard = CursorImageStatus::Default;
|
||||
}
|
||||
|
||||
// draw as relevant
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
renderer.window().set_cursor_visible(false);
|
||||
draw_cursor(
|
||||
&mut *renderer,
|
||||
surface,
|
||||
reader.as_ref(),
|
||||
(x as i32, y as i32),
|
||||
state.ctoken,
|
||||
&log,
|
||||
)
|
||||
.expect("Failed to render cursor");
|
||||
} else {
|
||||
renderer.window().set_cursor_visible(true);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}).map_err(Into::<SwapBuffersError>::into)
|
||||
.and_then(|x| x.into());
|
||||
|
||||
renderer.window().set_cursor_visible(cursor_visible);
|
||||
|
||||
if let Err(SwapBuffersError::ContextLost(err)) = renderer.finish() {
|
||||
if let Err(SwapBuffersError::ContextLost(err)) = result {
|
||||
error!(log, "Critical Rendering Error: {}", err);
|
||||
state.running.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
|
|
@ -2,17 +2,12 @@ use std::collections::HashSet;
|
|||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
use crate::wayland::compositor::Damage;
|
||||
use cgmath::Matrix3;
|
||||
use drm::buffer::PlanarBuffer;
|
||||
use drm::control::{connector, crtc, framebuffer, plane, Device, Mode};
|
||||
use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice};
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||
|
||||
use super::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface};
|
||||
use crate::backend::renderer::{Bind, Renderer, Texture, Transform};
|
||||
use crate::backend::renderer::{Bind, Frame, Renderer, Texture, Transform};
|
||||
use crate::backend::SwapBuffersError;
|
||||
use crate::backend::{
|
||||
allocator::{
|
||||
|
@ -20,8 +15,6 @@ use crate::backend::{
|
|||
Allocator, Buffer, Format, Fourcc, Modifier, Slot, Swapchain,
|
||||
},
|
||||
};
|
||||
#[cfg(all(feature = "backend_egl", feature = "wayland_frontend"))]
|
||||
use crate::backend::egl::display::EGLBufferReader;
|
||||
|
||||
/// Simplified by limited abstraction to link single [`DrmSurface`]s to renderers.
|
||||
///
|
||||
|
@ -33,7 +26,6 @@ use crate::backend::egl::display::EGLBufferReader;
|
|||
pub struct DrmRenderSurface<D: AsRawFd + 'static, A: Allocator<B>, R: Bind<Dmabuf>, B: Buffer> {
|
||||
_format: Format,
|
||||
buffers: Buffers<D, B>,
|
||||
current_buffer: Option<(Slot<B, (Dmabuf, BufferObject<FbHandle<D>>)>, Dmabuf)>,
|
||||
swapchain: Swapchain<A, B, (Dmabuf, BufferObject<FbHandle<D>>)>,
|
||||
renderer: R,
|
||||
drm: Arc<DrmSurface<D>>,
|
||||
|
@ -169,11 +161,11 @@ where
|
|||
.map_err(Error::<E1, E2, E3>::RenderError)
|
||||
.and_then(|_| {
|
||||
renderer
|
||||
.begin(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal)
|
||||
.render(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal, |_, frame| {
|
||||
frame.clear([0.0, 0.0, 0.0, 1.0])
|
||||
})
|
||||
.map_err(Error::RenderError)
|
||||
})
|
||||
.and_then(|_| renderer.clear([0.0, 0.0, 0.0, 1.0]).map_err(Error::RenderError))
|
||||
.and_then(|_| renderer.finish().map_err(|_| Error::InitialRenderingError))
|
||||
.and_then(|_| renderer.unbind().map_err(Error::RenderError))
|
||||
{
|
||||
Ok(_) => {}
|
||||
|
@ -204,7 +196,6 @@ where
|
|||
renderer,
|
||||
swapchain,
|
||||
buffers,
|
||||
current_buffer: None,
|
||||
})
|
||||
}
|
||||
Err(err) => {
|
||||
|
@ -217,34 +208,53 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Shortcut to [`Renderer::begin`] with the pending mode as dimensions.
|
||||
pub fn queue_frame(&mut self) -> Result<(), Error<E1, E2, E3>> {
|
||||
let mode = self.drm.pending_mode();
|
||||
let (width, height) = (mode.size().0 as u32, mode.size().1 as u32);
|
||||
self.begin(width, height, Transform::Normal)
|
||||
/// Access the underlying renderer
|
||||
pub fn renderer(&mut self) -> &mut R {
|
||||
&mut self.renderer
|
||||
}
|
||||
|
||||
/// Shortcut to abort the current frame.
|
||||
///
|
||||
/// Allows [`DrmRenderSurface::queue_frame`] or [`Renderer::begin`] to be called again
|
||||
/// without displaying the current rendering context to the user.
|
||||
pub fn drop_frame(&mut self) -> Result<(), SwapBuffersError> {
|
||||
if self.current_buffer.is_none() {
|
||||
return Ok(());
|
||||
/// Shortcut to [`Renderer::render`] with the pending mode as dimensions
|
||||
/// and this surface set a the rendering target.
|
||||
pub fn render<F, S>(&mut self, rendering: F) -> Result<S, Error<E1, E2, E3>>
|
||||
where
|
||||
F: FnOnce(&mut R, &mut <R as Renderer>::Frame) -> S
|
||||
{
|
||||
let mode = self.drm.pending_mode();
|
||||
let (width, height) = (mode.size().0 as u32, mode.size().1 as u32);
|
||||
let slot = self
|
||||
.swapchain
|
||||
.acquire()
|
||||
.map_err(Error::SwapchainError)?
|
||||
.ok_or(Error::NoFreeSlotsError)?;
|
||||
let dmabuf = match &*slot.userdata() {
|
||||
Some((buf, _)) => buf.clone(),
|
||||
None => (*slot).export().map_err(Error::AsDmabufError)?,
|
||||
};
|
||||
self.renderer.bind(dmabuf.clone()).map_err(Error::RenderError)?;
|
||||
|
||||
let result = self.renderer
|
||||
.render(
|
||||
width, height,
|
||||
Transform::Flipped180 /* TODO: add Add<Transform> implementation to add and correct _transform here */,
|
||||
rendering,
|
||||
)
|
||||
.map_err(Error::RenderError)?;
|
||||
|
||||
match self.buffers.queue::<E1, E2, E3>(slot, dmabuf) {
|
||||
Ok(()) => {}
|
||||
Err(Error::DrmError(drm)) => return Err(drm.into()),
|
||||
Err(Error::GbmError(err)) => return Err(err.into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// finish the renderer in case it needs it
|
||||
let result = self.renderer.finish();
|
||||
// but do not queue the buffer, drop it in any case
|
||||
let _ = self.current_buffer.take();
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Marks the current frame as submitted.
|
||||
///
|
||||
/// Needs to be called, after the vblank event of the matching [`DrmDevice`](super::DrmDevice)
|
||||
/// was received after calling [`Renderer::finish`] on this surface. Otherwise the rendering
|
||||
/// will run out of buffers eventually.
|
||||
/// was received after calling [`DrmRenderSurface::render`] on this surface.
|
||||
/// Otherwise the rendering will run out of buffers eventually.
|
||||
pub fn frame_submitted(&mut self) -> Result<(), Error<E1, E2, E3>> {
|
||||
self.buffers.submitted()
|
||||
}
|
||||
|
@ -325,100 +335,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<D, A, B, T, R, E1, E2, E3> Renderer for DrmRenderSurface<D, A, R, B>
|
||||
where
|
||||
D: AsRawFd + 'static,
|
||||
A: Allocator<B, Error = E1>,
|
||||
B: Buffer + AsDmabuf<Error = E2>,
|
||||
R: Bind<Dmabuf> + Renderer<Error = E3, TextureId = T>,
|
||||
T: Texture,
|
||||
E1: std::error::Error + 'static,
|
||||
E2: std::error::Error + 'static,
|
||||
E3: std::error::Error + 'static,
|
||||
{
|
||||
type Error = Error<E1, E2, E3>;
|
||||
type TextureId = T;
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
||||
&mut self,
|
||||
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
||||
) -> Result<Self::TextureId, Self::Error> {
|
||||
self.renderer.import_bitmap(image).map_err(Error::RenderError)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||
self.renderer.shm_formats()
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "backend_egl", feature = "wayland_frontend"))]
|
||||
fn import_buffer(
|
||||
&mut self,
|
||||
buffer: &wl_buffer::WlBuffer,
|
||||
damage: Option<&Damage>,
|
||||
egl: Option<&EGLBufferReader>,
|
||||
) -> Result<Self::TextureId, Self::Error> {
|
||||
self.renderer
|
||||
.import_buffer(buffer, damage, egl)
|
||||
.map_err(Error::RenderError)
|
||||
}
|
||||
|
||||
fn begin(&mut self, width: u32, height: u32, _transform: Transform) -> Result<(), Error<E1, E2, E3>> {
|
||||
if self.current_buffer.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let slot = self
|
||||
.swapchain
|
||||
.acquire()
|
||||
.map_err(Error::SwapchainError)?
|
||||
.ok_or(Error::NoFreeSlotsError)?;
|
||||
let dmabuf = match &*slot.userdata() {
|
||||
Some((buf, _)) => buf.clone(),
|
||||
None => (*slot).export().map_err(Error::AsDmabufError)?,
|
||||
};
|
||||
self.renderer.bind(dmabuf.clone()).map_err(Error::RenderError)?;
|
||||
self.current_buffer = Some((slot, dmabuf));
|
||||
self.renderer
|
||||
.begin(width, height, Transform::Flipped180 /* TODO: add Add<Transform> implementation to add and correct _transform here */)
|
||||
.map_err(Error::RenderError)
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||
self.renderer.clear(color).map_err(Error::RenderError)
|
||||
}
|
||||
|
||||
fn render_texture(
|
||||
&mut self,
|
||||
texture: &Self::TextureId,
|
||||
matrix: Matrix3<f32>,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.renderer
|
||||
.render_texture(texture, matrix, alpha)
|
||||
.map_err(Error::RenderError)
|
||||
}
|
||||
|
||||
fn finish(&mut self) -> Result<(), SwapBuffersError> {
|
||||
if self.current_buffer.is_none() {
|
||||
return Err(SwapBuffersError::AlreadySwapped);
|
||||
}
|
||||
|
||||
let result = self.renderer.finish();
|
||||
if result.is_ok() {
|
||||
let (slot, dmabuf) = self.current_buffer.take().unwrap();
|
||||
match self.buffers.queue::<E1, E2, E3>(slot, dmabuf) {
|
||||
Ok(()) => {}
|
||||
Err(Error::DrmError(drm)) => return Err(drm.into()),
|
||||
Err(Error::GbmError(err)) => return Err(SwapBuffersError::ContextLost(Box::new(err))),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
struct FbHandle<D: AsRawFd + 'static> {
|
||||
drm: Arc<DrmSurface<D>>,
|
||||
fb: framebuffer::Handle,
|
||||
|
|
|
@ -19,7 +19,7 @@ use cgmath::{prelude::*, Matrix3};
|
|||
mod shaders;
|
||||
mod version;
|
||||
|
||||
use super::{Bind, Renderer, Texture, Transform, Unbind};
|
||||
use super::{Bind, Frame, Renderer, Texture, Transform, Unbind};
|
||||
use crate::backend::allocator::{
|
||||
dmabuf::{Dmabuf, WeakDmabuf},
|
||||
Format,
|
||||
|
@ -48,7 +48,7 @@ pub mod ffi {
|
|||
// cannot assume, that resources between two renderers are (and even can be) shared.
|
||||
static RENDERER_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct Gles2Program {
|
||||
program: ffi::types::GLuint,
|
||||
uniform_tex: ffi::types::GLint,
|
||||
|
@ -147,13 +147,12 @@ pub struct Gles2Renderer {
|
|||
buffers: Vec<WeakGles2Buffer>,
|
||||
target_buffer: Option<Gles2Buffer>,
|
||||
target_surface: Option<Rc<EGLSurface>>,
|
||||
current_projection: Option<Matrix3<f32>>,
|
||||
extensions: Vec<String>,
|
||||
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
textures: HashMap<BufferEntry, Gles2Texture>,
|
||||
gl: ffi::Gles2,
|
||||
egl: EGLContext,
|
||||
gl: ffi::Gles2,
|
||||
destruction_callback: Receiver<CleanupResource>,
|
||||
destruction_callback_sender: Sender<CleanupResource>,
|
||||
logger_ptr: Option<*mut ::slog::Logger>,
|
||||
|
@ -161,6 +160,13 @@ pub struct Gles2Renderer {
|
|||
_not_send: *mut (),
|
||||
}
|
||||
|
||||
/// Handle to the currently rendered frame during [`Gles2Renderer::render`](Renderer::render)
|
||||
pub struct Gles2Frame {
|
||||
current_projection: Matrix3<f32>,
|
||||
gl: ffi::Gles2,
|
||||
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
||||
}
|
||||
|
||||
impl fmt::Debug for Gles2Renderer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Gles2Renderer")
|
||||
|
@ -168,7 +174,6 @@ impl fmt::Debug for Gles2Renderer {
|
|||
.field("buffers", &self.buffers)
|
||||
.field("target_buffer", &self.target_buffer)
|
||||
.field("target_surface", &self.target_surface)
|
||||
.field("current_projection", &self.current_projection)
|
||||
.field("extensions", &self.extensions)
|
||||
.field("programs", &self.programs)
|
||||
// ffi::Gles2 does not implement Debug
|
||||
|
@ -453,7 +458,6 @@ impl Gles2Renderer {
|
|||
buffers: Vec::new(),
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
textures: HashMap::new(),
|
||||
current_projection: None,
|
||||
destruction_callback: rx,
|
||||
destruction_callback_sender: tx,
|
||||
logger_ptr,
|
||||
|
@ -596,7 +600,6 @@ impl Gles2Renderer {
|
|||
self.gl.BindTexture(ffi::TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
self.egl.unbind()?;
|
||||
Ok(texture)
|
||||
})
|
||||
.map_err(Gles2Error::BufferAccessError)?
|
||||
|
@ -671,7 +674,6 @@ impl Gles2Renderer {
|
|||
self.make_current()?;
|
||||
let tex = Some(texture.0.texture);
|
||||
self.import_egl_image(egl_images[0], false, tex)?;
|
||||
self.egl.unbind()?;
|
||||
}
|
||||
Ok(Some(texture))
|
||||
}
|
||||
|
@ -867,6 +869,7 @@ static TEX_COORDS: [ffi::types::GLfloat; 8] = [
|
|||
impl Renderer for Gles2Renderer {
|
||||
type Error = Gles2Error;
|
||||
type TextureId = Gles2Texture;
|
||||
type Frame = Gles2Frame;
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||
|
@ -962,7 +965,15 @@ impl Renderer for Gles2Renderer {
|
|||
Ok(texture)
|
||||
}
|
||||
|
||||
fn begin(&mut self, width: u32, height: u32, transform: Transform) -> Result<(), Gles2Error> {
|
||||
fn render<F, R>(
|
||||
&mut self,
|
||||
width: u32, height: u32,
|
||||
transform: Transform,
|
||||
rendering: F,
|
||||
) -> Result<R, Self::Error>
|
||||
where
|
||||
F: FnOnce(&mut Self, &mut Self::Frame) -> R
|
||||
{
|
||||
self.make_current()?;
|
||||
// delayed destruction until the next frame rendering.
|
||||
self.cleanup()?;
|
||||
|
@ -991,13 +1002,44 @@ impl Renderer for Gles2Renderer {
|
|||
renderer[2][0] = -(1.0f32.copysign(renderer[0][0] + renderer[1][0]));
|
||||
renderer[2][1] = -(1.0f32.copysign(renderer[0][1] + renderer[1][1]));
|
||||
|
||||
// output transformation passed in by the user
|
||||
self.current_projection = Some(transform.matrix() * renderer);
|
||||
Ok(())
|
||||
let mut frame = Gles2Frame {
|
||||
gl: self.gl.clone(),
|
||||
programs: self.programs.clone(),
|
||||
// output transformation passed in by the user
|
||||
current_projection: transform.matrix() * renderer,
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl Frame for Gles2Frame {
|
||||
type Error = Gles2Error;
|
||||
type TextureId = Gles2Texture;
|
||||
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||
self.make_current()?;
|
||||
unsafe {
|
||||
self.gl.ClearColor(color[0], color[1], color[2], color[3]);
|
||||
self.gl.Clear(ffi::COLOR_BUFFER_BIT);
|
||||
|
@ -1012,13 +1054,8 @@ impl Renderer for Gles2Renderer {
|
|||
mut matrix: Matrix3<f32>,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.make_current()?;
|
||||
if self.current_projection.is_none() {
|
||||
return Err(Gles2Error::UnconstraintRenderingOperation);
|
||||
}
|
||||
|
||||
//apply output transformation
|
||||
matrix = self.current_projection.as_ref().unwrap() * matrix;
|
||||
matrix = self.current_projection * matrix;
|
||||
|
||||
let target = if tex.0.is_external {
|
||||
ffi::TEXTURE_EXTERNAL_OES
|
||||
|
@ -1083,31 +1120,4 @@ impl Renderer for Gles2Renderer {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(&mut self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||
self.make_current()?;
|
||||
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);
|
||||
}
|
||||
|
||||
self.current_projection = None;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,12 +140,67 @@ pub trait Texture {
|
|||
fn height(&self) -> u32;
|
||||
}
|
||||
|
||||
pub trait Frame {
|
||||
/// Error type returned by the rendering operations of this renderer.
|
||||
type Error: Error;
|
||||
/// Texture Handle type used by this renderer.
|
||||
type TextureId: Texture;
|
||||
|
||||
/// Clear the complete current target with a single given color.
|
||||
///
|
||||
/// This operation is only valid in between a `begin` and `finish`-call.
|
||||
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
|
||||
/// Render a texture to the current target using given projection matrix and alpha.
|
||||
///
|
||||
/// This operation is only valid in between a `begin` and `finish`-call.
|
||||
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
|
||||
fn render_texture(
|
||||
&mut self,
|
||||
texture: &Self::TextureId,
|
||||
matrix: Matrix3<f32>,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error>;
|
||||
/// Render a texture to the current target as a flat 2d-plane at a given
|
||||
/// position, applying the given transformation with the given alpha value.
|
||||
///
|
||||
/// This operation is only valid in between a `begin` and `finish`-call.
|
||||
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
|
||||
fn render_texture_at(
|
||||
&mut self,
|
||||
texture: &Self::TextureId,
|
||||
pos: (i32, i32),
|
||||
transform: Transform,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut mat = Matrix3::<f32>::identity();
|
||||
|
||||
// position and scale
|
||||
let size = texture.size();
|
||||
mat = mat * Matrix3::from_translation(Vector2::new(pos.0 as f32, pos.1 as f32));
|
||||
mat = mat * Matrix3::from_nonuniform_scale(size.0 as f32, size.1 as f32);
|
||||
|
||||
//apply surface transformation
|
||||
mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5));
|
||||
if transform == Transform::Normal {
|
||||
assert_eq!(mat, mat * transform.invert().matrix());
|
||||
assert_eq!(transform.matrix(), Matrix3::<f32>::identity());
|
||||
}
|
||||
mat = mat * transform.invert().matrix();
|
||||
mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5));
|
||||
|
||||
self.render_texture(texture, mat, alpha)
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstraction of commonly used rendering operations for compositors.
|
||||
pub trait Renderer {
|
||||
/// Error type returned by the rendering operations of this renderer.
|
||||
type Error: Error;
|
||||
/// Texture Handle type used by this renderer.
|
||||
type TextureId: Texture;
|
||||
|
||||
type Frame: Frame<Error=Self::Error, TextureId=Self::TextureId>;
|
||||
|
||||
/// Import a given bitmap into the renderer.
|
||||
///
|
||||
|
@ -196,64 +251,16 @@ pub trait Renderer {
|
|||
/// - There was a previous `begin`-call, which was not terminated by `finish`.
|
||||
/// - This renderer implements `Bind`, no target was bound *and* has no default target.
|
||||
/// - (Renderers not implementing `Bind` always have a default target.)
|
||||
fn begin(
|
||||
fn render<F, R>(
|
||||
&mut self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
transform: Transform,
|
||||
) -> Result<(), <Self as Renderer>::Error>;
|
||||
|
||||
/// Finish a renderering context, previously started by `begin`.
|
||||
///
|
||||
/// After this operation is finished the current rendering target contains a sucessfully rendered image.
|
||||
/// If the image is immediently shown to the user depends on the target.
|
||||
fn finish(&mut self) -> Result<(), SwapBuffersError>;
|
||||
|
||||
/// Clear the complete current target with a single given color.
|
||||
///
|
||||
/// This operation is only valid in between a `begin` and `finish`-call.
|
||||
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error>;
|
||||
/// Render a texture to the current target using given projection matrix and alpha.
|
||||
///
|
||||
/// This operation is only valid in between a `begin` and `finish`-call.
|
||||
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
|
||||
fn render_texture(
|
||||
&mut self,
|
||||
texture: &Self::TextureId,
|
||||
matrix: Matrix3<f32>,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error>;
|
||||
/// Render a texture to the current target as a flat 2d-plane at a given
|
||||
/// position, applying the given transformation with the given alpha value.
|
||||
///
|
||||
/// This operation is only valid in between a `begin` and `finish`-call.
|
||||
/// If called outside this operation may error-out, do nothing or modify future rendering results in any way.
|
||||
fn render_texture_at(
|
||||
&mut self,
|
||||
texture: &Self::TextureId,
|
||||
pos: (i32, i32),
|
||||
transform: Transform,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut mat = Matrix3::<f32>::identity();
|
||||
|
||||
// position and scale
|
||||
let size = texture.size();
|
||||
mat = mat * Matrix3::from_translation(Vector2::new(pos.0 as f32, pos.1 as f32));
|
||||
mat = mat * Matrix3::from_nonuniform_scale(size.0 as f32, size.1 as f32);
|
||||
|
||||
//apply surface transformation
|
||||
mat = mat * Matrix3::from_translation(Vector2::new(0.5, 0.5));
|
||||
if transform == Transform::Normal {
|
||||
assert_eq!(mat, mat * transform.invert().matrix());
|
||||
assert_eq!(transform.matrix(), Matrix3::<f32>::identity());
|
||||
}
|
||||
mat = mat * transform.invert().matrix();
|
||||
mat = mat * Matrix3::from_translation(Vector2::new(-0.5, -0.5));
|
||||
|
||||
self.render_texture(texture, mat, alpha)
|
||||
}
|
||||
rendering: F,
|
||||
) -> Result<R, Self::Error>
|
||||
where
|
||||
F: FnOnce(&mut Self, &mut Self::Frame) -> R
|
||||
;
|
||||
}
|
||||
|
||||
/// Returns the dimensions of a wl_buffer
|
||||
|
|
|
@ -10,17 +10,12 @@ use crate::backend::{
|
|||
UnusedEvent,
|
||||
},
|
||||
renderer::{
|
||||
gles2::{Gles2Error, Gles2Renderer, Gles2Texture},
|
||||
Bind, Renderer, Transform,
|
||||
gles2::{Gles2Error, Gles2Renderer, Gles2Frame, Gles2Texture},
|
||||
Bind, Unbind, Frame, Renderer, Transform,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
use crate::wayland::compositor::Damage;
|
||||
use cgmath::Matrix3;
|
||||
use std::{cell::RefCell, rc::Rc, time::Instant};
|
||||
use wayland_egl as wegl;
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||
use wayland_server::Display;
|
||||
use winit::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
|
||||
|
@ -259,72 +254,27 @@ impl WinitGraphicsBackend {
|
|||
&*self.window
|
||||
}
|
||||
|
||||
/// Shortcut to `Renderer::begin` with the current window dimensions.
|
||||
pub fn begin(&mut self) -> Result<(), Gles2Error> {
|
||||
/// Access the underlying renderer
|
||||
pub fn renderer(&mut self) -> &mut Gles2Renderer {
|
||||
&mut self.renderer
|
||||
}
|
||||
|
||||
/// Shortcut to `Renderer::render` with the current window dimensions
|
||||
/// and this window set as the rendering target.
|
||||
pub fn render<F, R>(&mut self, rendering: F) -> Result<R, crate::backend::SwapBuffersError>
|
||||
where
|
||||
F: FnOnce(&mut Gles2Renderer, &mut Gles2Frame) -> R
|
||||
{
|
||||
let (width, height) = {
|
||||
let size = self.size.borrow();
|
||||
size.physical_size.into()
|
||||
};
|
||||
|
||||
self.renderer.bind(self.egl.clone())?;
|
||||
self.renderer.begin(width, height, Transform::Normal)
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for WinitGraphicsBackend {
|
||||
type Error = Gles2Error;
|
||||
type TextureId = Gles2Texture;
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
fn import_bitmap<C: std::ops::Deref<Target = [u8]>>(
|
||||
&mut self,
|
||||
image: &image::ImageBuffer<image::Rgba<u8>, C>,
|
||||
) -> Result<Self::TextureId, Self::Error> {
|
||||
self.renderer.import_bitmap(image)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn shm_formats(&self) -> &[wl_shm::Format] {
|
||||
Renderer::shm_formats(&self.renderer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
fn import_buffer(
|
||||
&mut self,
|
||||
buffer: &wl_buffer::WlBuffer,
|
||||
damage: Option<&Damage>,
|
||||
egl: Option<&EGLBufferReader>,
|
||||
) -> Result<Self::TextureId, Self::Error> {
|
||||
self.renderer.import_buffer(buffer, damage, egl)
|
||||
}
|
||||
|
||||
fn begin(
|
||||
&mut self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
transform: Transform,
|
||||
) -> Result<(), <Self as Renderer>::Error> {
|
||||
self.renderer.bind(self.egl.clone())?;
|
||||
self.renderer.begin(width, height, transform)
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: [f32; 4]) -> Result<(), Self::Error> {
|
||||
self.renderer.clear(color)
|
||||
}
|
||||
|
||||
fn render_texture(
|
||||
&mut self,
|
||||
texture: &Self::TextureId,
|
||||
matrix: Matrix3<f32>,
|
||||
alpha: f32,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.renderer.render_texture(texture, matrix, alpha)
|
||||
}
|
||||
|
||||
fn finish(&mut self) -> Result<(), crate::backend::SwapBuffersError> {
|
||||
self.renderer.finish()?;
|
||||
let result = self.renderer.render(width, height, Transform::Normal, rendering)?;
|
||||
self.egl.swap_buffers()?;
|
||||
Ok(())
|
||||
self.renderer.unbind()?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue