diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index 5b1134e..4a71622 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -3,11 +3,9 @@ use std::cell::RefCell; use slog::Logger; -#[cfg(feature = "egl")] -use smithay::backend::{egl::display::EGLBufferReader, renderer::ImportEgl}; use smithay::{ backend::{ - renderer::{buffer_type, BufferType, Frame, ImportDma, ImportShm, Renderer, Texture, Transform}, + renderer::{buffer_type, BufferType, Frame, ImportAll, Renderer, Texture, Transform}, SwapBuffersError, }, reexports::wayland_server::protocol::{wl_buffer, wl_surface}, @@ -18,11 +16,6 @@ use smithay::{ seat::CursorImageRole, }, }; -// hacky... -#[cfg(not(feature = "egl"))] -pub trait ImportEgl {} -#[cfg(not(feature = "egl"))] -impl ImportEgl for T {} use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData}; @@ -43,13 +36,12 @@ pub fn draw_cursor( renderer: &mut R, frame: &mut F, surface: &wl_surface::WlSurface, - #[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>, (x, y): (i32, i32), token: MyCompositorToken, log: &Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer + ImportShm + ImportEgl + ImportDma, + R: Renderer + ImportAll, F: Frame, E: std::error::Error + Into, T: Texture + 'static, @@ -64,29 +56,19 @@ where (0, 0) } }; - draw_surface_tree( - renderer, - frame, - surface, - #[cfg(feature = "egl")] - egl_buffer_reader, - (x - dx, y - dy), - token, - log, - ) + draw_surface_tree(renderer, frame, surface, (x - dx, y - dy), token, log) } fn draw_surface_tree( renderer: &mut R, frame: &mut F, root: &wl_surface::WlSurface, - #[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>, location: (i32, i32), compositor_token: MyCompositorToken, log: &Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer + ImportShm + ImportEgl + ImportDma, + R: Renderer + ImportAll, F: Frame, E: std::error::Error + Into, T: Texture + 'static, @@ -102,54 +84,36 @@ where let mut data = data.borrow_mut(); if data.texture.is_none() { if let Some(buffer) = data.current_state.buffer.take() { - let texture = match buffer_type( - &buffer, - #[cfg(feature = "egl")] - egl_buffer_reader, - ) { - Some(BufferType::Shm) => { - let damage = attributes - .damage - .iter() - .map(|dmg| match dmg { - Damage::Buffer(rect) => *rect, - // TODO also apply transformations - Damage::Surface(rect) => rect.scale(attributes.buffer_scale), - }) - .collect::>(); - let result = renderer.import_shm_buffer(&buffer, Some(&attributes), &damage); - buffer.release(); - // don't return the buffer as it is already released - Some((result, None)) - } - #[cfg(feature = "egl")] - Some(BufferType::Egl) => Some(( - renderer.import_egl_buffer(&buffer, egl_buffer_reader.unwrap()), - Some(buffer), - )), - Some(BufferType::Dma) => { - Some((renderer.import_dma_buffer(&buffer), Some(buffer))) - } - _ => { - error!(log, "Unknown buffer format for: {:?}", buffer); - buffer.release(); - None - } - }; - match texture { - Some((Ok(m), buffer)) => { - data.texture = Some(Box::new(BufferTextures { buffer, texture: m }) - as Box) - } - // there was an error reading the buffer, release it. - Some((Err(err), buffer)) => { - warn!(log, "Error loading buffer: {:?}", err); - if let Some(buffer) = buffer { + let damage = attributes + .damage + .iter() + .map(|dmg| match dmg { + Damage::Buffer(rect) => *rect, + // TODO also apply transformations + Damage::Surface(rect) => rect.scale(attributes.buffer_scale), + }) + .collect::>(); + + match renderer.import_buffer(&buffer, Some(&attributes), &damage) { + Some(Ok(m)) => { + if let Some(BufferType::Shm) = buffer_type(&buffer) { buffer.release(); } + data.texture = Some(Box::new(BufferTextures { + buffer: Some(buffer), + texture: m, + }) + as Box) } - None => {} - }; + Some(Err(err)) => { + warn!(log, "Error loading buffer: {:?}", err); + buffer.release(); + } + None => { + error!(log, "Unknown buffer format for: {:?}", buffer); + buffer.release(); + } + } } } // Now, should we be drawn ? @@ -204,14 +168,13 @@ where pub fn draw_windows( renderer: &mut R, frame: &mut F, - #[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>, window_map: &MyWindowMap, output_rect: Option, compositor_token: MyCompositorToken, log: &::slog::Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer + ImportShm + ImportEgl + ImportDma, + R: Renderer + ImportAll, F: Frame, E: std::error::Error + Into, T: Texture + 'static, @@ -229,16 +192,9 @@ where } if let Some(wl_surface) = toplevel_surface.get_surface() { // 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, - #[cfg(feature = "egl")] - egl_buffer_reader, - initial_place, - compositor_token, - log, - ) { + if let Err(err) = + draw_surface_tree(renderer, frame, &wl_surface, initial_place, compositor_token, log) + { result = Err(err); } } @@ -251,13 +207,12 @@ pub fn draw_dnd_icon( renderer: &mut R, frame: &mut F, surface: &wl_surface::WlSurface, - #[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>, (x, y): (i32, i32), token: MyCompositorToken, log: &::slog::Logger, ) -> Result<(), SwapBuffersError> where - R: Renderer + ImportShm + ImportEgl + ImportDma, + R: Renderer + ImportAll, F: Frame, E: std::error::Error + Into, T: Texture + 'static, @@ -268,14 +223,5 @@ where "Trying to display as a dnd icon a surface that does not have the DndIcon role." ); } - draw_surface_tree( - renderer, - frame, - surface, - #[cfg(feature = "egl")] - egl_buffer_reader, - (x, y), - token, - log, - ) + draw_surface_tree(renderer, frame, surface, (x, y), token, log) } diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 3899537..c433155 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -4,8 +4,6 @@ use std::{ sync::{Arc, Mutex}, }; -#[cfg(feature = "egl")] -use smithay::backend::egl::display::EGLBufferReader; use smithay::{ backend::renderer::buffer_dimensions, reexports::{ @@ -324,22 +322,15 @@ pub struct ShellHandles { pub window_map: Rc>, } -pub fn init_shell(display: &mut Display, log: ::slog::Logger) -> ShellHandles { +pub fn init_shell(display: &mut Display, log: ::slog::Logger) -> ShellHandles { // Create the compositor let (compositor_token, _, _) = compositor_init( display, move |request, surface, ctoken, mut ddata| match request { SurfaceEvent::Commit => { - let anvil_state = ddata.get::>().unwrap(); + let anvil_state = ddata.get::>().unwrap(); let window_map = anvil_state.window_map.as_ref(); - #[cfg(feature = "egl")] - { - surface_commit(&surface, ctoken, anvil_state.egl_reader.as_ref(), &*window_map) - } - #[cfg(not(feature = "egl"))] - { - surface_commit(&surface, ctoken, &*window_map) - } + surface_commit(&surface, ctoken, &*window_map) } }, log.clone(), @@ -850,7 +841,6 @@ impl SurfaceData { fn surface_commit( surface: &wl_surface::WlSurface, token: CompositorToken, - #[cfg(feature = "egl")] egl_reader: Option<&EGLBufferReader>, window_map: &RefCell, ) { #[cfg(feature = "xwayland")] @@ -924,14 +914,7 @@ fn surface_commit( match attributes.buffer.take() { Some(BufferAssignment::NewBuffer { buffer, .. }) => { // new contents - #[cfg(feature = "egl")] - { - next_state.dimensions = buffer_dimensions(&buffer, egl_reader); - } - #[cfg(not(feature = "egl"))] - { - next_state.dimensions = buffer_dimensions(&buffer); - } + next_state.dimensions = buffer_dimensions(&buffer); next_state.buffer = Some(buffer); } Some(BufferAssignment::Removed) => { diff --git a/anvil/src/state.rs b/anvil/src/state.rs index 29394e0..031efa5 100644 --- a/anvil/src/state.rs +++ b/anvil/src/state.rs @@ -20,8 +20,6 @@ use smithay::{ }, }; -#[cfg(feature = "egl")] -use smithay::backend::egl::display::EGLBufferReader; #[cfg(feature = "xwayland")] use smithay::xwayland::{XWayland, XWaylandEvent}; @@ -45,8 +43,7 @@ pub struct AnvilState { pub cursor_status: Arc>, pub seat_name: String, pub start_time: std::time::Instant, - #[cfg(feature = "egl")] - pub egl_reader: Option, + // things we must keep alive #[cfg(feature = "xwayland")] pub xwayland: XWayland>, } @@ -56,7 +53,6 @@ impl AnvilState { display: Rc>, handle: LoopHandle<'static, AnvilState>, backend_data: BackendData, - #[cfg(feature = "egl")] egl_reader: Option, log: slog::Logger, ) -> AnvilState { // init the wayland connection @@ -170,8 +166,6 @@ impl AnvilState { cursor_status, pointer_location: (0.0, 0.0), seat_name, - #[cfg(feature = "egl")] - egl_reader, start_time: std::time::Instant::now(), #[cfg(feature = "xwayland")] xwayland, diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index c2325ee..1af0f0d 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -58,7 +58,11 @@ use smithay::{ }; #[cfg(feature = "egl")] use smithay::{ - backend::{drm::DevPath, egl::display::EGLBufferReader, renderer::ImportDma, udev::primary_gpu}, + backend::{ + drm::DevPath, + renderer::{ImportDma, ImportEgl}, + udev::primary_gpu, + }, wayland::dmabuf::init_dmabuf_global, }; @@ -130,14 +134,7 @@ pub fn run_udev( pointer_image: ImageBuffer::from_raw(64, 64, pointer_bytes.to_vec()).unwrap(), render_timer: timer.handle(), }; - let mut state = AnvilState::init( - display.clone(), - event_loop.handle(), - data, - #[cfg(feature = "egl")] - None, - log.clone(), - ); + let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone()); // re-render timer event_loop @@ -460,17 +457,6 @@ impl AnvilState { } }; - #[cfg(feature = "egl")] - let is_primary = path.canonicalize().ok() == self.backend_data.primary_gpu; - // init hardware acceleration on the primary gpu. - #[cfg(feature = "egl")] - { - if is_primary { - info!(self.log, "Initializing EGL Hardware Acceleration via {:?}", path); - self.egl_reader = egl.bind_wl_display(&*self.display.borrow()).ok(); - } - } - let context = match EGLContext::new(&egl, self.log.clone()) { Ok(context) => context, Err(err) => { @@ -486,6 +472,15 @@ impl AnvilState { Gles2Renderer::new(context, self.log.clone()).unwrap() })); + #[cfg(feature = "egl")] + if path.canonicalize().ok() == self.backend_data.primary_gpu { + info!(self.log, "Initializing EGL Hardware Acceleration via {:?}", path); + renderer + .borrow_mut() + .bind_wl_display(&*self.display.borrow()) + .expect("Unable to bind Wl Display?"); + } + let backends = Rc::new(RefCell::new(scan_connectors( &mut device, &gbm, @@ -597,12 +592,8 @@ impl AnvilState { // don't use hardware acceleration anymore, if this was the primary gpu #[cfg(feature = "egl")] - { - if _device.dev_path().and_then(|path| path.canonicalize().ok()) - == self.backend_data.primary_gpu - { - self.egl_reader = None; - } + if _device.dev_path().and_then(|path| path.canonicalize().ok()) == self.backend_data.primary_gpu { + backend_data.renderer.borrow_mut().unbind_wl_display(); } debug!(self.log, "Dropping device"); } @@ -637,8 +628,6 @@ impl AnvilState { let result = render_surface( &mut *surface.borrow_mut(), &mut *device_backend.renderer.borrow_mut(), - #[cfg(feature = "egl")] - self.egl_reader.as_ref(), device_backend.dev_id, crtc, &mut *self.window_map.borrow_mut(), @@ -687,7 +676,6 @@ impl AnvilState { fn render_surface( surface: &mut RenderSurface, renderer: &mut Gles2Renderer, - #[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>, device_id: dev_t, crtc: crtc::Handle, window_map: &mut MyWindowMap, @@ -726,8 +714,6 @@ fn render_surface( draw_windows( renderer, frame, - #[cfg(feature = "egl")] - egl_buffer_reader, window_map, Some(Rectangle { x: x as i32, @@ -754,8 +740,6 @@ fn render_surface( renderer, frame, wl_surface, - #[cfg(feature = "egl")] - egl_buffer_reader, (ptr_x, ptr_y), *compositor_token, logger, @@ -779,8 +763,6 @@ fn render_surface( renderer, frame, wl_surface, - #[cfg(feature = "egl")] - egl_buffer_reader, (ptr_x, ptr_y), *compositor_token, logger, diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 02f4b14..7a9ab18 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -38,9 +38,7 @@ pub fn run_winit( let renderer = Rc::new(RefCell::new(renderer)); #[cfg(feature = "egl")] - let reader = renderer.borrow().bind_wl_display(&display.borrow()).ok(); - #[cfg(feature = "egl")] - if reader.is_some() { + if renderer.borrow().bind_wl_display(&display.borrow()).is_ok() { info!(log, "EGL hardware-acceleration enabled"); let dmabuf_formats = renderer .borrow_mut() @@ -67,8 +65,6 @@ pub fn run_winit( display.clone(), event_loop.handle(), WinitData, - #[cfg(feature = "egl")] - reader, log.clone(), ); @@ -129,8 +125,6 @@ pub fn run_winit( draw_windows( renderer, frame, - #[cfg(feature = "egl")] - state.egl_reader.as_ref(), &*state.window_map.borrow(), None, state.ctoken, @@ -147,8 +141,6 @@ pub fn run_winit( renderer, frame, surface, - #[cfg(feature = "egl")] - state.egl_reader.as_ref(), (x as i32, y as i32), state.ctoken, &log, @@ -171,16 +163,7 @@ pub fn run_winit( // draw as relevant if let CursorImageStatus::Image(ref surface) = *guard { cursor_visible = false; - draw_cursor( - renderer, - frame, - surface, - #[cfg(feature = "egl")] - state.egl_reader.as_ref(), - (x as i32, y as i32), - state.ctoken, - &log, - )?; + draw_cursor(renderer, frame, surface, (x as i32, y as i32), state.ctoken, &log)?; } else { cursor_visible = true; } diff --git a/src/backend/egl/display.rs b/src/backend/egl/display.rs index d2cde13..af13b8f 100644 --- a/src/backend/egl/display.rs +++ b/src/backend/egl/display.rs @@ -5,6 +5,8 @@ use std::ffi::CStr; use std::mem::MaybeUninit; use std::ops::Deref; use std::sync::Arc; +#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] +use std::sync::{Mutex, Weak}; use libc::c_void; use nix::libc::c_int; @@ -24,6 +26,11 @@ use crate::backend::egl::{ #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] use crate::backend::egl::{BufferAccessError, EGLBuffer, Format}; +#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] +lazy_static! { + pub(crate) static ref BUFFER_READER: Mutex> = Mutex::new(None); +} + /// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed /// once all resources bound to it have been dropped. #[derive(Debug)] @@ -535,7 +542,18 @@ impl EGLDisplay { ffi::egl::BindWaylandDisplayWL(**self.display, display.c_ptr() as *mut _) }) .map_err(Error::OtherEGLDisplayAlreadyBound)?; - Ok(EGLBufferReader::new(self.display.clone(), display.c_ptr())) + let reader = EGLBufferReader::new(self.display.clone(), display.c_ptr()); + let mut global = BUFFER_READER.lock().unwrap(); + if global.as_ref().and_then(|x| x.upgrade()).is_some() { + warn!( + self.logger, + "Double bind_wl_display, smithay does not support this, please report" + ); + } + *global = Some(WeakBufferReader { + display: Arc::downgrade(&self.display), + }); + Ok(reader) } } @@ -663,6 +681,24 @@ pub struct EGLBufferReader { wayland: Option>, } +#[cfg(feature = "use_system_lib")] +pub(crate) struct WeakBufferReader { + display: Weak, +} + +#[cfg(feature = "use_system_lib")] +impl WeakBufferReader { + pub fn upgrade(&self) -> Option { + Some(EGLBufferReader { + display: self.display.upgrade()?, + wayland: None, + }) + } +} + +#[cfg(feature = "use_system_lib")] +unsafe impl Send for EGLBufferReader {} + #[cfg(feature = "use_system_lib")] impl EGLBufferReader { fn new(display: Arc, wayland: *mut wl_display) -> Self { @@ -825,7 +861,7 @@ impl EGLBufferReader { #[cfg(feature = "use_system_lib")] impl Drop for EGLBufferReader { fn drop(&mut self) { - if let Ok(wayland) = Arc::try_unwrap(self.wayland.take().unwrap()) { + if let Some(wayland) = self.wayland.take().and_then(|x| Arc::try_unwrap(x).ok()) { if !wayland.is_null() { unsafe { // ignore errors on drop diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index 491f2d4..b82a55f 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -152,6 +152,8 @@ pub struct Gles2Renderer { #[cfg(feature = "wayland_frontend")] dmabuf_cache: HashMap, egl: EGLContext, + #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] + egl_reader: Option, gl: ffi::Gles2, destruction_callback: Receiver, destruction_callback_sender: Sender, @@ -446,6 +448,8 @@ impl Gles2Renderer { id: RENDERER_COUNTER.fetch_add(1, Ordering::SeqCst), gl, egl: context, + #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] + egl_reader: None, extensions: exts, programs, target_buffer: None, @@ -619,15 +623,33 @@ impl ImportShm for Gles2Renderer { feature = "use_system_lib" ))] impl ImportEgl for Gles2Renderer { - fn import_egl_buffer( + fn bind_wl_display( &mut self, - buffer: &wl_buffer::WlBuffer, - reader: &EGLBufferReader, - ) -> Result { + display: &wayland_server::Display, + ) -> Result<(), crate::backend::egl::Error> { + self.egl_reader = Some(self.egl.display.bind_wl_display(display)?); + Ok(()) + } + + fn unbind_wl_display(&mut self) { + self.egl_reader = None; + } + + fn egl_reader(&self) -> Option<&EGLBufferReader> { + self.egl_reader.as_ref() + } + + fn import_egl_buffer(&mut self, buffer: &wl_buffer::WlBuffer) -> Result { if !self.extensions.iter().any(|ext| ext == "GL_OES_EGL_image") { return Err(Gles2Error::GLExtensionNotSupported(&["GL_OES_EGL_image"])); } + if self.egl_reader().is_none() { + return Err(Gles2Error::EGLBufferAccessError( + crate::backend::egl::BufferAccessError::NotManaged(crate::backend::egl::EGLError::BadDisplay), + )); + } + // We can not use the caching logic for textures here as the // egl buffers a potentially managed external which will fail the // clean up check if the buffer is still alive. For wl_drm the @@ -635,7 +657,10 @@ impl ImportEgl for Gles2Renderer { // will never be cleaned up. self.make_current()?; - let egl = reader + let egl = self + .egl_reader + .as_ref() + .unwrap() .egl_buffer_contents(&buffer) .map_err(Gles2Error::EGLBufferAccessError)?; @@ -905,6 +930,8 @@ impl Drop for Gles2Renderer { let _ = Box::from_raw(logger_ptr); } + #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] + let _ = self.egl_reader.take(); let _ = self.egl.unbind(); } } diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index e8ac8d0..a90a609 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -25,7 +25,10 @@ use crate::backend::allocator::{dmabuf::Dmabuf, Format}; feature = "backend_egl", feature = "use_system_lib" ))] -use crate::backend::egl::display::EGLBufferReader; +use crate::backend::egl::{ + display::{EGLBufferReader, BUFFER_READER}, + Error as EglError, +}; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] /// Possible transformations to two-dimensional planes @@ -281,6 +284,34 @@ pub trait ImportShm: Renderer { ))] /// Trait for Renderers supporting importing wl_drm-based buffers. pub trait ImportEgl: Renderer { + /// Binds the underlying EGL display to the given Wayland display. + /// + /// This will allow clients to utilize EGL to create hardware-accelerated + /// surfaces. This renderer will thus be able to handle wl_drm-based buffers. + /// + /// ## Errors + /// + /// This might return [`EglExtensionNotSupported`](Error::EglExtensionNotSupported) + /// if binding is not supported by the EGL implementation. + /// + /// This might return [`OtherEGLDisplayAlreadyBound`](Error::OtherEGLDisplayAlreadyBound) + /// if called for the same [`Display`] multiple times, as only one egl display may be bound at any given time. + fn bind_wl_display(&mut self, display: &wayland_server::Display) -> Result<(), EglError>; + + /// Unbinds a previously bound egl display, if existing. + /// + /// *Note*: As a result any previously created egl-based WlBuffers will not be readable anymore. + /// Your compositor will have to deal with existing buffers of *unknown* type. + fn unbind_wl_display(&mut self); + + /// Returns the underlying [`EGLBufferReader`]. + /// + /// The primary use for this is calling [`buffer_dimensions`] or [`buffer_type`]. + /// + /// Returns `None` if no [`Display`] was previously bound to the underlying [`EGLDisplay`] + /// (see [`ImportEgl::bind_wl_display`]). + fn egl_reader(&self) -> Option<&EGLBufferReader>; + /// Import a given wl_drm-based buffer into the renderer (see [`buffer_type`]). /// /// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`]) @@ -295,7 +326,6 @@ pub trait ImportEgl: Renderer { fn import_egl_buffer( &mut self, buffer: &wl_buffer::WlBuffer, - egl: &EGLBufferReader, ) -> Result<::TextureId, ::Error>; } @@ -351,12 +381,8 @@ pub trait ImportDma: Renderer { // pub type ImportAll = Renderer + ImportShm + ImportEgl; /// Common trait for renderers of any wayland buffer type -#[cfg(all( - feature = "wayland_frontend", - feature = "backend_egl", - feature = "use_system_lib" -))] -pub trait ImportAll: Renderer + ImportShm + ImportEgl { +#[cfg(feature = "wayland_frontend")] +pub trait ImportAll: Renderer { /// Import a given buffer into the renderer. /// /// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`]) @@ -380,21 +406,49 @@ pub trait ImportAll: Renderer + ImportShm + ImportEgl { buffer: &wl_buffer::WlBuffer, surface: Option<&SurfaceAttributes>, damage: &[Rectangle], - egl: Option<&EGLBufferReader>, - ) -> Option::TextureId, ::Error>> { - match buffer_type(buffer, egl) { - Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)), - Some(BufferType::Egl) => Some(self.import_egl_buffer(buffer, egl.unwrap())), - _ => None, - } - } + ) -> Option::TextureId, ::Error>>; } + +// TODO: Do this with specialization, when possible and do default implementations #[cfg(all( feature = "wayland_frontend", feature = "backend_egl", feature = "use_system_lib" ))] -impl ImportAll for R {} +impl ImportAll for R { + fn import_buffer( + &mut self, + buffer: &wl_buffer::WlBuffer, + surface: Option<&SurfaceAttributes>, + damage: &[Rectangle], + ) -> Option::TextureId, ::Error>> { + match buffer_type(buffer) { + Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)), + Some(BufferType::Egl) => Some(self.import_egl_buffer(buffer)), + Some(BufferType::Dma) => Some(self.import_dma_buffer(buffer)), + _ => None, + } + } +} + +#[cfg(all( + feature = "wayland_frontend", + not(all(feature = "backend_egl", feature = "use_system_lib")) +))] +impl ImportAll for R { + fn import_buffer( + &mut self, + buffer: &wl_buffer::WlBuffer, + surface: Option<&SurfaceAttributes>, + damage: &[Rectangle], + ) -> Option::TextureId, ::Error>> { + match buffer_type(buffer) { + Some(BufferType::Shm) => Some(self.import_shm_buffer(buffer, surface, damage)), + Some(BufferType::Dma) => Some(self.import_dma_buffer(buffer)), + _ => None, + } + } +} #[cfg(feature = "wayland_frontend")] #[non_exhaustive] @@ -413,94 +467,58 @@ pub enum BufferType { /// /// Returns `None` if the type is not known to smithay /// or otherwise not supported (e.g. not initialized using one of smithays [`crate::wayland`]-handlers). -#[cfg(all( - feature = "wayland_frontend", - feature = "backend_egl", - feature = "use_system_lib" -))] -pub fn buffer_type( - buffer: &wl_buffer::WlBuffer, - egl_buffer_reader: Option<&EGLBufferReader>, -) -> Option { +#[cfg(feature = "wayland_frontend")] +pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option { if buffer.as_ref().user_data().get::().is_some() { - Some(BufferType::Dma) - } else if egl_buffer_reader + return Some(BufferType::Dma); + } + + #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))] + if BUFFER_READER + .lock() + .unwrap() .as_ref() + .and_then(|x| x.upgrade()) .and_then(|x| x.egl_buffer_dimensions(&buffer)) .is_some() { - Some(BufferType::Egl) - } else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() { - Some(BufferType::Shm) - } else { - None + return Some(BufferType::Egl); } -} -/// Returns the *type* of a wl_buffer -/// -/// Returns `None` if the type is not recognized by smithay or otherwise not supported. -#[cfg(all( - feature = "wayland_frontend", - not(all(feature = "backend_egl", feature = "use_system_lib")) -))] -pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option { - if buffer.as_ref().user_data().get::().is_some() { - Some(BufferType::Dma) - } else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() { - Some(BufferType::Shm) - } else { - None + if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() { + return Some(BufferType::Shm); } + + None } /// Returns the dimensions of a wl_buffer /// /// *Note*: This will only return dimensions for buffer types known to smithay (see [`buffer_type`]) -#[cfg(all( - feature = "wayland_frontend", - feature = "backend_egl", - feature = "use_system_lib" -))] -pub fn buffer_dimensions( - buffer: &wl_buffer::WlBuffer, - egl_buffer_reader: Option<&EGLBufferReader>, -) -> Option<(i32, i32)> { - use crate::backend::allocator::Buffer; - - if let Some(buf) = buffer.as_ref().user_data().get::() { - Some((buf.width() as i32, buf.height() as i32)) - } else if let Some((w, h)) = egl_buffer_reader - .as_ref() - .and_then(|x| x.egl_buffer_dimensions(&buffer)) - { - Some((w, h)) - } else if let Ok((w, h)) = - crate::wayland::shm::with_buffer_contents(&buffer, |_, data| (data.width, data.height)) - { - Some((w, h)) - } else { - None - } -} - -/// Returns the dimensions of a wl_buffer -/// -/// *Note*: This will only return dimensions for buffer types known to smithay (see [`buffer_type`]) -#[cfg(all( - feature = "wayland_frontend", - not(all(feature = "backend_egl", feature = "use_system_lib")) -))] +#[cfg(feature = "wayland_frontend")] pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option<(i32, i32)> { use crate::backend::allocator::Buffer; if let Some(buf) = buffer.as_ref().user_data().get::() { - Some((buf.width() as i32, buf.height() as i32)) - } else if let Ok((w, h)) = + return Some((buf.width() as i32, buf.height() as i32)); + } + + #[cfg(all(feature = "backend_egl", feature = "use_system_lib"))] + if let Some((w, h)) = BUFFER_READER + .lock() + .unwrap() + .as_ref() + .and_then(|x| x.upgrade()) + .and_then(|x| x.egl_buffer_dimensions(&buffer)) + { + return Some((w, h)); + } + + if let Ok((w, h)) = crate::wayland::shm::with_buffer_contents(&buffer, |_, data| (data.width, data.height)) { - Some((w, h)) - } else { - None + return Some((w, h)); } + + None }