From 12e80ca2c6e3211aa73e333ddb043df1d80e90de Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 26 May 2021 19:12:45 +0200 Subject: [PATCH] cargo fmt --- anvil/src/drawing.rs | 30 +- anvil/src/raw.rs | 664 +++++++++++++++++++++++++++++ anvil/src/udev.rs | 120 +++--- anvil/src/winit.rs | 103 ++--- examples/raw_drm.rs | 8 +- src/backend/allocator/dmabuf.rs | 6 +- src/backend/allocator/gbm.rs | 2 +- src/backend/allocator/swapchain.rs | 9 +- src/backend/drm/device/legacy.rs | 4 +- src/backend/drm/device/mod.rs | 9 +- src/backend/drm/mod.rs | 26 +- src/backend/drm/render.rs | 23 +- src/backend/drm/surface/atomic.rs | 77 +++- src/backend/drm/surface/mod.rs | 71 +-- src/backend/renderer/gles2/mod.rs | 66 +-- src/backend/renderer/mod.rs | 15 +- src/backend/winit.rs | 12 +- 17 files changed, 990 insertions(+), 255 deletions(-) create mode 100644 anvil/src/raw.rs diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index 1a3e81d..15a244d 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -15,7 +15,7 @@ use smithay::{ }, utils::Rectangle, wayland::{ - compositor::{roles::Role, SubsurfaceRole, TraversalAction, Damage}, + compositor::{roles::Role, Damage, SubsurfaceRole, TraversalAction}, data_device::DnDIconRole, seat::CursorImageRole, }, @@ -46,7 +46,7 @@ pub fn draw_cursor( log: &Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer, + R: Renderer, F: Frame, E: std::error::Error + Into, T: Texture + 'static, @@ -61,7 +61,15 @@ where (0, 0) } }; - draw_surface_tree(renderer, frame, 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( @@ -74,7 +82,7 @@ fn draw_surface_tree( log: &Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer, + R: Renderer, F: Frame, E: std::error::Error + Into, T: Texture + 'static, @@ -92,7 +100,12 @@ where if let Some(buffer) = data.current_state.buffer.take() { match renderer.import_buffer(&buffer, &attributes, egl_buffer_reader) { Ok(m) => { - let buffer = if smithay::wayland::shm::with_buffer_contents(&buffer, |_,_| ()).is_ok() { + let buffer = if smithay::wayland::shm::with_buffer_contents( + &buffer, + |_, _| (), + ) + .is_ok() + { buffer.release(); None } else { @@ -111,7 +124,8 @@ where } } // 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::::has(role) { x += data.current_state.sub_location.0; y += data.current_state.sub_location.1; @@ -168,7 +182,7 @@ pub fn draw_windows( log: &::slog::Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer, + R: Renderer, F: Frame, E: std::error::Error + Into, T: Texture + 'static, @@ -213,7 +227,7 @@ pub fn draw_dnd_icon( log: &::slog::Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer, + R: Renderer, F: Frame, E: std::error::Error + Into, T: Texture + 'static, diff --git a/anvil/src/raw.rs b/anvil/src/raw.rs new file mode 100644 index 0000000..d24adc1 --- /dev/null +++ b/anvil/src/raw.rs @@ -0,0 +1,664 @@ +use std::{ + cell::RefCell, + collections::hash_map::{Entry, HashMap}, + io::Error as IoError, + fs::{File, OpenOptions}, + rc::Rc, + os::unix::io::{AsRawFd, RawFd}, + sync::{atomic::Ordering, Arc, Mutex}, + time::Duration, +}; + +use image::ImageBuffer; +use slog::Logger; + +#[cfg(feature = "egl")] +use smithay::{ + backend::egl::display::EGLBufferReader, +}; +use smithay::{ + backend::{ + drm::{device_bind, DeviceHandler, DrmDevice, DrmError, DrmRenderSurface}, + egl::{EGLContext, EGLDisplay}, + renderer::{ + gles2::{Gles2Renderer, Gles2Texture}, + Frame, Renderer, Transform, + }, + SwapBuffersError, + }, + reexports::{ + calloop::{ + generic::Generic, + timer::{Timer, TimerHandle}, + EventLoop, LoopHandle, Source, + }, + drm::{ + self, + control::{ + connector::{Info as ConnectorInfo, State as ConnectorState}, + crtc, + encoder::Info as EncoderInfo, + Device as ControlDevice, + }, + }, + gbm::{BufferObject as GbmBuffer, Device as GbmDevice}, + nix::sys::stat::dev_t, + wayland_server::{ + protocol::{wl_output, wl_surface, wl_buffer}, + Display, Global, + }, + }, + utils::Rectangle, + wayland::{ + compositor::CompositorToken, + output::{Mode, Output, PhysicalProperties}, + seat::CursorImageStatus, + }, +}; + +use crate::drawing::*; +use crate::shell::{MyWindowMap, Roles}; +use crate::state::AnvilState; + +pub struct FileWrapper(File); +impl AsRawFd for FileWrapper { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +impl Clone for FileWrapper { + fn clone(&self) -> Self { + FileWrapper(self.0.try_clone().unwrap()) + } +} + +pub fn run_raw( + display: Rc>, + event_loop: &mut EventLoop, + path: impl AsRef, + log: Logger, +) -> Result<(), ()> { + let name = display + .borrow_mut() + .add_socket_auto() + .unwrap() + .into_string() + .unwrap(); + info!(log, "Listening on wayland socket"; "name" => name.clone()); + ::std::env::set_var("WAYLAND_DISPLAY", name); + + #[cfg(feature = "egl")] + let egl_buffer_reader = Rc::new(RefCell::new(None)); + + let output_map = Rc::new(RefCell::new(Vec::new())); + + /* + * Initialize the compositor + */ + let mut state = AnvilState::init( + display.clone(), + event_loop.handle(), + #[cfg(feature = "egl")] + egl_buffer_reader.clone(), + None, + None, + log.clone(), + ); + + /* + * Initialize the backend + */ + // Try to open the device + let mut options = OpenOptions::new(); + options.read(true); + options.write(true); + let _backend = if let Some((mut device, gbm)) = options.open(path.as_ref()) + .ok() + .and_then(|fd| { + let file = FileWrapper(fd); + match { + ( + DrmDevice::new(file.clone(), true, log.clone()), + GbmDevice::new(file), + ) + } { + (Ok(drm), Ok(gbm)) => Some((drm, gbm)), + (Err(err), _) => { + error!( + log, + "Aborting initializing {:?}, because of drm error: {}", path.as_ref(), err + ); + None + } + (_, Err(err)) => { + // TODO try DumbBuffer allocator in this case + error!( + log, + "Aborting initializing {:?}, because of gbm error: {}", path.as_ref(), err + ); + None + } + } + }) + { + let egl = match EGLDisplay::new(&gbm, log.clone()) { + Ok(display) => display, + Err(err) => { + warn!( + log, + "Skipping device {:?}, because of egl display error: {}", path.as_ref(), err + ); + return Err(()); + } + }; + + let context = match EGLContext::new(&egl, log.clone()) { + Ok(context) => context, + Err(err) => { + warn!( + log, + "Skipping device {:?}, because of egl context error: {}", path.as_ref(), err + ); + return Err(()); + } + }; + + #[cfg(feature = "egl")] + { + info!( + log, + "Initializing EGL Hardware Acceleration via {:?}", path.as_ref() + ); + *egl_buffer_reader.borrow_mut() = egl.bind_wl_display(&*display.borrow()).ok(); + } + + let backends = Rc::new(RefCell::new(scan_connectors( + &mut device, + &gbm, + &egl, + &context, + &mut *display.borrow_mut(), + &mut *output_map.borrow_mut(), + &log, + ))); + + let bytes = include_bytes!("../resources/cursor2.rgba"); + let pointer_image = { + let context = EGLContext::new_shared(&egl, &context, log.clone()).unwrap(); + let mut renderer = unsafe { Gles2Renderer::new(context, log.clone()).unwrap() }; + let image = ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(); + renderer + .import_bitmap(&image) + .expect("Failed to load pointer") + }; + + // Set the handler. + // Note: if you replicate this (very simple) structure, it is rather easy + // to introduce reference cycles with Rc. Be sure about your drop order + let renderer = Rc::new(DrmRenderer { + #[cfg(feature = "egl")] + egl_buffer_reader:egl_buffer_reader.borrow().clone(), + compositor_token: state.ctoken, + backends: backends.clone(), + window_map: state.window_map.clone(), + output_map: output_map.clone(), + pointer_location: state.pointer_location.clone(), + pointer_image, + cursor_status: state.cursor_status.clone(), + dnd_icon: state.dnd_icon.clone(), + logger: log.clone(), + start_time: std::time::Instant::now(), + }); + device.set_handler(DrmHandlerImpl { + renderer, + loop_handle: event_loop.handle(), + }); + + let event_source = device_bind(&event_loop.handle(), device) + .map_err(|e| -> IoError { e.into() }) + .unwrap(); + + trace!(log, "Backends: {:?}", backends.borrow().keys()); + for renderer in backends.borrow_mut().values() { + // render first frame + trace!(log, "Scheduling frame"); + schedule_initial_render(renderer.clone(), &event_loop.handle(), log.clone()); + } + + BackendData { + event_source, + surfaces: backends, + egl, + context, + } + } else { + return Err(()); + }; + + /* + * And run our loop + */ + + while state.running.load(Ordering::SeqCst) { + if event_loop + .dispatch(Some(Duration::from_millis(16)), &mut state) + .is_err() + { + state.running.store(false, Ordering::SeqCst); + } else { + display.borrow_mut().flush_clients(&mut state); + state.window_map.borrow_mut().refresh(); + } + } + + // Cleanup stuff + state.window_map.borrow_mut().clear(); + + Ok(()) +} + +pub fn scan_connectors( + device: &mut DrmDevice, + gbm: &GbmDevice, + egl: &EGLDisplay, + context: &EGLContext, + display: &mut Display, + output_map: &mut Vec, + logger: &::slog::Logger, +) -> HashMap>> { + // Get a set of all modesetting resource handles (excluding planes): + let res_handles = device.resource_handles().unwrap(); + + // Use first connected connector + let connector_infos: Vec = res_handles + .connectors() + .iter() + .map(|conn| device.get_connector(*conn).unwrap()) + .filter(|conn| conn.state() == ConnectorState::Connected) + .inspect(|conn| info!(logger, "Connected: {:?}", conn.interface())) + .collect(); + + let mut backends = HashMap::new(); + + // very naive way of finding good crtc/encoder/connector combinations. This problem is np-complete + for connector_info in connector_infos { + let encoder_infos = connector_info + .encoders() + .iter() + .filter_map(|e| *e) + .flat_map(|encoder_handle| device.get_encoder(encoder_handle)) + .collect::>(); + 'outer: for encoder_info in encoder_infos { + for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { + if let Entry::Vacant(entry) = backends.entry(crtc) { + info!( + logger, + "Trying to setup connector {:?}-{} with crtc {:?}", + connector_info.interface(), + connector_info.interface_id(), + crtc, + ); + let context = match EGLContext::new_shared(egl, context, logger.clone()) { + Ok(context) => context, + Err(err) => { + warn!(logger, "Failed to create EGLContext: {}", err); + continue; + } + }; + let renderer = match unsafe { Gles2Renderer::new(context, logger.clone()) } { + Ok(renderer) => renderer, + Err(err) => { + warn!(logger, "Failed to create Gles2 Renderer: {}", err); + continue; + } + }; + let surface = match device.create_surface( + crtc, + connector_info.modes()[0], + &[connector_info.handle()], + ) { + Ok(surface) => surface, + Err(err) => { + warn!(logger, "Failed to create drm surface: {}", err); + continue; + } + }; + let renderer = + match DrmRenderSurface::new(surface, gbm.clone(), renderer, logger.clone()) { + Ok(renderer) => renderer, + Err(err) => { + warn!(logger, "Failed to create rendering surface: {}", err); + continue; + } + }; + + output_map.push(MyOutput::new( + display, + device.device_id(), + crtc, + connector_info, + logger.clone(), + )); + + entry.insert(Rc::new(RefCell::new(renderer))); + break 'outer; + } + } + } + } + + backends +} + +pub struct MyOutput { + pub device_id: dev_t, + pub crtc: crtc::Handle, + pub size: (u32, u32), + _wl: Output, + global: Option>, +} + +impl MyOutput { + fn new( + display: &mut Display, + device_id: dev_t, + crtc: crtc::Handle, + conn: ConnectorInfo, + logger: ::slog::Logger, + ) -> MyOutput { + let (output, global) = Output::new( + display, + format!("{:?}", conn.interface()), + PhysicalProperties { + width: conn.size().unwrap_or((0, 0)).0 as i32, + height: conn.size().unwrap_or((0, 0)).1 as i32, + subpixel: wl_output::Subpixel::Unknown, + make: "Smithay".into(), + model: "Generic DRM".into(), + }, + logger, + ); + + let mode = conn.modes()[0]; + let (w, h) = mode.size(); + output.change_current_state( + Some(Mode { + width: w as i32, + height: h as i32, + refresh: (mode.vrefresh() * 1000) as i32, + }), + None, + None, + ); + output.set_preferred(Mode { + width: w as i32, + height: h as i32, + refresh: (mode.vrefresh() * 1000) as i32, + }); + + MyOutput { + device_id, + crtc, + size: (w as u32, h as u32), + _wl: output, + global: Some(global), + } + } +} + +impl Drop for MyOutput { + fn drop(&mut self) { + self.global.take().unwrap().destroy(); + } +} + +pub type RenderSurface = DrmRenderSurface, Gles2Renderer, GbmBuffer<()>>; + +struct BackendData { + surfaces: Rc>>>>, + context: EGLContext, + egl: EGLDisplay, + event_source: Source>>, +} + +pub struct DrmHandlerImpl { + renderer: Rc, + loop_handle: LoopHandle, +} + +impl DeviceHandler for DrmHandlerImpl { + fn vblank(&mut self, crtc: crtc::Handle) { + self.renderer.clone().render(crtc, None, Some(&self.loop_handle)) + } + + fn error(&mut self, error: DrmError) { + error!(self.renderer.logger, "{:?}", error); + } +} + +pub struct DrmRenderer { + #[cfg(feature = "egl")] + egl_buffer_reader: Option, + compositor_token: CompositorToken, + backends: Rc>>>>, + window_map: Rc>, + output_map: Rc>>, + pointer_location: Rc>, + pointer_image: Gles2Texture, + cursor_status: Arc>, + dnd_icon: Arc>>, + logger: ::slog::Logger, + start_time: std::time::Instant, +} + +impl DrmRenderer { + fn render( + self: Rc, + crtc: crtc::Handle, + timer: Option, crtc::Handle)>>, + evt_handle: Option<&LoopHandle>, + ) { + if let Some(surface) = self.backends.borrow().get(&crtc) { + let result = DrmRenderer::render_surface( + &mut *surface.borrow_mut(), + #[cfg(feature = "egl")] + self.egl_buffer_reader.as_ref(), + crtc, + &mut *self.window_map.borrow_mut(), + &mut *self.output_map.borrow_mut(), + &self.compositor_token, + &*self.pointer_location.borrow(), + &self.pointer_image, + &*self.dnd_icon.lock().unwrap(), + &mut *self.cursor_status.lock().unwrap(), + &self.logger, + ); + if let Err(err) = result { + warn!(self.logger, "Error during rendering: {:?}", err); + let reschedule = match err { + SwapBuffersError::AlreadySwapped => false, + SwapBuffersError::TemporaryFailure(err) => !matches!( + err.downcast_ref::(), + Some(&DrmError::DeviceInactive) + | Some(&DrmError::Access { + source: drm::SystemError::PermissionDenied, + .. + }) + ), + SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err), + }; + + if reschedule { + debug!(self.logger, "Rescheduling"); + match (timer, evt_handle) { + (Some(handle), _) => { + let _ = handle.add_timeout( + Duration::from_millis(1000 /*a seconds*/ / 60 /*refresh rate*/), + (Rc::downgrade(&self), crtc), + ); + } + (None, Some(evt_handle)) => { + let timer = Timer::new().unwrap(); + let handle = timer.handle(); + let _ = handle.add_timeout( + Duration::from_millis(1000 /*a seconds*/ / 60 /*refresh rate*/), + (Rc::downgrade(&self), crtc), + ); + evt_handle + .insert_source(timer, |(renderer, crtc), handle, _data| { + if let Some(renderer) = renderer.upgrade() { + renderer.render( + crtc, + Some(handle.clone()), + Option::<&LoopHandle>::None, + ); + } + }) + .unwrap(); + } + _ => unreachable!(), + } + } + } else { + // TODO: only send drawn windows the frames callback + // Send frame events so that client start drawing their next frame + self.window_map + .borrow() + .send_frames(self.start_time.elapsed().as_millis() as u32); + } + } + } + + #[allow(clippy::too_many_arguments)] + fn render_surface( + surface: &mut RenderSurface, + #[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>, + crtc: crtc::Handle, + window_map: &mut MyWindowMap, + output_map: &mut Vec, + compositor_token: &CompositorToken, + pointer_location: &(f64, f64), + pointer_image: &Gles2Texture, + dnd_icon: &Option, + cursor_status: &mut CursorImageStatus, + logger: &slog::Logger, + ) -> Result<(), SwapBuffersError> { + #[cfg(not(feature = "egl"))] + let egl_buffer_reader = None; + + surface.frame_submitted()?; + + // get output coordinates + let (x, y) = output_map + .iter() + .take_while(|output| output.crtc != crtc) + .fold((0u32, 0u32), |pos, output| (pos.0 + output.size.0, pos.1)); + let (width, height) = output_map + .iter() + .find(|output| output.crtc == crtc) + .map(|output| output.size) + .unwrap_or((0, 0)); // in this case the output will be removed. + + // and draw in sync with our monitor + surface.render(|renderer, frame| -> Result<(), SwapBuffersError> { + 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; + + // 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)?; + } + } + } + Ok(()) + }).map_err(Into::::into).and_then(|x| x) + } +} + +fn schedule_initial_render( + renderer: Rc>, + evt_handle: &LoopHandle, + 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::::into) + }) + .map_err(Into::::into) + .and_then(|x| x.map_err(Into::::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), + } + } +} \ No newline at end of file diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 37f6175..1adeadd 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -767,36 +767,61 @@ impl DrmRenderer { .unwrap_or((0, 0)); // in this case the output will be removed. // and draw in sync with our monitor - 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, - )?; + 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( + // 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, @@ -805,40 +830,17 @@ impl DrmRenderer { *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( - 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)?; - } - } - } - - Ok(()) - }).map_err(Into::::into) - .and_then(|x| x) - .map_err(Into::::into) + Ok(()) + }) + .map_err(Into::::into) + .and_then(|x| x) + .map_err(Into::::into) } } @@ -871,4 +873,4 @@ fn schedule_initial_render( SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err), } } -} \ No newline at end of file +} diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 8892e68..e0dcdc4 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -99,28 +99,55 @@ pub fn run_winit( { let mut renderer = renderer.borrow_mut(); + let result = renderer + .render(|renderer, frame| { + frame.clear([0.8, 0.8, 0.9, 1.0])?; - let result = renderer.render(|renderer, frame| { - frame.clear([0.8, 0.8, 0.9, 1.0])?; + // draw the windows + draw_windows( + renderer, + frame, + reader.as_ref(), + &*state.window_map.borrow(), + None, + state.ctoken, + &log, + )?; - // 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; + } - 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( + // draw as relevant + if let CursorImageStatus::Image(ref surface) = *guard { + cursor_visible = false; + draw_cursor( renderer, frame, surface, @@ -129,42 +156,16 @@ pub fn run_winit( state.ctoken, &log, )?; + } 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 { - cursor_visible = false; - draw_cursor( - renderer, - frame, - surface, - reader.as_ref(), - (x as i32, y as i32), - state.ctoken, - &log, - )?; - } else { - cursor_visible = true; - } - } + Ok(()) + }) + .map_err(Into::::into) + .and_then(|x| x.into()); - Ok(()) - }).map_err(Into::::into) - .and_then(|x| x.into()); - renderer.window().set_cursor_visible(cursor_visible); if let Err(SwapBuffersError::ContextLost(err)) = result { diff --git a/examples/raw_drm.rs b/examples/raw_drm.rs index 77d653f..1045d1a 100644 --- a/examples/raw_drm.rs +++ b/examples/raw_drm.rs @@ -122,7 +122,9 @@ fn main() { .unwrap(); // Start rendering - surface.commit([(framebuffer, surface.plane())].iter(), true).unwrap(); + surface + .commit([(framebuffer, surface.plane())].iter(), true) + .unwrap(); // Run event_loop.run(None, &mut (), |_| {}).unwrap(); @@ -158,7 +160,9 @@ impl DeviceHandler for DrmHandlerImpl { } let fb = self.current.userdata().unwrap(); - self.surface.page_flip([(fb, self.surface.plane())].iter(), true).unwrap(); + self.surface + .page_flip([(fb, self.surface.plane())].iter(), true) + .unwrap(); } fn error(&mut self, error: DrmError) { diff --git a/src/backend/allocator/dmabuf.rs b/src/backend/allocator/dmabuf.rs index 393f0e6..d20f6f5 100644 --- a/src/backend/allocator/dmabuf.rs +++ b/src/backend/allocator/dmabuf.rs @@ -1,12 +1,12 @@ //! Module for [dmabuf](https://01.org/linuxgraphics/gfx-docs/drm/driver-api/dma-buf.html) buffers. -//! +//! //! `Dmabuf`s act alike to smart pointers and can be freely cloned and passed around. //! Once the last `Dmabuf` reference is dropped, its file descriptor is closed and //! underlying resources are freed. -//! +//! //! If you want to hold on to a potentially alive dmabuf without blocking the free up //! of the underlying resouces, you may `downgrade` a `Dmabuf` reference to a `WeakDmabuf`. -//! +//! //! This can be especially useful in resources where other parts of the stack should decide upon //! the lifetime of the buffer. E.g. when you are only caching associated resources for a dmabuf. diff --git a/src/backend/allocator/gbm.rs b/src/backend/allocator/gbm.rs index ada2bd3..d1e0a05 100644 --- a/src/backend/allocator/gbm.rs +++ b/src/backend/allocator/gbm.rs @@ -1,5 +1,5 @@ //! Module for Buffers created using [libgbm](gbm). -//! +//! //! The re-exported [`GbmDevice`](gbm::Device) implements the [`Allocator`](super::Allocator) trait //! and [`GbmBuffer`](gbm::BufferObject) satisfies the [`Buffer`](super::Buffer) trait while also allowing //! conversions to and from [dmabufs](super::dmabuf). diff --git a/src/backend/allocator/swapchain.rs b/src/backend/allocator/swapchain.rs index c990668..83825f3 100644 --- a/src/backend/allocator/swapchain.rs +++ b/src/backend/allocator/swapchain.rs @@ -111,9 +111,14 @@ where /// The swapchain has an internal maximum of four re-usable buffers. /// This function returns the first free one. pub fn acquire(&mut self) -> Result>, A::Error> { - if let Some(free_slot) = self.slots.iter_mut().find(|s| !s.acquired.swap(true, Ordering::SeqCst)) { + if let Some(free_slot) = self + .slots + .iter_mut() + .find(|s| !s.acquired.swap(true, Ordering::SeqCst)) + { if free_slot.buffer.is_none() { - let mut free_slot = Arc::get_mut(free_slot).expect("Acquired was false, but Arc is not unique?"); + let mut free_slot = + Arc::get_mut(free_slot).expect("Acquired was false, but Arc is not unique?"); free_slot.buffer = Some(self.allocator.create_buffer( self.width, self.height, diff --git a/src/backend/drm/device/legacy.rs b/src/backend/drm/device/legacy.rs index df05346..014637b 100644 --- a/src/backend/drm/device/legacy.rs +++ b/src/backend/drm/device/legacy.rs @@ -90,7 +90,9 @@ impl LegacyDrmDevice { for crtc in res_handles.crtcs() { #[allow(deprecated)] - let _ = self.fd.set_cursor(*crtc, Option::<&drm::control::dumbbuffer::DumbBuffer>::None); + let _ = self + .fd + .set_cursor(*crtc, Option::<&drm::control::dumbbuffer::DumbBuffer>::None); // null commit (necessary to trigger removal on the kernel side with the legacy api.) self.fd .set_crtc(*crtc, None, (0, 0), &[], None) diff --git a/src/backend/drm/device/mod.rs b/src/backend/drm/device/mod.rs index 0e0faf1..d091271 100644 --- a/src/backend/drm/device/mod.rs +++ b/src/backend/drm/device/mod.rs @@ -5,18 +5,15 @@ use std::rc::Rc; use std::sync::{atomic::AtomicBool, Arc}; use calloop::{generic::Generic, InsertError, LoopHandle, Source}; -use drm::control::{ - connector, crtc, Device as ControlDevice, Event, Mode, - ResourceHandles, -}; +use drm::control::{connector, crtc, Device as ControlDevice, Event, Mode, ResourceHandles}; use drm::{ClientCapability, Device as BasicDevice}; use nix::libc::dev_t; use nix::sys::stat::fstat; pub(super) mod atomic; pub(super) mod legacy; -use super::{error::Error, Planes, planes}; use super::surface::{atomic::AtomicDrmSurface, legacy::LegacyDrmSurface, DrmSurface, DrmSurfaceInternal}; +use super::{error::Error, planes, Planes}; use atomic::AtomicDrmDevice; use legacy::LegacyDrmDevice; @@ -337,8 +334,6 @@ impl DrmDevice { } } - - /// Trait to receive events of a bound [`DrmDevice`] /// /// See [`device_bind`] diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index a91c601..4ac3784 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -74,7 +74,7 @@ pub use error::Error as DrmError; pub use render::{DrmRenderSurface, Error as DrmRenderError}; pub use surface::DrmSurface; -use drm::control::{plane, crtc, Device as ControlDevice, PlaneType}; +use drm::control::{crtc, plane, Device as ControlDevice, PlaneType}; /// A set of planes as supported by a crtc pub struct Planes { @@ -86,11 +86,15 @@ pub struct Planes { pub overlay: Vec, } -fn planes(dev: &impl ControlDevice, crtc: &crtc::Handle, has_universal_planes: bool) -> Result { +fn planes( + dev: &impl ControlDevice, + crtc: &crtc::Handle, + has_universal_planes: bool, +) -> Result { let mut primary = None; let mut cursor = None; let mut overlay = Vec::new(); - + let planes = dev.plane_handles().map_err(|source| DrmError::Access { errmsg: "Error loading plane handles", dev: dev.dev_path(), @@ -101,7 +105,7 @@ fn planes(dev: &impl ControlDevice, crtc: &crtc::Handle, has_universal_planes: b errmsg: "Error loading resource handles", dev: dev.dev_path(), source, - })?; + })?; for plane in planes.planes() { let info = dev.get_plane(*plane).map_err(|source| DrmError::Access { @@ -127,16 +131,8 @@ fn planes(dev: &impl ControlDevice, crtc: &crtc::Handle, has_universal_planes: b Ok(Planes { primary: primary.expect("Crtc has no primary plane"), - cursor: if has_universal_planes { - cursor - } else { - None - }, - overlay: if has_universal_planes { - overlay - } else { - Vec::new() - }, + cursor: if has_universal_planes { cursor } else { None }, + overlay: if has_universal_planes { overlay } else { Vec::new() }, }) } @@ -162,4 +158,4 @@ fn plane_type(dev: &impl ControlDevice, plane: plane::Handle) -> Result::RenderError) .and_then(|_| { renderer - .render(mode.size().0 as u32, mode.size().1 as u32, Transform::Normal, |_, frame| { - frame.clear([0.0, 0.0, 0.0, 1.0]) - }) + .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.unbind().map_err(Error::RenderError)) @@ -217,7 +218,7 @@ where /// and this surface set a the rendering target. pub fn render(&mut self, rendering: F) -> Result> where - F: FnOnce(&mut R, &mut ::Frame) -> S + F: FnOnce(&mut R, &mut ::Frame) -> S, { let mode = self.drm.pending_mode(); let (width, height) = (mode.size().0 as u32, mode.size().1 as u32); @@ -239,7 +240,7 @@ where rendering, ) .map_err(Error::RenderError)?; - + match self.buffers.queue::(slot, dmabuf) { Ok(()) => {} Err(Error::DrmError(drm)) => return Err(drm.into()), diff --git a/src/backend/drm/surface/atomic.rs b/src/backend/drm/surface/atomic.rs index 2bb4dc8..a61a598 100644 --- a/src/backend/drm/surface/atomic.rs +++ b/src/backend/drm/surface/atomic.rs @@ -379,8 +379,13 @@ impl AtomicDrmSurface { Ok(()) } - - pub fn use_plane(&self, plane: plane::Handle, position: (i32, i32), size: (u32, u32)) -> Result<(), Error> { + + pub fn use_plane( + &self, + plane: plane::Handle, + position: (i32, i32), + size: (u32, u32), + ) -> Result<(), Error> { let info = PlaneInfo { handle: plane, x: position.0, @@ -399,20 +404,26 @@ impl AtomicDrmSurface { &mut [].iter(), self.plane, &new_planes, - Some([(self.create_test_buffer(pending.mode.size())?, self.plane)] - .iter() - .chain(new_planes.iter().map(|info| { - match self.create_test_buffer((info.w as u16, info.h as u16)) { - Ok(test_buff) => Ok((test_buff, info.handle)), - Err(err) => Err(err), - } - }).collect::, _>>()?.iter()) + Some( + [(self.create_test_buffer(pending.mode.size())?, self.plane)] + .iter() + .chain( + new_planes + .iter() + .map( + |info| match self.create_test_buffer((info.w as u16, info.h as u16)) { + Ok(test_buff) => Ok((test_buff, info.handle)), + Err(err) => Err(err), + }, + ) + .collect::, _>>()? + .iter(), + ), ), Some(pending.mode), Some(pending.blob), )?; - self - .fd + self.fd .atomic_commit( &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], req, @@ -428,7 +439,11 @@ impl AtomicDrmSurface { *self.pending.read().unwrap() != *self.state.read().unwrap() } - pub fn commit<'a>(&self, framebuffers: impl Iterator, event: bool) -> Result<(), Error> { + pub fn commit<'a>( + &self, + framebuffers: impl Iterator, + event: bool, + ) -> Result<(), Error> { if !self.active.load(Ordering::SeqCst) { return Err(Error::DeviceInactive); } @@ -538,7 +553,11 @@ impl AtomicDrmSurface { result } - pub fn page_flip<'a>(&self, framebuffers: impl Iterator, event: bool) -> Result<(), Error> { + pub fn page_flip<'a>( + &self, + framebuffers: impl Iterator, + event: bool, + ) -> Result<(), Error> { if !self.active.load(Ordering::SeqCst) { return Err(Error::DeviceInactive); } @@ -618,7 +637,13 @@ impl AtomicDrmSurface { Ok(result) } - pub fn test_plane_buffer(&self, fb: framebuffer::Handle, plane: plane::Handle, position: (i32, i32), size: (u32, u32)) -> Result { + pub fn test_plane_buffer( + &self, + fb: framebuffer::Handle, + plane: plane::Handle, + position: (i32, i32), + size: (u32, u32), + ) -> Result { if !self.active.load(Ordering::SeqCst) { return Err(Error::DeviceInactive); } @@ -726,7 +751,7 @@ impl AtomicDrmSurface { removed_connectors: &mut dyn Iterator, primary: plane::Handle, planes: &[PlaneInfo], - framebuffers: Option>, + framebuffers: Option>, mode: Option, blob: Option>, ) -> Result { @@ -832,7 +857,7 @@ impl AtomicDrmSurface { property::Value::UnsignedRange(mode.size().1 as u64), ); } - + // and finally the others for plane_info in planes { req.add_property( @@ -901,7 +926,8 @@ impl AtomicDrmSurface { property::Value::Framebuffer(None), ); - let result = self.fd + let result = self + .fd .atomic_commit(&[AtomicCommitFlags::Nonblock], req) .map_err(|source| Error::Access { errmsg: "Failed to commit on clear_plane", @@ -910,7 +936,10 @@ impl AtomicDrmSurface { }); if result.is_ok() { - self.additional_planes.lock().unwrap().retain(|info| info.handle != plane); + self.additional_planes + .lock() + .unwrap() + .retain(|info| info.handle != plane); } result @@ -947,11 +976,17 @@ impl Drop for AtomicDrmSurface { // other ttys that use no cursor, might not clear it themselves. // This makes sure our cursor won't stay visible. if let Err(err) = self.clear_plane(self.plane) { - warn!(self.logger, "Failed to clear plane {:?} on {:?}: {}", self.plane, self.crtc, err); + warn!( + self.logger, + "Failed to clear plane {:?} on {:?}: {}", self.plane, self.crtc, err + ); } for plane_info in self.additional_planes.lock().unwrap().iter() { if let Err(err) = self.clear_plane(plane_info.handle) { - warn!(self.logger, "Failed to clear plane {:?} on {:?}: {}", plane_info.handle, self.crtc, err); + warn!( + self.logger, + "Failed to clear plane {:?} on {:?}: {}", plane_info.handle, self.crtc, err + ); } } diff --git a/src/backend/drm/surface/mod.rs b/src/backend/drm/surface/mod.rs index 270fc66..2c47f87 100644 --- a/src/backend/drm/surface/mod.rs +++ b/src/backend/drm/surface/mod.rs @@ -11,12 +11,7 @@ use nix::libc::dev_t; pub(super) mod atomic; pub(super) mod legacy; -use super::{ - error::Error, - Planes, PlaneType, - plane_type, planes, - device::DevPath, -}; +use super::{device::DevPath, error::Error, plane_type, planes, PlaneType, Planes}; use crate::backend::allocator::{Format, Fourcc, Modifier}; use atomic::AtomicDrmSurface; use legacy::LegacyDrmSurface; @@ -150,16 +145,21 @@ impl DrmSurface { /// Tries to setup a cursor or overlay [`Plane`](drm::control::plane) /// to be set at the next commit/page_flip with the given position and size. - /// + /// /// Planes can have arbitrary hardware constraints, that cannot be expressed in the api, /// like supporting only positions at even or odd values, allowing only certain sizes or disallowing overlapping planes. /// Using planes should therefor be done in a best-efford manner. Failures on `page_flip` or `commit` /// should be expected and alternative code paths without the usage of planes prepared. - /// + /// /// Fails if tests for the given plane fail, if the underlying /// implementation does not support the use of planes or if the plane /// is not supported by this crtc. - pub fn use_plane(&self, plane: plane::Handle, position: (i32, i32), size: (u32, u32)) -> Result<(), Error> { + pub fn use_plane( + &self, + plane: plane::Handle, + position: (i32, i32), + size: (u32, u32), + ) -> Result<(), Error> { match &*self.internal { DrmSurfaceInternal::Atomic(surf) => surf.use_plane(plane, position, size), DrmSurfaceInternal::Legacy(_) => Err(Error::NonPrimaryPlane(plane)), @@ -167,7 +167,7 @@ impl DrmSurface { } /// Disables the given plane. - /// + /// /// Errors if the plane is not supported by this crtc or if the underlying /// implementation does not support the use of planes. pub fn clear_plane(&self, plane: plane::Handle) -> Result<(), Error> { @@ -200,17 +200,23 @@ impl DrmSurface { /// but will trigger a `vblank` event once done. /// Make sure to [set a `DeviceHandler`](crate::backend::drm::DrmDevice::set_handler) and /// [register the belonging `Device`](crate::backend::drm::device_bind) before to receive the event in time. - pub fn commit<'a>(&self, mut framebuffers: impl Iterator, event: bool) -> Result<(), Error> { + pub fn commit<'a>( + &self, + mut framebuffers: impl Iterator, + event: bool, + ) -> Result<(), Error> { match &*self.internal { DrmSurfaceInternal::Atomic(surf) => surf.commit(framebuffers, event), - DrmSurfaceInternal::Legacy(surf) => if let Some((fb, plane)) = framebuffers.next() { - if plane_type(self, *plane)? != PlaneType::Primary { - return Err(Error::NonPrimaryPlane(*plane)); + DrmSurfaceInternal::Legacy(surf) => { + if let Some((fb, plane)) = framebuffers.next() { + if plane_type(self, *plane)? != PlaneType::Primary { + return Err(Error::NonPrimaryPlane(*plane)); + } + surf.commit(*fb, event) + } else { + Ok(()) } - surf.commit(*fb, event) - } else { - Ok(()) - }, + } } } @@ -222,17 +228,23 @@ impl DrmSurface { /// This operation is not blocking and will produce a `vblank` event once swapping is done. /// Make sure to [set a `DeviceHandler`](crate::backend::drm::DrmDevice::set_handler) and /// [register the belonging `DrmDevice`](crate::backend::drm::device_bind) before to receive the event in time. - pub fn page_flip<'a>(&self, mut framebuffers: impl Iterator, event: bool) -> Result<(), Error> { + pub fn page_flip<'a>( + &self, + mut framebuffers: impl Iterator, + event: bool, + ) -> Result<(), Error> { match &*self.internal { DrmSurfaceInternal::Atomic(surf) => surf.page_flip(framebuffers, event), - DrmSurfaceInternal::Legacy(surf) => if let Some((fb, plane)) = framebuffers.next() { - if plane_type(self, *plane)? != PlaneType::Primary { - return Err(Error::NonPrimaryPlane(*plane)); + DrmSurfaceInternal::Legacy(surf) => { + if let Some((fb, plane)) = framebuffers.next() { + if plane_type(self, *plane)? != PlaneType::Primary { + return Err(Error::NonPrimaryPlane(*plane)); + } + surf.page_flip(*fb, event) + } else { + Ok(()) } - surf.page_flip(*fb, event) - } else { - Ok(()) - }, + } } } @@ -394,7 +406,7 @@ impl DrmSurface { } // There is no test-commiting with the legacy interface } } - + /// Tests is a framebuffer can be used with this surface and a given plane. /// /// # Arguments @@ -404,7 +416,7 @@ impl DrmSurface { /// (only works for *cursor* and *overlay* planes - for primary planes use `test_buffer`) /// - `position` - The position of the plane /// - `size` - The size of the plane - /// + /// /// If the test cannot be performed, this function returns false. /// This is always the case for non-atomic surfaces. pub fn test_plane_buffer( @@ -416,8 +428,7 @@ impl DrmSurface { ) -> Result { match &*self.internal { DrmSurfaceInternal::Atomic(surf) => surf.test_plane_buffer(fb, plane, position, size), - DrmSurfaceInternal::Legacy(_) => { Ok(false) } - // There is no test-commiting with the legacy interface + DrmSurfaceInternal::Legacy(_) => Ok(false), // There is no test-commiting with the legacy interface } } diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index 4838a8f..0c06c58 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -28,7 +28,7 @@ use crate::backend::egl::{ ffi::egl::{self as ffi_egl, types::EGLImage}, EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError, }; -use crate::{backend::SwapBuffersError}; +use crate::backend::SwapBuffersError; #[cfg(feature = "wayland_frontend")] use crate::{ @@ -534,28 +534,32 @@ impl Gles2Renderer { }; let mut upload_full = false; - + let texture = Gles2Texture( // why not store a `Gles2Texture`? because the user might do so. // this is guaranteed a non-public internal type, so we are good. - surface.user_data.get::>().cloned().unwrap_or_else(|| { - let mut tex = 0; - unsafe { self.gl.GenTextures(1, &mut tex) }; - // new texture, upload in full - upload_full = true; - let texture = Rc::new(Gles2TextureInternal { - texture: tex, - texture_kind: shader_idx, - is_external: false, - y_inverted: false, - width: width as u32, - height: height as u32, - buffer: Some(buffer.clone()), - egl_images: None, - destruction_callback_sender: self.destruction_callback_sender.clone(), - }); - texture - }) + surface + .user_data + .get::>() + .cloned() + .unwrap_or_else(|| { + let mut tex = 0; + unsafe { self.gl.GenTextures(1, &mut tex) }; + // new texture, upload in full + upload_full = true; + let texture = Rc::new(Gles2TextureInternal { + texture: tex, + texture_kind: shader_idx, + is_external: false, + y_inverted: false, + width: width as u32, + height: height as u32, + buffer: Some(buffer.clone()), + egl_images: None, + destruction_callback_sender: self.destruction_callback_sender.clone(), + }); + texture + }), ); unsafe { @@ -566,8 +570,7 @@ impl Gles2Renderer { self.gl .TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32); self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize); - - + if upload_full { trace!(self.logger, "Uploading shm texture for {:?}", buffer); self.gl.TexImage2D( @@ -659,7 +662,10 @@ impl Gles2Renderer { } #[cfg(feature = "wayland_frontend")] - fn existing_dmabuf_texture(&self, buffer: &wl_buffer::WlBuffer) -> Result, Gles2Error> { + fn existing_dmabuf_texture( + &self, + buffer: &wl_buffer::WlBuffer, + ) -> Result, Gles2Error> { let existing_texture = self .dmabuf_cache .iter() @@ -945,10 +951,7 @@ impl Renderer for Gles2Renderer { let texture = if egl.and_then(|egl| egl.egl_buffer_dimensions(&buffer)).is_some() { self.import_egl(&buffer, egl.unwrap()) } else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() { - self.import_shm( - &buffer, - surface, - ) + self.import_shm(&buffer, surface) } else { Err(Gles2Error::UnknownBufferType) }?; @@ -973,12 +976,13 @@ impl Renderer for Gles2Renderer { fn render( &mut self, - width: u32, height: u32, + width: u32, + height: u32, transform: Transform, rendering: F, ) -> Result where - F: FnOnce(&mut Self, &mut Self::Frame) -> R + F: FnOnce(&mut Self, &mut Self::Frame) -> R, { self.make_current()?; // delayed destruction until the next frame rendering. @@ -1016,7 +1020,7 @@ impl Renderer for Gles2Renderer { }; let result = rendering(self, &mut frame); - + unsafe { self.gl.Flush(); // We need to wait for the previously submitted GL commands to complete @@ -1027,7 +1031,7 @@ impl Renderer for Gles2Renderer { // 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 + // 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 diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index 7c20b7d..dabe85b 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -10,11 +10,11 @@ use std::collections::HashSet; use std::error::Error; +#[cfg(feature = "wayland_frontend")] +use crate::wayland::compositor::SurfaceAttributes; use cgmath::{prelude::*, Matrix3, Vector2}; #[cfg(feature = "wayland_frontend")] use wayland_server::protocol::{wl_buffer, wl_shm}; -#[cfg(feature = "wayland_frontend")] -use crate::wayland::compositor::SurfaceAttributes; use crate::{backend::SwapBuffersError, utils::Rectangle}; #[cfg(feature = "renderer_gl")] @@ -108,7 +108,7 @@ impl From for Transform { /// Abstraction for Renderers, that can render into different targets pub trait Bind: Unbind { /// Bind a given rendering target, which will contain the rendering results until `unbind` is called. - /// + /// /// Binding to target, while another one is already bound, is rendering defined. /// Some renderers might happily replace the current target, while other might drop the call /// or throw an error. @@ -199,8 +199,8 @@ pub trait Renderer { type Error: Error; /// Texture Handle type used by this renderer. type TextureId: Texture; - - type Frame: Frame; + + type Frame: Frame; /// Import a given bitmap into the renderer. /// @@ -261,9 +261,8 @@ pub trait Renderer { transform: Transform, rendering: F, ) -> Result - where - F: FnOnce(&mut Self, &mut Self::Frame) -> R - ; + where + F: FnOnce(&mut Self, &mut Self::Frame) -> R; } /// Returns the dimensions of a wl_buffer diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 4a234dd..fef11ea 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -10,10 +10,11 @@ use crate::backend::{ UnusedEvent, }, renderer::{ - gles2::{Gles2Error, Gles2Renderer, Gles2Frame, Gles2Texture}, - Bind, Unbind, Frame, Renderer, Transform, + gles2::{Gles2Error, Gles2Frame, Gles2Renderer, Gles2Texture}, + Bind, Frame, Renderer, Transform, Unbind, }, }; +use crate::utils::Rectangle; use std::{cell::RefCell, rc::Rc, time::Instant}; use wayland_egl as wegl; use wayland_server::Display; @@ -28,7 +29,6 @@ use winit::{ platform::unix::WindowExtUnix, window::{Window as WinitWindow, WindowBuilder}, }; -use crate::utils::Rectangle; #[cfg(feature = "use_system_lib")] use crate::backend::egl::display::EGLBufferReader; @@ -264,7 +264,7 @@ impl WinitGraphicsBackend { /// and this window set as the rendering target. pub fn render(&mut self, rendering: F) -> Result where - F: FnOnce(&mut Gles2Renderer, &mut Gles2Frame) -> R + F: FnOnce(&mut Gles2Renderer, &mut Gles2Frame) -> R, { let (width, height) = { let size = self.size.borrow(); @@ -272,7 +272,9 @@ impl WinitGraphicsBackend { }; self.renderer.bind(self.egl.clone())?; - let result = self.renderer.render(width, height, Transform::Normal, rendering)?; + let result = self + .renderer + .render(width, height, Transform::Normal, rendering)?; self.egl.swap_buffers()?; self.renderer.unbind()?; Ok(result)