From c9e67cdfef63fdfe451dfdf21dc5b8327367a60b Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:19:40 +0100 Subject: [PATCH 01/56] Move egl module - Remove gbm code - rename EGLWaylandExtensions to EGLGraphicsBackend - remove OpenGL specific code where possible --- src/backend/{graphics => }/egl/context.rs | 77 +++------ src/backend/{graphics => }/egl/error.rs | 0 src/backend/{graphics => }/egl/ffi.rs | 5 - .../{graphics/egl/wayland.rs => egl/mod.rs} | 135 ++++++++++++--- src/backend/{graphics => }/egl/native.rs | 102 ++---------- src/backend/{graphics => }/egl/surface.rs | 25 +-- src/backend/graphics/egl/mod.rs | 155 ------------------ 7 files changed, 161 insertions(+), 338 deletions(-) rename src/backend/{graphics => }/egl/context.rs (91%) rename src/backend/{graphics => }/egl/error.rs (100%) rename src/backend/{graphics => }/egl/ffi.rs (97%) rename src/backend/{graphics/egl/wayland.rs => egl/mod.rs} (76%) rename src/backend/{graphics => }/egl/native.rs (64%) rename src/backend/{graphics => }/egl/surface.rs (83%) delete mode 100644 src/backend/graphics/egl/mod.rs diff --git a/src/backend/graphics/egl/context.rs b/src/backend/egl/context.rs similarity index 91% rename from src/backend/graphics/egl/context.rs rename to src/backend/egl/context.rs index 4c8f1f8..4c64afc 100644 --- a/src/backend/graphics/egl/context.rs +++ b/src/backend/egl/context.rs @@ -1,16 +1,9 @@ //! EGL context related structs -use super::{error::*, ffi, native, EGLSurface, PixelFormat}; -#[cfg(feature = "backend_drm")] -use drm::control::Device as ControlDevice; -#[cfg(feature = "backend_drm")] -use drm::Device as BasicDevice; -#[cfg(feature = "backend_drm")] -use gbm::Device as GbmDevice; +use super::{error::*, ffi, native, EGLSurface}; +use backend::graphics::gl::PixelFormat; use nix::libc::{c_int, c_void}; use slog; -#[cfg(feature = "backend_drm")] -use std::os::unix::io::{AsRawFd, RawFd}; use std::{ ffi::{CStr, CString}, marker::PhantomData, @@ -29,7 +22,6 @@ pub struct EGLContext> { pub(crate) surface_attributes: Vec, pixel_format: PixelFormat, pub(crate) wl_drm_support: bool, - pub(crate) egl_to_texture_support: bool, logger: slog::Logger, _backend: PhantomData, } @@ -67,7 +59,6 @@ impl> EGLContext { surface_attributes, pixel_format, wl_drm_support, - egl_to_texture_support, ) = unsafe { EGLContext::::new_internal(ptr, attributes, reqs, log.clone()) }?; Ok(EGLContext { @@ -78,7 +69,6 @@ impl> EGLContext { surface_attributes, pixel_format, wl_drm_support, - egl_to_texture_support, logger: log, _backend: PhantomData, }) @@ -96,7 +86,6 @@ impl> EGLContext { Vec, PixelFormat, bool, - bool, )> { // If no version is given, try OpenGLES 3.0, if available, // fallback to 2.0 otherwise @@ -128,14 +117,15 @@ impl> EGLContext { bail!(ErrorKind::OpenGlVersionNotSupported(version)); } }; - + + fn constrain(f: F) -> F + where + F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void, + { + f + }; + ffi::egl::LOAD.call_once(|| { - fn constrain(f: F) -> F - where - F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void, - { - f - }; ffi::egl::load_with(|sym| { let name = CString::new(sym).unwrap(); let symbol = ffi::egl::LIB.get::<*mut c_void>(name.as_bytes()); @@ -153,9 +143,8 @@ impl> EGLContext { ffi::egl::BindWaylandDisplayWL::load_with(&proc_address); ffi::egl::UnbindWaylandDisplayWL::load_with(&proc_address); ffi::egl::QueryWaylandBufferWL::load_with(&proc_address); - ffi::gl::load_with(&proc_address); }); - + // the first step is to query the list of extensions without any display, if supported let dp_extensions = { let p = ffi::egl::QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32); @@ -435,17 +424,6 @@ impl> EGLContext { // make current and get list of gl extensions ffi::egl::MakeCurrent(display as *const _, ptr::null(), ptr::null(), context as *const _); - // the list of gl extensions supported by the context - let gl_extensions = { - let data = CStr::from_ptr(ffi::gl::GetString(ffi::gl::EXTENSIONS) as *const _) - .to_bytes() - .to_vec(); - let list = String::from_utf8(data).unwrap(); - list.split(' ').map(|e| e.to_string()).collect::>() - }; - - info!(log, "GL Extensions: {:?}", gl_extensions); - Ok(( Rc::new(context as *const _), Rc::new(display as *const _), @@ -453,25 +431,22 @@ impl> EGLContext { surface_attributes, desc, extensions.iter().any(|s| *s == "EGL_WL_bind_wayland_display"), - gl_extensions - .iter() - .any(|s| *s == "GL_OES_EGL_image" || *s == "GL_OES_EGL_image_base"), )) } /// Creates a surface for rendering - pub fn create_surface(&self, args: N::Arguments) -> Result> { + pub fn create_surface(&mut self, args: N::Arguments) -> Result> { trace!(self.logger, "Creating EGL window surface."); - let res = EGLSurface::new( - self, - self.native + let surface = self.native .create_surface(args) - .chain_err(|| ErrorKind::SurfaceCreationFailed)?, - ); - if res.is_ok() { + .chain_err(|| ErrorKind::SurfaceCreationFailed)?; + EGLSurface::new( + self, + surface, + ).map(|x| { debug!(self.logger, "EGL surface successfully created"); - } - res + x + }) } /// Returns the address of an OpenGL function. @@ -508,18 +483,6 @@ impl> Drop for EGLContext } } -#[cfg(feature = "backend_drm")] -impl AsRawFd for EGLContext, GbmDevice> { - fn as_raw_fd(&self) -> RawFd { - self.native.as_raw_fd() - } -} - -#[cfg(feature = "backend_drm")] -impl BasicDevice for EGLContext, GbmDevice> {} -#[cfg(feature = "backend_drm")] -impl ControlDevice for EGLContext, GbmDevice> {} - /// Attributes to use when creating an OpenGL context. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct GlAttributes { diff --git a/src/backend/graphics/egl/error.rs b/src/backend/egl/error.rs similarity index 100% rename from src/backend/graphics/egl/error.rs rename to src/backend/egl/error.rs diff --git a/src/backend/graphics/egl/ffi.rs b/src/backend/egl/ffi.rs similarity index 97% rename from src/backend/graphics/egl/ffi.rs rename to src/backend/egl/ffi.rs index f5ace9f..b43d1fe 100644 --- a/src/backend/graphics/egl/ffi.rs +++ b/src/backend/egl/ffi.rs @@ -13,11 +13,6 @@ pub type NativeDisplayType = *const c_void; pub type NativePixmapType = *const c_void; pub type NativeWindowType = *const c_void; -#[cfg_attr(feature = "cargo-clippy", allow(clippy))] -pub mod gl { - include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); -} - #[cfg_attr(feature = "cargo-clippy", allow(clippy))] pub mod egl { use super::*; diff --git a/src/backend/graphics/egl/wayland.rs b/src/backend/egl/mod.rs similarity index 76% rename from src/backend/graphics/egl/wayland.rs rename to src/backend/egl/mod.rs index 53dcb46..9335b7c 100644 --- a/src/backend/graphics/egl/wayland.rs +++ b/src/backend/egl/mod.rs @@ -1,3 +1,10 @@ +//! Common traits and types for egl rendering +//! +//! Large parts of this module are taken from +//! https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/src/api/egl/ +//! +//! It therefore falls under glutin's Apache 2.0 license +//! (see https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/LICENSE) //! Wayland specific EGL functionality - EGL based `WlBuffer`s. //! //! The types of this module can be used to initialize hardware acceleration rendering @@ -10,13 +17,11 @@ //! You may then use the resulting `EGLDisplay` to receive `EGLImages` of an EGL-based `WlBuffer` //! for rendering. -use backend::graphics::egl::{ - error::*, - ffi::{self, egl::types::EGLImage}, - native, EGLContext, EglExtensionNotSupportedError, -}; +#[cfg(feature = "renderer_gl")] +use backend::graphics::gl::ffi as gl_ffi; use nix::libc::c_uint; use std::{ + ffi::CStr, fmt, rc::{Rc, Weak}, }; @@ -26,6 +31,49 @@ use wayland_server::{ }; use wayland_sys::server::wl_display; +pub mod context; +pub use self::context::EGLContext; +pub mod error; +use self::error::*; + +#[allow( + non_camel_case_types, + dead_code, + unused_mut, + non_upper_case_globals +)] +pub mod ffi; +use self::ffi::egl::types::EGLImage; + +pub mod native; +pub mod surface; +pub use self::surface::EGLSurface; + +/// Error that can happen on optional EGL features +#[derive(Debug, Clone, PartialEq)] +pub struct EglExtensionNotSupportedError(&'static [&'static str]); + +impl fmt::Display for EglExtensionNotSupportedError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> { + write!( + formatter, + "None of the following EGL extensions is supported by the underlying EGL implementation, + at least one is required: {:?}", + self.0 + ) + } +} + +impl ::std::error::Error for EglExtensionNotSupportedError { + fn description(&self) -> &str { + "The required EGL extension is not supported by the underlying EGL implementation" + } + + fn cause(&self) -> Option<&::std::error::Error> { + None + } +} + /// Error that can occur when accessing an EGL buffer pub enum BufferAccessError { /// The corresponding Context is not alive anymore @@ -104,6 +152,8 @@ pub enum TextureCreationError { /// application on sleep and wakes it up later. However any OpenGL implementation /// can theoretically lose the context at any time. ContextLost, + /// Required OpenGL Extension for texture creation is missing + GLExtensionNotSupported(&'static str), /// Failed to bind the `EGLImage` to the given texture /// /// The given argument is the GL error code @@ -116,6 +166,9 @@ impl fmt::Display for TextureCreationError { match *self { TextureCreationError::ContextLost => write!(formatter, "{}", self.description()), TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()), + TextureCreationError::GLExtensionNotSupported(ext) => { + write!(formatter, "{}: {:}", self.description(), ext) + } TextureCreationError::TextureBindingFailed(code) => { write!(formatter, "{}. Gl error code: {:?}", self.description(), code) } @@ -128,6 +181,7 @@ impl ::std::error::Error for TextureCreationError { match *self { TextureCreationError::ContextLost => "The context has been lost, it needs to be recreated", TextureCreationError::PlaneIndexOutOfBounds => "This buffer is not managed by EGL", + TextureCreationError::GLExtensionNotSupported(_) => "Required OpenGL Extension for texture creation is missing", TextureCreationError::TextureBindingFailed(_) => "Failed to create EGLImages from the buffer", } } @@ -180,6 +234,10 @@ pub struct EGLImages { pub format: Format, images: Vec, buffer: Resource, + #[cfg(feature = "renderer_gl")] + gl: gl_ffi::Gles2, + #[cfg(feature = "renderer_gl")] + egl_to_texture_support: bool, } impl EGLImages { @@ -195,17 +253,22 @@ impl EGLImages { /// # Unsafety /// /// The given `tex_id` needs to be a valid GL texture otherwise undefined behavior might occur. + #[cfg(feature = "renderer_gl")] pub unsafe fn bind_to_texture( &self, plane: usize, tex_id: c_uint, ) -> ::std::result::Result<(), TextureCreationError> { if self.display.upgrade().is_some() { + if !self.egl_to_texture_support { + return Err(TextureCreationError::GLExtensionNotSupported("GL_OES_EGL_image")); + } + let mut old_tex_id: i32 = 0; - ffi::gl::GetIntegerv(ffi::gl::TEXTURE_BINDING_2D, &mut old_tex_id); - ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id); - ffi::gl::EGLImageTargetTexture2DOES( - ffi::gl::TEXTURE_2D, + self.gl.GetIntegerv(gl_ffi::TEXTURE_BINDING_2D, &mut old_tex_id); + self.gl.BindTexture(gl_ffi::TEXTURE_2D, tex_id); + self.gl.EGLImageTargetTexture2DOES( + gl_ffi::TEXTURE_2D, *self .images .get(plane) @@ -215,7 +278,7 @@ impl EGLImages { ffi::egl::SUCCESS => Ok(()), err => Err(TextureCreationError::TextureBindingFailed(err)), }; - ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, old_tex_id as u32); + self.gl.BindTexture(gl_ffi::TEXTURE_2D, old_tex_id as u32); res } else { Err(TextureCreationError::ContextLost) @@ -238,7 +301,7 @@ impl Drop for EGLImages { /// Trait any backend type may implement that allows binding a `wayland_server::Display` /// to create an `EGLDisplay` for EGL-based `WlBuffer`s. -pub trait EGLWaylandExtensions { +pub trait EGLGraphicsBackend { /// Binds this EGL context to the given Wayland display. /// /// This will allow clients to utilize EGL to create hardware-accelerated @@ -257,15 +320,38 @@ pub trait EGLWaylandExtensions { /// Type to receive `EGLImages` for EGL-based `WlBuffer`s. /// -/// Can be created by using `EGLWaylandExtensions::bind_wl_display`. -pub struct EGLDisplay(Weak, *mut wl_display); +/// Can be created by using `EGLGraphicsBackend::bind_wl_display`. +pub struct EGLDisplay { + egl: Weak, + wayland: *mut wl_display, + #[cfg(feature = "renderer_gl")] + gl: gl_ffi::Gles2, + #[cfg(feature = "renderer_gl")] + egl_to_texture_support: bool, +} impl EGLDisplay { fn new>( context: &EGLContext, display: *mut wl_display, ) -> EGLDisplay { - EGLDisplay(Rc::downgrade(&context.display), display) + let gl = gl_ffi::Gles2::load_with(|s| unsafe { context.get_proc_address(s) as *const _ }); + + EGLDisplay { + egl: Rc::downgrade(&context.display), + wayland: display, + #[cfg(feature = "renderer_gl")] + egl_to_texture_support: { + // the list of gl extensions supported by the context + let data = unsafe { CStr::from_ptr(gl.GetString(gl_ffi::EXTENSIONS) as *const _ )} + .to_bytes() + .to_vec(); + let list = String::from_utf8(data).unwrap(); + list.split(' ').any(|s| s == "GL_OES_EGL_image" || s == "GL_OES_EGL_image_base") + }, + #[cfg(feature = "renderer_gl")] + gl, + } } /// Try to receive `EGLImages` from a given `WlBuffer`. @@ -277,7 +363,7 @@ impl EGLDisplay { &self, buffer: Resource, ) -> ::std::result::Result { - if let Some(display) = self.0.upgrade() { + if let Some(display) = self.egl.upgrade() { let mut format: i32 = 0; if unsafe { ffi::egl::QueryWaylandBufferWL( @@ -368,6 +454,10 @@ impl EGLDisplay { format, images, buffer, + #[cfg(feature = "renderer_gl")] + gl: self.gl.clone(), + #[cfg(feature = "renderer_gl")] + egl_to_texture_support: self.egl_to_texture_support, }) } else { Err(BufferAccessError::ContextLost) @@ -377,36 +467,33 @@ impl EGLDisplay { impl Drop for EGLDisplay { fn drop(&mut self) { - if let Some(display) = self.0.upgrade() { - if !self.1.is_null() { + if let Some(display) = self.egl.upgrade() { + if !self.wayland.is_null() { unsafe { - ffi::egl::UnbindWaylandDisplayWL(*display, self.1 as *mut _); + ffi::egl::UnbindWaylandDisplayWL(*display, self.wayland as *mut _); } } } } } -impl EGLWaylandExtensions for Rc { +impl EGLGraphicsBackend for Rc { fn bind_wl_display(&self, display: &Display) -> Result { (**self).bind_wl_display(display) } } -impl> EGLWaylandExtensions for EGLContext { +impl> EGLGraphicsBackend for EGLContext { fn bind_wl_display(&self, display: &Display) -> Result { if !self.wl_drm_support { bail!(ErrorKind::EglExtensionNotSupported(&[ "EGL_WL_bind_wayland_display" ])); } - if !self.egl_to_texture_support { - bail!(ErrorKind::EglExtensionNotSupported(&["GL_OES_EGL_image"])); - } let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) }; if res == 0 { bail!(ErrorKind::OtherEGLDisplayAlreadyBound); } Ok(EGLDisplay::new(self, display.c_ptr())) } -} +} \ No newline at end of file diff --git a/src/backend/graphics/egl/native.rs b/src/backend/egl/native.rs similarity index 64% rename from src/backend/graphics/egl/native.rs rename to src/backend/egl/native.rs index 1089804..6e4e79e 100644 --- a/src/backend/graphics/egl/native.rs +++ b/src/backend/egl/native.rs @@ -1,16 +1,11 @@ //! Type safe native types for safe context/surface creation use super::{error::*, ffi}; -#[cfg(feature = "backend_drm")] -use backend::drm::error::{Error as DrmError, ErrorKind as DrmErrorKind, Result as DrmResult}; -#[cfg(feature = "backend_drm")] -use gbm::{AsRaw, BufferObjectFlags, Device as GbmDevice, Format as GbmFormat, Surface as GbmSurface}; -#[cfg(feature = "backend_drm")] -use std::marker::PhantomData; -#[cfg(feature = "backend_drm")] -use std::os::unix::io::AsRawFd; -#[cfg(any(feature = "backend_drm", feature = "backend_winit"))] +use backend::graphics::SwapBuffersError; + +#[cfg(feature = "backend_winit")] use std::ptr; + #[cfg(feature = "backend_winit")] use wayland_client::egl as wegl; #[cfg(feature = "backend_winit")] @@ -95,38 +90,6 @@ impl Backend for X11 { } } } -#[cfg(feature = "backend_drm")] -/// Gbm backend type -pub struct Gbm { - _userdata: PhantomData, -} -#[cfg(feature = "backend_drm")] -impl Backend for Gbm { - type Surface = GbmSurface; - - unsafe fn get_display( - display: ffi::NativeDisplayType, - has_dp_extension: F, - log: ::slog::Logger, - ) -> ffi::egl::types::EGLDisplay - where - F: Fn(&str) -> bool, - { - if has_dp_extension("EGL_KHR_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() { - trace!(log, "EGL Display Initialization via EGL_KHR_platform_gbm"); - ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_KHR, display as *mut _, ptr::null()) - } else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplayEXT::is_loaded() { - trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm"); - ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null()) - } else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() { - trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm"); - ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null()) - } else { - trace!(log, "Default EGL Display Initialization via GetDisplay"); - ffi::egl::GetDisplay(display as *mut _) - } - } -} /// Trait for types returning Surfaces which can be used to initialize `EGLSurface`s /// @@ -144,7 +107,7 @@ pub unsafe trait NativeDisplay { /// Return a raw pointer EGL will accept for context creation. fn ptr(&self) -> Result; /// Create a surface - fn create_surface(&self, args: Self::Arguments) -> ::std::result::Result; + fn create_surface(&mut self, args: Self::Arguments) -> ::std::result::Result; } #[cfg(feature = "backend_winit")] @@ -162,7 +125,7 @@ unsafe impl NativeDisplay for WinitWindow { .ok_or(ErrorKind::NonMatchingBackend("X11").into()) } - fn create_surface(&self, _args: ()) -> Result { + fn create_surface(&mut self, _args: ()) -> Result { self.get_xlib_window() .map(XlibWindow) .ok_or(ErrorKind::NonMatchingBackend("X11").into()) @@ -184,7 +147,7 @@ unsafe impl NativeDisplay for WinitWindow { .ok_or(ErrorKind::NonMatchingBackend("Wayland").into()) } - fn create_surface(&self, _args: ()) -> Result { + fn create_surface(&mut self, _args: ()) -> Result { if let Some(surface) = self.get_wayland_surface() { let size = self.get_inner_size().unwrap(); Ok(unsafe { @@ -196,41 +159,7 @@ unsafe impl NativeDisplay for WinitWindow { } } -#[cfg(feature = "backend_drm")] -/// Arguments necessary to construct a `GbmSurface` -pub struct GbmSurfaceArguments { - /// Size of the surface - pub size: (u32, u32), - /// Pixel format of the surface - pub format: GbmFormat, - /// Flags for surface creation - pub flags: BufferObjectFlags, -} - -#[cfg(feature = "backend_drm")] -unsafe impl NativeDisplay> for GbmDevice { - type Arguments = GbmSurfaceArguments; - type Error = DrmError; - - fn is_backend(&self) -> bool { - true - } - - fn ptr(&self) -> Result { - Ok(self.as_raw() as *const _) - } - - fn create_surface(&self, args: GbmSurfaceArguments) -> DrmResult> { - use backend::drm::error::ResultExt as DrmResultExt; - - DrmResultExt::chain_err( - GbmDevice::create_surface(self, args.size.0, args.size.1, args.format, args.flags), - || DrmErrorKind::GbmInitFailed, - ) - } -} - -/// Trait for types returning valid surface pointers for initializing EGL +/// Trait for types returning valid surface pointers for initializing egl /// /// ## Unsafety /// @@ -238,6 +167,14 @@ unsafe impl NativeDisplay> for GbmDevic pub unsafe trait NativeSurface { /// Return a raw pointer egl will accept for surface creation. fn ptr(&self) -> ffi::NativeWindowType; + /// Adds additional semantics when calling EGLSurface::swap_buffers + /// + /// Only implement if required by the backend, flip must be called during this call. + fn swap_buffers(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> + where F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + { + flip() + } } #[cfg(feature = "backend_winit")] @@ -253,10 +190,3 @@ unsafe impl NativeSurface for wegl::WlEglSurface { self.ptr() as *const _ } } - -#[cfg(feature = "backend_drm")] -unsafe impl NativeSurface for GbmSurface { - fn ptr(&self) -> ffi::NativeWindowType { - self.as_raw() as *const _ - } -} diff --git a/src/backend/graphics/egl/surface.rs b/src/backend/egl/surface.rs similarity index 83% rename from src/backend/graphics/egl/surface.rs rename to src/backend/egl/surface.rs index fce3cd4..71970cb 100644 --- a/src/backend/graphics/egl/surface.rs +++ b/src/backend/egl/surface.rs @@ -1,6 +1,7 @@ //! EGL surface related structs -use super::{error::*, ffi, native, EGLContext, SwapBuffersError}; +use super::{error::*, ffi, native, EGLContext}; +use backend::graphics::SwapBuffersError; use std::{ ops::{Deref, DerefMut}, rc::{Rc, Weak}, @@ -55,20 +56,22 @@ impl EGLSurface { /// Swaps buffers at the end of a frame. pub fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { - if let Some(display) = self.display.upgrade() { - let ret = unsafe { ffi::egl::SwapBuffers((*display) as *const _, self.surface as *const _) }; + self.native.swap_buffers(|| { + if let Some(display) = self.display.upgrade() { + let ret = unsafe { ffi::egl::SwapBuffers((*display) as *const _, self.surface as *const _) }; - if ret == 0 { - match unsafe { ffi::egl::GetError() } as u32 { - ffi::egl::CONTEXT_LOST => Err(SwapBuffersError::ContextLost), - err => Err(SwapBuffersError::Unknown(err)), + if ret == 0 { + match unsafe { ffi::egl::GetError() } as u32 { + ffi::egl::CONTEXT_LOST => Err(SwapBuffersError::ContextLost), + err => Err(SwapBuffersError::Unknown(err)), + } + } else { + Ok(()) } } else { - Ok(()) + Err(SwapBuffersError::ContextLost) } - } else { - Err(SwapBuffersError::ContextLost) - } + }) } /// Makes the OpenGL context the current context in the current thread. diff --git a/src/backend/graphics/egl/mod.rs b/src/backend/graphics/egl/mod.rs deleted file mode 100644 index 2d04696..0000000 --- a/src/backend/graphics/egl/mod.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Common traits and types for EGL rendering - -// Large parts of this module are taken from -// https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/src/api/egl/ -// -// It therefore falls under glutin's Apache 2.0 license -// (see https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/LICENSE) - -use super::GraphicsBackend; -use nix::libc::c_void; -use std::fmt; - -pub mod context; -pub use self::context::EGLContext; -pub mod error; -#[allow( - non_camel_case_types, - dead_code, - unused_mut, - non_upper_case_globals -)] -pub mod ffi; -pub mod native; -pub mod surface; -pub use self::surface::EGLSurface; -pub mod wayland; -pub use self::wayland::{BufferAccessError, EGLImages, EGLWaylandExtensions}; - -/// Error that can happen when swapping buffers. -#[derive(Debug, Clone, PartialEq)] -pub enum SwapBuffersError { - /// The OpenGL context has been lost and needs to be recreated. - /// - /// All the objects associated to it (textures, buffers, programs, etc.) - /// need to be recreated from scratch. - /// - /// Operations will have no effect. Functions that read textures, buffers, etc. - /// from OpenGL will return uninitialized data instead. - /// - /// A context loss usually happens on mobile devices when the user puts the - /// application to sleep and wakes it up later. However any OpenGL implementation - /// can theoretically lose the context at any time. - ContextLost, - /// The buffers have already been swapped. - /// - /// This error can be returned when `swap_buffers` has been called multiple times - /// without any modification in between. - AlreadySwapped, - /// Unknown GL error - Unknown(u32), -} - -impl fmt::Display for SwapBuffersError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> { - use std::error::Error; - write!(formatter, "{}", self.description()) - } -} - -impl ::std::error::Error for SwapBuffersError { - fn description(&self) -> &str { - match *self { - SwapBuffersError::ContextLost => "The context has been lost, it needs to be recreated", - SwapBuffersError::AlreadySwapped => { - "Buffers are already swapped, swap_buffers was called too many times" - } - SwapBuffersError::Unknown(_) => "Unknown Open GL error occurred", - } - } - - fn cause(&self) -> Option<&::std::error::Error> { - None - } -} - -/// Error that can happen on optional EGL features -#[derive(Debug, Clone, PartialEq)] -pub struct EglExtensionNotSupportedError(&'static [&'static str]); - -impl fmt::Display for EglExtensionNotSupportedError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> { - write!( - formatter, - "None of the following EGL extensions is supported by the underlying EGL implementation, - at least one is required: {:?}", - self.0 - ) - } -} - -impl ::std::error::Error for EglExtensionNotSupportedError { - fn description(&self) -> &str { - "The required EGL extension is not supported by the underlying EGL implementation" - } - - fn cause(&self) -> Option<&::std::error::Error> { - None - } -} - -/// Describes the pixel format of the main framebuffer -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct PixelFormat { - /// is the format hardware accelerated - pub hardware_accelerated: bool, - /// number of bits used for colors - pub color_bits: u8, - /// number of bits used for alpha channel - pub alpha_bits: u8, - /// number of bits used for depth channel - pub depth_bits: u8, - /// number of bits used for stencil buffer - pub stencil_bits: u8, - /// is stereoscopy enabled - pub stereoscopy: bool, - /// is double buffering enabled - pub double_buffer: bool, - /// number of samples used for multisampling if enabled - pub multisampling: Option, - /// is srgb enabled - pub srgb: bool, -} - -/// Trait that describes objects that have an OpenGL context -/// and can be used to render upon -pub trait EGLGraphicsBackend: GraphicsBackend { - /// Swaps buffers at the end of a frame. - fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError>; - - /// Returns the address of an OpenGL function. - /// - /// Supposes that the context has been made current before this function is called. - unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void; - - /// Returns the dimensions of the window, or screen, etc in points. - /// - /// That are the scaled pixels of the underlying graphics backend. - /// For nested compositors this will respect the scaling of the root compositor. - /// For drawing directly onto hardware this unit will be equal to actual pixels. - fn get_framebuffer_dimensions(&self) -> (u32, u32); - - /// Returns `true` if the OpenGL context is the current one in the thread. - fn is_current(&self) -> bool; - - /// Makes the OpenGL context the current context in the current thread. - /// - /// # Unsafety - /// - /// This function is marked unsafe, because the context cannot be made current - /// on multiple threads. - unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError>; - - /// Returns the pixel format of the main framebuffer of the context. - fn get_pixel_format(&self) -> PixelFormat; -} From ac0dc42e9ef1de172c47678d5359cdef466decd8 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:21:12 +0100 Subject: [PATCH 02/56] Add seperate GL module - Move parts of glium & egl module into own module - Add raw GL loader as an alternative --- src/backend/graphics/gl.rs | 76 +++++++++++++++++++++++++++++++++++ src/backend/graphics/glium.rs | 28 +++++-------- src/backend/graphics/mod.rs | 3 +- src/backend/mod.rs | 2 + 4 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 src/backend/graphics/gl.rs diff --git a/src/backend/graphics/gl.rs b/src/backend/graphics/gl.rs new file mode 100644 index 0000000..5f120b5 --- /dev/null +++ b/src/backend/graphics/gl.rs @@ -0,0 +1,76 @@ +use nix::libc::c_void; + +use super::SwapBuffersError; + +#[cfg_attr(feature = "cargo-clippy", allow(clippy))] +#[allow(missing_docs)] +pub(crate) mod ffi { + include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); +} + +pub use self::ffi::Gles2; + +/// Describes the pixel format of the main framebuffer +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PixelFormat { + /// is the format hardware accelerated + pub hardware_accelerated: bool, + /// number of bits used for colors + pub color_bits: u8, + /// number of bits used for alpha channel + pub alpha_bits: u8, + /// number of bits used for depth channel + pub depth_bits: u8, + /// number of bits used for stencil buffer + pub stencil_bits: u8, + /// is stereoscopy enabled + pub stereoscopy: bool, + /// is double buffering enabled + pub double_buffer: bool, + /// number of samples used for multisampling if enabled + pub multisampling: Option, + /// is srgb enabled + pub srgb: bool, +} + +/// Trait that describes objects that have an OpenGL context +/// and can be used to render upon +pub trait GLGraphicsBackend { + /// Swaps buffers at the end of a frame. + fn swap_buffers(&self) -> Result<(), SwapBuffersError>; + + /// Returns the address of an OpenGL function. + /// + /// Supposes that the context has been made current before this function is called. + unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void; + + /// Returns the dimensions of the window, or screen, etc in points. + /// + /// That are the scaled pixels of the underlying graphics backend. + /// For nested compositors this will respect the scaling of the root compositor. + /// For drawing directly onto hardware this unit will be equal to actual pixels. + fn get_framebuffer_dimensions(&self) -> (u32, u32); + + /// Returns true if the OpenGL context is the current one in the thread. + fn is_current(&self) -> bool; + + /// Makes the OpenGL context the current context in the current thread. + /// + /// # Unsafety + /// + /// This function is marked unsafe, because the context cannot be made current + /// on multiple threads. + unsafe fn make_current(&self) -> Result<(), SwapBuffersError>; + + /// Returns the pixel format of the main framebuffer of the context. + fn get_pixel_format(&self) -> PixelFormat; +} + +/// Loads a Raw GLES Interface for a given `GLGraphicsBackend` +/// +/// This remains valid as long as the underlying `GLGraphicsBackend` is alive +/// and may only be used in combination with the backend. Using this with any +/// other gl context may cause undefined behavior. +pub fn load_raw_gl(backend: &B) -> Gles2 { + Gles2::load_with(|s| unsafe { backend.get_proc_address(s) as *const _ }) +} \ No newline at end of file diff --git a/src/backend/graphics/glium.rs b/src/backend/graphics/glium.rs index 4c242fe..caf1b1f 100644 --- a/src/backend/graphics/glium.rs +++ b/src/backend/graphics/glium.rs @@ -1,9 +1,8 @@ //! Glium compatibility module -use backend::graphics::egl::{ - error::Result as EGLResult, - wayland::{EGLDisplay, EGLWaylandExtensions}, - EGLGraphicsBackend, SwapBuffersError, +use backend::graphics::{ + gl::GLGraphicsBackend, + SwapBuffersError, }; use glium::{ backend::{Backend, Context, Facade}, @@ -15,7 +14,6 @@ use std::{ os::raw::c_void, rc::Rc, }; -use wayland_server::Display; impl From for GliumSwapBuffersError { fn from(error: SwapBuffersError) -> Self { @@ -28,14 +26,14 @@ impl From for GliumSwapBuffersError { } /// Wrapper to expose `Glium` compatibility -pub struct GliumGraphicsBackend { +pub struct GliumGraphicsBackend { context: Rc, backend: Rc>, } -struct InternalBackend(RefCell); +struct InternalBackend(RefCell); -impl GliumGraphicsBackend { +impl GliumGraphicsBackend { fn new(backend: T) -> GliumGraphicsBackend { let internal = Rc::new(InternalBackend(RefCell::new(backend))); @@ -79,27 +77,19 @@ impl GliumGraphicsBackend { } } -impl Facade for GliumGraphicsBackend { +impl Facade for GliumGraphicsBackend { fn get_context(&self) -> &Rc { &self.context } } -impl From for GliumGraphicsBackend { +impl From for GliumGraphicsBackend { fn from(backend: T) -> Self { GliumGraphicsBackend::new(backend) } } -impl EGLWaylandExtensions - for GliumGraphicsBackend -{ - fn bind_wl_display(&self, display: &Display) -> EGLResult { - (*self.backend).0.borrow().bind_wl_display(display) - } -} - -unsafe impl Backend for InternalBackend { +unsafe impl Backend for InternalBackend { fn swap_buffers(&self) -> Result<(), GliumSwapBuffersError> { self.0.borrow().swap_buffers().map_err(Into::into) } diff --git a/src/backend/graphics/mod.rs b/src/backend/graphics/mod.rs index e9470e8..323cc39 100644 --- a/src/backend/graphics/mod.rs +++ b/src/backend/graphics/mod.rs @@ -35,7 +35,8 @@ pub trait GraphicsBackend { ) -> Result<(), Self::Error>; } -pub mod egl; +#[cfg(feature = "renderer_gl")] +pub mod gl; #[cfg(feature = "renderer_glium")] pub mod glium; pub mod software; diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 328f605..ba94a50 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -19,6 +19,8 @@ pub mod input; #[cfg(feature = "backend_drm")] pub mod drm; +#[cfg(feature = "backend_egl")] +pub mod egl; #[cfg(feature = "backend_libinput")] pub mod libinput; #[cfg(feature = "backend_session")] From 09e589b23c5b20405c7778d8d0adaf5d1ab195e6 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:28:15 +0100 Subject: [PATCH 03/56] Generate (e)gl_bindings based on feature set --- Cargo.toml | 10 ++++---- build.rs | 68 +++++++++++++++++++++++++++++------------------------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 64de8fb..025e680 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,16 +34,18 @@ error-chain = "0.11.0" lazy_static = "1.0.0" [build-dependencies] -gl_generator = "0.9" +gl_generator = { version = "0.9", optional = true } [features] default = ["backend_winit", "backend_drm", "backend_libinput", "backend_udev", "renderer_glium", "xwayland"] -backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen"] -backend_drm = ["drm", "gbm"] +backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl"] +backend_drm = ["drm", "backend_egl"] +backend_egl = ["gl_generator"] backend_libinput = ["input"] backend_session = [] backend_session_udev = ["udev", "backend_session"] backend_session_logind = ["dbus", "systemd", "backend_session"] backend_udev = ["udev", "backend_drm", "backend_session_udev"] -renderer_glium = ["glium"] +renderer_gl = ["gl_generator"] +renderer_glium = ["renderer_gl", "glium"] xwayland = [] \ No newline at end of file diff --git a/build.rs b/build.rs index 700499f..b119e11 100644 --- a/build.rs +++ b/build.rs @@ -8,37 +8,41 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); - let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap(); - Registry::new( - Api::Egl, - (1, 5), - Profile::Core, - Fallbacks::All, - [ - "EGL_KHR_create_context", - "EGL_EXT_create_context_robustness", - "EGL_KHR_create_context_no_error", - "EGL_KHR_platform_x11", - "EGL_KHR_platform_android", - "EGL_KHR_platform_wayland", - "EGL_KHR_platform_gbm", - "EGL_EXT_platform_base", - "EGL_EXT_platform_x11", - "EGL_MESA_platform_gbm", - "EGL_EXT_platform_wayland", - "EGL_EXT_platform_device", - "EGL_KHR_image_base", - ], - ).write_bindings(gl_generator::GlobalGenerator, &mut file) - .unwrap(); + if env::var_os("CARGO_FEATURE_BACKEND_EGL").is_some() { + let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap(); + Registry::new( + Api::Egl, + (1, 5), + Profile::Core, + Fallbacks::All, + [ + "EGL_KHR_create_context", + "EGL_EXT_create_context_robustness", + "EGL_KHR_create_context_no_error", + "EGL_KHR_platform_x11", + "EGL_KHR_platform_android", + "EGL_KHR_platform_wayland", + "EGL_KHR_platform_gbm", + "EGL_EXT_platform_base", + "EGL_EXT_platform_x11", + "EGL_MESA_platform_gbm", + "EGL_EXT_platform_wayland", + "EGL_EXT_platform_device", + "EGL_KHR_image_base", + ], + ).write_bindings(gl_generator::GlobalGenerator, &mut file) + .unwrap(); + } - let mut file = File::create(&dest.join("gl_bindings.rs")).unwrap(); - Registry::new( - Api::Gles2, - (3, 2), - Profile::Compatibility, - Fallbacks::None, - ["GL_OES_EGL_image"], - ).write_bindings(gl_generator::GlobalGenerator, &mut file) - .unwrap(); + if env::var_os("CARGO_FEATURE_RENDERER_GL").is_some() { + let mut file = File::create(&dest.join("gl_bindings.rs")).unwrap(); + Registry::new( + Api::Gles2, + (3, 2), + Profile::Compatibility, + Fallbacks::None, + ["GL_OES_EGL_image"], + ).write_bindings(gl_generator::StructGenerator, &mut file) + .unwrap(); + } } From bbf28655d169aeed371f866273a311bbf8d5ad85 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:32:44 +0100 Subject: [PATCH 04/56] Rename GraphicsBackend to CursorBackend --- src/backend/graphics/cursor.rs | 33 +++++++++++++++++++++++++++++++++ src/backend/graphics/mod.rs | 33 ++------------------------------- 2 files changed, 35 insertions(+), 31 deletions(-) create mode 100644 src/backend/graphics/cursor.rs diff --git a/src/backend/graphics/cursor.rs b/src/backend/graphics/cursor.rs new file mode 100644 index 0000000..fe2ab8c --- /dev/null +++ b/src/backend/graphics/cursor.rs @@ -0,0 +1,33 @@ +/// Functions to render cursors on any graphics backend independently from it's rendering techique. +pub trait CursorBackend<'a> { + /// Format representing the image drawn for the cursor. + type CursorFormat: 'a; + + /// Error the underlying backend throws if operations fail + type Error; + + /// Sets the cursor position and therefor updates the drawn cursors position. + /// Useful as well for e.g. pointer wrapping. + /// + /// Not guaranteed to be supported on every backend. The result usually + /// depends on the backend, the cursor might be "owned" by another more priviledged + /// compositor (running nested). + /// + /// In these cases setting the position is actually not required, as movement is done + /// by the higher compositor and not by the backend. It is still good practice to update + /// the position after every recieved event, but don't rely on pointer wrapping working. + /// + fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error>; + + /// Set the cursor drawn on the `CursorBackend`. + /// + /// The format is entirely dictated by the concrete implementation and might range + /// from raw image buffers over a fixed list of possible cursor types to simply the + /// void type () to represent no possible customization of the cursor itself. + fn set_cursor_representation<'b>( + &'b self, + cursor: Self::CursorFormat, + hotspot: (u32, u32), + ) -> Result<(), Self::Error> + where 'a: 'b; +} \ No newline at end of file diff --git a/src/backend/graphics/mod.rs b/src/backend/graphics/mod.rs index 323cc39..00bcc32 100644 --- a/src/backend/graphics/mod.rs +++ b/src/backend/graphics/mod.rs @@ -2,38 +2,9 @@ //! //! Note: Not every API may be supported by every backend -/// General functions any graphics backend should support independently from it's rendering -/// technique. -pub trait GraphicsBackend { - /// Format representing the image drawn for the cursor. - type CursorFormat; - /// Error the underlying backend throws if operations fail - type Error; - - /// Sets the cursor position and therefor updates the drawn cursors position. - /// Useful as well for e.g. pointer wrapping. - /// - /// Not guaranteed to be supported on every backend. The result usually - /// depends on the backend, the cursor might be "owned" by another more privileged - /// compositor (running nested). - /// - /// In these cases setting the position is actually not required, as movement is done - /// by the higher compositor and not by the backend. It is still good practice to update - /// the position after every received event, but don't rely on pointer wrapping working. - fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), Self::Error>; - - /// Set the cursor drawn on the `GraphicsBackend`. - /// - /// The format is entirely dictated by the concrete implementation and might range - /// from raw image buffers over a fixed list of possible cursor types to simply the - /// void type `()` to represent no possible customization of the cursor itself. - fn set_cursor_representation( - &self, - cursor: &Self::CursorFormat, - hotspot: (u32, u32), - ) -> Result<(), Self::Error>; -} +mod cursor; +pub use self::cursor::*; #[cfg(feature = "renderer_gl")] pub mod gl; From ccc7abc94fdbafeb580b9577e6bc908ce6caa44b Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:33:33 +0100 Subject: [PATCH 05/56] Create general SwapBuffersError --- src/backend/graphics/errors.rs | 46 ++++++++++++++++++++++++++++++++++ src/backend/graphics/mod.rs | 2 ++ 2 files changed, 48 insertions(+) create mode 100644 src/backend/graphics/errors.rs diff --git a/src/backend/graphics/errors.rs b/src/backend/graphics/errors.rs new file mode 100644 index 0000000..4b0b56a --- /dev/null +++ b/src/backend/graphics/errors.rs @@ -0,0 +1,46 @@ +use std::fmt; +use std::error::Error; + +/// Error that can happen when swapping buffers. +#[derive(Debug, Clone, PartialEq)] +pub enum SwapBuffersError { + /// The corresponding context has been lost and needs to be recreated. + /// + /// All the objects associated to it (textures, buffers, programs, etc.) + /// need to be recreated from scratch. + /// + /// Operations will have no effect. Functions that read textures, buffers, etc. + /// will return uninitialized data instead. + ContextLost, + /// The buffers have already been swapped. + /// + /// This error can be returned when `swap_buffers` has been called multiple times + /// without any modification in between. + AlreadySwapped, + /// Unknown error + Unknown(u32), +} + +impl fmt::Display for SwapBuffersError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use std::error::Error; + write!(formatter, "{}", self.description()) + } +} + +impl Error for SwapBuffersError { + fn description(&self) -> &str { + match *self { + SwapBuffersError::ContextLost => "The context has been lost, it needs to be recreated", + SwapBuffersError::AlreadySwapped => { + "Buffers are already swapped, swap_buffers was called too many times" + } + SwapBuffersError::Unknown(_) => "Unknown error occurred", + } + } + + fn cause(&self) -> Option<&Error> { + None + } +} + diff --git a/src/backend/graphics/mod.rs b/src/backend/graphics/mod.rs index 00bcc32..d6b3a28 100644 --- a/src/backend/graphics/mod.rs +++ b/src/backend/graphics/mod.rs @@ -2,6 +2,8 @@ //! //! Note: Not every API may be supported by every backend +mod errors; +pub use self::errors::*; mod cursor; pub use self::cursor::*; From 38ec44f70cf4d584f799ee6ac815f511e77a8416 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:35:46 +0100 Subject: [PATCH 06/56] Hide SoftwareRenderer behind feature flag - Don't let backend depend on `CursorBackend` (used to be `GraphicsBackend`) anymore --- src/backend/graphics/mod.rs | 1 + src/backend/graphics/software.rs | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/graphics/mod.rs b/src/backend/graphics/mod.rs index d6b3a28..abac583 100644 --- a/src/backend/graphics/mod.rs +++ b/src/backend/graphics/mod.rs @@ -12,4 +12,5 @@ pub use self::cursor::*; pub mod gl; #[cfg(feature = "renderer_glium")] pub mod glium; +#[cfg(feature = "renderer_software")] pub mod software; diff --git a/src/backend/graphics/software.rs b/src/backend/graphics/software.rs index a7570bd..700f292 100644 --- a/src/backend/graphics/software.rs +++ b/src/backend/graphics/software.rs @@ -1,11 +1,10 @@ //! Common traits and types used for software rendering on graphics backends -use super::GraphicsBackend; use std::error::Error; use wayland_server::protocol::wl_shm::Format; /// Trait that describes objects providing a software rendering implementation -pub trait CpuGraphicsBackend: GraphicsBackend { +pub trait CpuGraphicsBackend { /// Render a given buffer of a given format at a specified place in the framebuffer /// /// # Error From 505791e336d5adcf1ed29cbd3be9cddc79b988a9 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:37:57 +0100 Subject: [PATCH 07/56] Upgrade backends to calloop 0.4 and renamed gl-traits --- Cargo.toml | 6 +++--- src/backend/libinput.rs | 45 +++++++++++++++++++---------------------- src/backend/winit.rs | 41 ++++++++++++++++++++----------------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 025e680..39730bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ repository = "https://github.com/Smithay/smithay" members = [ "anvil" ] [dependencies] -wayland-server = "0.21.1" -wayland-sys = "0.21.1" +wayland-server = "0.21.4" +wayland-sys = "0.21.3" wayland-commons = "0.21.1" nix = "0.11" xkbcommon = "0.2.1" @@ -28,7 +28,7 @@ input = { version = "0.4.0", optional = true } udev = { version = "0.2.0", optional = true } dbus = { version = "0.6.1", optional = true } systemd = { version = "^0.2.0", optional = true } -wayland-protocols = { version = "0.21.1", features = ["unstable_protocols", "native_server"] } +wayland-protocols = { version = "0.21.3", features = ["unstable_protocols", "native_server"] } image = "0.17.0" error-chain = "0.11.0" lazy_static = "1.0.0" diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index 6a5407e..4e62ca7 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -7,25 +7,22 @@ use input as libinput; use input::event; use std::{ - cell::RefCell, collections::hash_map::{DefaultHasher, Entry, HashMap}, hash::{Hash, Hasher}, io::Error as IoError, - os::unix::io::RawFd, - path::Path, - rc::Rc, + os::unix::io::{AsRawFd, RawFd}, }; use wayland_server::calloop::{ - generic::{EventedRawFd, Generic}, + generic::{EventedFd, Generic}, mio::Ready, - LoopHandle, Source, + LoopHandle, Source, InsertError, }; // No idea if this is the same across unix platforms // Lets make this linux exclusive for now, once someone tries to build it for // any BSD-like system, they can verify if this is right and make a PR to change this. -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(all(any(target_os = "linux", target_os = "android"), feature = "backend_session"))] const INPUT_MAJOR: u32 = 13; /// Libinput based `InputBackend`. @@ -590,6 +587,12 @@ impl libinput::LibinputInterface for LibinputSessionInterface { } } +impl AsRawFd for LibinputInputBackend { + fn as_raw_fd(&self) -> RawFd { + unsafe { self.context.fd() } + } +} + /// Binds a `LibinputInputBackend` to a given `EventLoop`. /// /// Automatically feeds the backend with incoming events without any manual calls to @@ -597,22 +600,16 @@ impl libinput::LibinputInterface for LibinputSessionInterface { pub fn libinput_bind( backend: LibinputInputBackend, handle: LoopHandle, -) -> ::std::result::Result>, (IoError, LibinputInputBackend)> { - let mut source = Generic::from_raw_fd(unsafe { backend.context.fd() }); +) -> ::std::result::Result>>, InsertError>>> { + let mut source = Generic::from_fd_source(backend); source.set_interest(Ready::readable()); - let backend = Rc::new(RefCell::new(backend)); - let fail_backend = backend.clone(); - handle - .insert_source(source, move |_, _| { - use backend::input::InputBackend; - if let Err(error) = backend.borrow_mut().dispatch_new_events() { - warn!(backend.borrow().logger, "Libinput errored: {}", error); - } - }).map_err(move |e| { - // the backend in the closure should already have been dropped - let backend = Rc::try_unwrap(fail_backend) - .unwrap_or_else(|_| unreachable!()) - .into_inner(); - (e.into(), backend) - }) + + handle.insert_source(source, move |evt, _| { + use backend::input::InputBackend; + + let mut backend = evt.source.borrow_mut(); + if let Err(error) = backend.0.dispatch_new_events() { + warn!(backend.0.logger, "Libinput errored: {}", error); + } + }) } diff --git a/src/backend/winit.rs b/src/backend/winit.rs index dd03a8e..f7d3a41 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -2,15 +2,16 @@ use backend::{ graphics::{ - egl::{ - context::GlAttributes, - error as egl_error, - error::Result as EGLResult, - native, - wayland::{EGLDisplay, EGLWaylandExtensions}, - EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError, - }, - GraphicsBackend, + gl::{GLGraphicsBackend, PixelFormat}, + CursorBackend, + SwapBuffersError, + }, + egl::{ + context::GlAttributes, + error as egl_error, + error::Result as EGLResult, + native, + EGLDisplay, EGLContext, EGLGraphicsBackend, EGLSurface, }, input::{ Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, @@ -156,12 +157,12 @@ where let reqs = Default::default(); let window = Rc::new( if native::NativeDisplay::::is_backend(&winit_window) { - let context = + let mut context = EGLContext::::new(winit_window, attributes, reqs, log.clone())?; let surface = context.create_surface(())?; Window::Wayland { context, surface } } else if native::NativeDisplay::::is_backend(&winit_window) { - let context = + let mut context = EGLContext::::new(winit_window, attributes, reqs, log.clone())?; let surface = context.create_surface(())?; Window::X11 { context, surface } @@ -226,8 +227,8 @@ impl WinitGraphicsBackend { } } -impl GraphicsBackend for WinitGraphicsBackend { - type CursorFormat = MouseCursor; +impl<'a> CursorBackend<'a> for WinitGraphicsBackend { + type CursorFormat = &'a MouseCursor; type Error = (); fn set_cursor_position(&self, x: u32, y: u32) -> ::std::result::Result<(), ()> { @@ -240,11 +241,13 @@ impl GraphicsBackend for WinitGraphicsBackend { }) } - fn set_cursor_representation( - &self, - cursor: &Self::CursorFormat, + fn set_cursor_representation<'b>( + &'b self, + cursor: Self::CursorFormat, _hotspot: (u32, u32), - ) -> ::std::result::Result<(), ()> { + ) -> ::std::result::Result<(), ()> + where 'a: 'b + { // Cannot log this one, as `CursorFormat` is not `Debug` and should not be debug!(self.logger, "Changing cursor representation"); self.window.window().set_cursor(*cursor); @@ -252,7 +255,7 @@ impl GraphicsBackend for WinitGraphicsBackend { } } -impl EGLGraphicsBackend for WinitGraphicsBackend { +impl GLGraphicsBackend for WinitGraphicsBackend { fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { trace!(self.logger, "Swapping buffers"); match *self.window { @@ -303,7 +306,7 @@ impl EGLGraphicsBackend for WinitGraphicsBackend { } } -impl EGLWaylandExtensions for WinitGraphicsBackend { +impl EGLGraphicsBackend for WinitGraphicsBackend { fn bind_wl_display(&self, display: &Display) -> EGLResult { match *self.window { Window::Wayland { ref context, .. } => context.bind_wl_display(display), From b537237a7495c93c8def8d6815038ca35d985ea5 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:39:09 +0100 Subject: [PATCH 08/56] Refactor udev backend - Do not open devices for `UdevHandler` anymore - `UdevBackend` does not require `LoopHandle` or `Session` anymore - Type of the created device can be choosed freely by the handler - `UdevBackendObserver` is not needed anymore --- .travis.yml | 1 - Cargo.toml | 3 +- src/backend/udev.rs | 425 ++++++++------------------------------------ 3 files changed, 71 insertions(+), 358 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6779588..f714af3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,6 @@ env: - FEATURES="backend_libinput" - FEATURES="backend_udev" - FEATURES="backend_session" - - FEATURES="backend_session_udev" - FEATURES="backend_session_logind" - FEATURES="renderer_glium" - FEATURES="xwayland" diff --git a/Cargo.toml b/Cargo.toml index 39730bd..ce3a8db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,9 +43,8 @@ backend_drm = ["drm", "backend_egl"] backend_egl = ["gl_generator"] backend_libinput = ["input"] backend_session = [] -backend_session_udev = ["udev", "backend_session"] +backend_udev = ["udev"] backend_session_logind = ["dbus", "systemd", "backend_session"] -backend_udev = ["udev", "backend_drm", "backend_session_udev"] renderer_gl = ["gl_generator"] renderer_glium = ["renderer_gl", "glium"] xwayland = [] \ No newline at end of file diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 4055697..3f94d95 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -9,258 +9,91 @@ //! See also `examples/udev.rs` for pure hardware backed example of a compositor utilizing this //! backend. -use backend::{ - drm::{drm_device_bind, DrmDevice, DrmHandler}, - session::{AsSessionObserver, Session, SessionObserver}, -}; -use drm::{control::Device as ControlDevice, Device as BasicDevice}; -use nix::{fcntl, sys::stat::dev_t}; +use nix::sys::stat::{dev_t, stat}; use std::{ - cell::RefCell, - collections::HashMap, + collections::HashSet, ffi::OsString, - io::Error as IoError, - mem::drop, os::unix::io::{AsRawFd, RawFd}, path::{Path, PathBuf}, - rc::{Rc, Weak}, }; -use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult}; +use udev::{Context, Enumerator, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult}; use wayland_server::calloop::{ - generic::{EventedRawFd, Generic}, + generic::{EventedFd, Generic}, mio::Ready, - LoopHandle, Source, + LoopHandle, Source, InsertError, }; -/// Udev's `DrmDevice` type based on the underlying session -pub struct SessionFdDrmDevice(RawFd); - -impl AsRawFd for SessionFdDrmDevice { - fn as_raw_fd(&self) -> RawFd { - self.0 - } -} -impl BasicDevice for SessionFdDrmDevice {} -impl ControlDevice for SessionFdDrmDevice {} - -/// Graphical backend that monitors available DRM devices. +/// Backend to monitor available drm devices. /// -/// Provides a way to automatically initialize a `DrmDevice` for available GPUs and notifies the -/// given handler of any changes. Can be used to provide hot-plug functionality for GPUs and +/// Provides a way to automatically scan for available gpus and notifies the +/// given handler of any changes. Can be used to provide hot-plug functionality for gpus and /// attached monitors. -pub struct UdevBackend< - H: DrmHandler + 'static, - S: Session + 'static, - T: UdevHandler + 'static, - Data: 'static, -> { - _handler: ::std::marker::PhantomData, - devices: Rc< - RefCell< - HashMap< - dev_t, - ( - Source>, - Rc>>, - ), - >, - >, - >, +pub struct UdevBackend { + devices: HashSet, monitor: MonitorSocket, - session: S, handler: T, logger: ::slog::Logger, - handle: LoopHandle, } -impl< - H: DrmHandler + 'static, - S: Session + 'static, - T: UdevHandler + 'static, - Data: 'static, - > UdevBackend -{ +impl AsRawFd for UdevBackend { + fn as_raw_fd(&self) -> RawFd { + self.monitor.as_raw_fd() + } +} + +impl UdevBackend { /// Creates a new `UdevBackend` and adds it to the given `EventLoop`'s state. /// /// ## Arguments - /// `evlh` - An event loop to use for binding `DrmDevices` /// `context` - An initialized udev context - /// `session` - A session used to open and close devices as they become available /// `handler` - User-provided handler to respond to any detected changes + /// `seat` - /// `logger` - slog Logger to be used by the backend and its `DrmDevices`. - pub fn new( - handle: LoopHandle, + pub fn new>( context: &Context, - mut session: S, mut handler: T, + seat: S, logger: L, - ) -> Result> + ) -> UdevResult> where L: Into>, { - let logger = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_udev")); - let seat = session.seat(); - let devices = all_gpus(context, seat) - .chain_err(|| ErrorKind::FailedToScan)? + let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_udev")); + + let devices = all_gpus(context, seat)? .into_iter() // Create devices - .flat_map(|path| { - match DrmDevice::new( - { - match session.open( - &path, - fcntl::OFlag::O_RDWR - | fcntl::OFlag::O_CLOEXEC - | fcntl::OFlag::O_NOCTTY - | fcntl::OFlag::O_NONBLOCK, - ) { - Ok(fd) => SessionFdDrmDevice(fd), - Err(err) => { - warn!( - logger, - "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err - ); - return None; - } - } - }, - logger.clone(), - ) { - // Call the handler, which might add it to the runloop - Ok(mut device) => { - let devnum = device.device_id(); - let fd = device.as_raw_fd(); - match handler.device_added(&mut device) { - Some(drm_handler) => match drm_device_bind(&handle, device, drm_handler) { - Ok((event_source, device)) => Some((devnum, (event_source, device))), - Err((err, mut device)) => { - warn!(logger, "Failed to bind device. Error: {:?}.", err); - handler.device_removed(&mut device); - drop(device); - if let Err(err) = session.close(fd) { - warn!( - logger, - "Failed to close dropped device. Error: {:?}. Ignoring", err - ); - }; - None - } - }, - None => { - drop(device); //drops master - if let Err(err) = session.close(fd) { - warn!(logger, "Failed to close device. Error: {:?}. Ignoring", err); - } - None - } - } - } - Err(err) => { - warn!( - logger, - "Failed to initialize device {:?}. Error: {:?}. Skipping", path, err - ); - None - } + .flat_map(|path| match stat(&path) { + Ok(stat) => { + handler.device_added(stat.st_rdev, path); + Some(stat.st_rdev) + }, + Err(err) => { + warn!(log, "Unable to get id of {:?}, Error: {:?}. Skipping", path, err); + None } - }).collect::>(); + }) + .collect(); - let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?; - builder - .match_subsystem("drm") - .chain_err(|| ErrorKind::FailedToInitMonitor)?; - let monitor = builder.listen().chain_err(|| ErrorKind::FailedToInitMonitor)?; + let mut builder = MonitorBuilder::new(context)?; + builder.match_subsystem("drm")?; + let monitor = builder.listen()?; Ok(UdevBackend { - _handler: ::std::marker::PhantomData, - devices: Rc::new(RefCell::new(devices)), + devices, monitor, - session, handler, - logger, - handle, + logger: log, }) } - - /// Closes the udev backend and frees all remaining open devices. - pub fn close(&mut self) { - let mut devices = self.devices.borrow_mut(); - for (_, (event_source, device)) in devices.drain() { - event_source.remove(); - let mut device = Rc::try_unwrap(device) - .unwrap_or_else(|_| unreachable!()) - .into_inner(); - self.handler.device_removed(&mut device); - let fd = device.as_raw_fd(); - drop(device); - if let Err(err) = self.session.close(fd) { - warn!(self.logger, "Failed to close device. Error: {:?}. Ignoring", err); - }; - } - info!(self.logger, "All devices closed"); - } } -impl< - H: DrmHandler + 'static, - S: Session + 'static, - T: UdevHandler + 'static, - Data: 'static, - > Drop for UdevBackend +impl Drop for UdevBackend { fn drop(&mut self) { - self.close(); - } -} - -/// `SessionObserver` linked to the `UdevBackend` it was created from. -pub struct UdevBackendObserver { - devices: Weak< - RefCell< - HashMap< - dev_t, - ( - Source>, - Rc>>, - ), - >, - >, - >, - logger: ::slog::Logger, -} - -impl< - H: DrmHandler + 'static, - S: Session + 'static, - T: UdevHandler + 'static, - Data: 'static, - > AsSessionObserver for UdevBackend -{ - fn observer(&mut self) -> UdevBackendObserver { - UdevBackendObserver { - devices: Rc::downgrade(&self.devices), - logger: self.logger.clone(), - } - } -} - -impl SessionObserver for UdevBackendObserver { - fn pause(&mut self, devnum: Option<(u32, u32)>) { - if let Some(devices) = self.devices.upgrade() { - for &mut (_, ref device) in devices.borrow_mut().values_mut() { - info!(self.logger, "changed successful"); - device.borrow_mut().observer().pause(devnum); - } - } - } - - fn activate(&mut self, devnum: Option<(u32, u32, Option)>) { - if let Some(devices) = self.devices.upgrade() { - for &mut (_, ref device) in devices.borrow_mut().values_mut() { - info!(self.logger, "changed successful"); - device.borrow_mut().observer().activate(devnum); - } + for device in &self.devices { + self.handler.device_removed(*device); } } } @@ -269,122 +102,39 @@ impl SessionObserver for UdevBackendObserver { /// /// Allows the backend to receive kernel events and thus to drive the `UdevHandler`. /// No runtime functionality can be provided without using this function. -pub fn udev_backend_bind( - mut udev: UdevBackend, -) -> ::std::result::Result>, IoError> -where - H: DrmHandler + 'static, - T: UdevHandler + 'static, - S: Session + 'static, +pub fn udev_backend_bind( + handle: &LoopHandle, + udev: UdevBackend, +) -> Result>>>, InsertError>>>> { - let fd = udev.monitor.as_raw_fd(); - let handle = udev.handle.clone(); - let mut source = Generic::from_raw_fd(fd); + let mut source = Generic::from_fd_source(udev); source.set_interest(Ready::readable()); - handle - .insert_source(source, move |_, _| { - udev.process_events(); - }).map_err(Into::into) + + handle.insert_source(source, |evt, _| { + evt.source.borrow_mut().0.process_events(); + }) } -impl UdevBackend -where - H: DrmHandler + 'static, - T: UdevHandler + 'static, - S: Session + 'static, - Data: 'static, -{ +impl UdevBackend { fn process_events(&mut self) { - let events = self.monitor.clone().collect::>(); - for event in events { + let monitor = self.monitor.clone(); + for event in monitor { match event.event_type() { // New device EventType::Add => { info!(self.logger, "Device Added"); if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) { - let mut device = { - match DrmDevice::new( - { - let logger = self.logger.clone(); - match self.session.open( - path, - fcntl::OFlag::O_RDWR - | fcntl::OFlag::O_CLOEXEC - | fcntl::OFlag::O_NOCTTY - | fcntl::OFlag::O_NONBLOCK, - ) { - Ok(fd) => SessionFdDrmDevice(fd), - Err(err) => { - warn!( - logger, - "Unable to open drm device {:?}, Error: {:?}. Skipping", - path, - err - ); - continue; - } - } - }, - self.logger.clone(), - ) { - Ok(dev) => dev, - Err(err) => { - warn!( - self.logger, - "Failed to initialize device {:?}. Error: {}. Skipping", path, err - ); - continue; - } - } - }; - let fd = device.as_raw_fd(); - match self.handler.device_added(&mut device) { - Some(drm_handler) => match drm_device_bind(&self.handle, device, drm_handler) { - Ok(fd_event_source) => { - self.devices.borrow_mut().insert(devnum, fd_event_source); - } - Err((err, mut device)) => { - warn!(self.logger, "Failed to bind device. Error: {:?}.", err); - self.handler.device_removed(&mut device); - drop(device); - if let Err(err) = self.session.close(fd) { - warn!( - self.logger, - "Failed to close dropped device. Error: {:?}. Ignoring", err - ); - }; - } - }, - None => { - self.handler.device_removed(&mut device); - drop(device); - if let Err(err) = self.session.close(fd) { - warn!(self.logger, "Failed to close unused device. Error: {:?}", err); - } - } - }; + if self.devices.insert(devnum) { + self.handler.device_added(devnum, path.to_path_buf()); + } } } // Device removed EventType::Remove => { info!(self.logger, "Device Remove"); if let Some(devnum) = event.devnum() { - if let Some((fd_event_source, device)) = self.devices.borrow_mut().remove(&devnum) { - fd_event_source.remove(); - let mut device = Rc::try_unwrap(device) - .unwrap_or_else(|_| unreachable!()) - .into_inner(); - self.handler.device_removed(&mut device); - let fd = device.as_raw_fd(); - drop(device); - if let Err(err) = self.session.close(fd) { - warn!( - self.logger, - "Failed to close device {:?}. Error: {:?}. Ignoring", - event.sysname(), - err - ); - }; + if self.devices.remove(&devnum) { + self.handler.device_removed(devnum); } } } @@ -393,9 +143,8 @@ where info!(self.logger, "Device Changed"); if let Some(devnum) = event.devnum() { info!(self.logger, "Devnum: {:b}", devnum); - if let Some(&(_, ref device)) = self.devices.borrow_mut().get(&devnum) { - let handler = &mut self.handler; - handler.device_changed(&mut device.borrow_mut()); + if self.devices.contains(&devnum) { + self.handler.device_changed(devnum); } else { info!(self.logger, "changed, but device not tracked by backend"); }; @@ -409,36 +158,21 @@ where } } -/// Handler for the `UdevBackend`, allows to open, close and update DRM devices as they change during runtime. -pub trait UdevHandler + 'static> { - /// Called on initialization for every known device and when a new device is detected. - /// - /// Returning a `DrmHandler` will initialize the device, returning `None` will ignore the device. - /// - /// ## Panics - /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn device_added(&mut self, device: &mut DrmDevice) -> Option; +/// Handler for the `UdevBackend`, allows to open, close and update drm devices as they change during runtime. +pub trait UdevHandler { + /// Called when a new device is detected. + fn device_added(&mut self, device: dev_t, path: PathBuf); /// Called when an open device is changed. /// /// This usually indicates that some connectors did become available or were unplugged. The handler /// should scan again for connected monitors and mode switch accordingly. - /// - /// ## Panics - /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn device_changed(&mut self, device: &mut DrmDevice); + fn device_changed(&mut self, device: dev_t); /// Called when a device was removed. /// - /// The device will not accept any operations anymore and its file descriptor will be closed once - /// this function returns, any open references/tokens to this device need to be released. - /// - /// ## Panics - /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn device_removed(&mut self, device: &mut DrmDevice); - /// Called when the udev context has encountered and error. - /// - /// ## Panics - /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn error(&mut self, error: IoError); + /// The corresponding `UdevRawFd` will never return a valid `RawFd` anymore + /// and its file descriptor will be closed once this function returns, + /// any open references/tokens to this device need to be released. + fn device_removed(&mut self, device: dev_t); } /// Returns the path of the primary GPU device if any @@ -489,22 +223,3 @@ pub fn all_gpus>(context: &Context, seat: S) -> UdevResult Date: Wed, 21 Nov 2018 09:44:48 +0100 Subject: [PATCH 09/56] Refactor drm backend - Split `DrmDevice` into `LegacyDrmDevice`, `GbmDevice` and `EglDevice` - Provide common `Device` and `RawDevice` traits - Change `DrmBackend` into `Surface` (and `RawSurface`) implementations of each `Device` (or `RawDevice`) --- Cargo.toml | 9 +- src/backend/drm/backend.rs | 537 ------------------ src/backend/drm/egl/error.rs | 19 + src/backend/drm/egl/mod.rs | 172 ++++++ src/backend/drm/egl/session.rs | 35 ++ src/backend/drm/egl/surface.rs | 110 ++++ src/backend/drm/gbm/egl.rs | 118 ++++ src/backend/drm/gbm/error.rs | 47 ++ src/backend/drm/gbm/mod.rs | 191 +++++++ src/backend/drm/gbm/session.rs | 89 +++ src/backend/drm/gbm/surface.rs | 329 ++++++++++++ src/backend/drm/{ => legacy}/error.rs | 19 +- src/backend/drm/legacy/mod.rs | 257 +++++++++ src/backend/drm/legacy/session.rs | 97 ++++ src/backend/drm/legacy/surface.rs | 264 +++++++++ src/backend/drm/mod.rs | 747 +++----------------------- 16 files changed, 1811 insertions(+), 1229 deletions(-) delete mode 100644 src/backend/drm/backend.rs create mode 100644 src/backend/drm/egl/error.rs create mode 100644 src/backend/drm/egl/mod.rs create mode 100644 src/backend/drm/egl/session.rs create mode 100644 src/backend/drm/egl/surface.rs create mode 100644 src/backend/drm/gbm/egl.rs create mode 100644 src/backend/drm/gbm/error.rs create mode 100644 src/backend/drm/gbm/mod.rs create mode 100644 src/backend/drm/gbm/session.rs create mode 100644 src/backend/drm/gbm/surface.rs rename src/backend/drm/{ => legacy}/error.rs (76%) create mode 100644 src/backend/drm/legacy/mod.rs create mode 100644 src/backend/drm/legacy/session.rs create mode 100644 src/backend/drm/legacy/surface.rs diff --git a/Cargo.toml b/Cargo.toml index ce3a8db..b65e227 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ slog-stdlog = "3.0.2" libloading = "0.4.0" wayland-client = { version = "0.21.1", features = ["egl"], optional = true } winit = { version = "0.18.0", optional = true } -drm = { version = "^0.3.1", optional = true } +drm = { version = "^0.3.4", optional = true } gbm = { version = "^0.4.0", optional = true, default-features = false, features = ["drm-support"] } glium = { version = "0.19.0", optional = true, default-features = false } input = { version = "0.4.0", optional = true } @@ -37,9 +37,12 @@ lazy_static = "1.0.0" gl_generator = { version = "0.9", optional = true } [features] -default = ["backend_winit", "backend_drm", "backend_libinput", "backend_udev", "renderer_glium", "xwayland"] +default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "renderer_glium", "xwayland"] backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl"] -backend_drm = ["drm", "backend_egl"] +backend_drm = ["drm"] +backend_drm_legacy = ["backend_drm"] +backend_drm_gbm = ["backend_drm", "gbm"] +backend_drm_egl = ["backend_drm", "backend_egl"] backend_egl = ["gl_generator"] backend_libinput = ["input"] backend_session = [] diff --git a/src/backend/drm/backend.rs b/src/backend/drm/backend.rs deleted file mode 100644 index 6abd4bb..0000000 --- a/src/backend/drm/backend.rs +++ /dev/null @@ -1,537 +0,0 @@ -use super::{error::*, DevPath}; -use backend::graphics::{ - egl::{ - error::Result as EGLResult, - native::{Gbm, GbmSurfaceArguments}, - wayland::{EGLDisplay, EGLWaylandExtensions}, - EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError, - }, - GraphicsBackend, -}; -use drm::{ - control::{connector, crtc, encoder, framebuffer, Device, Mode, ResourceInfo}, - Device as BasicDevice, -}; -use gbm::{ - BufferObject, BufferObjectFlags, Device as GbmDevice, Format as GbmFormat, Surface as GbmSurface, - SurfaceBufferHandle, -}; -use image::{ImageBuffer, Rgba}; -use nix::libc::c_void; -use std::{ - cell::Cell, - os::unix::io::{AsRawFd, RawFd}, - rc::{Rc, Weak}, -}; -use wayland_server::Display; - -/// Backend based on a `DrmDevice` and a given crtc -pub struct DrmBackend { - backend: Rc>, - surface: EGLSurface>, - mode: Mode, - connectors: Vec, -} - -pub(crate) struct DrmBackendInternal { - pub(crate) context: Rc, GbmDevice>>, - pub(crate) cursor: Cell<(BufferObject<()>, (u32, u32))>, - current_frame_buffer: Cell, - front_buffer: Cell>, - next_buffer: Cell>>, - crtc: crtc::Handle, - logger: ::slog::Logger, -} - -impl DrmBackend { - pub(crate) fn new( - context: Rc, GbmDevice>>, - crtc: crtc::Handle, - mode: Mode, - connectors: Vec, - log: ::slog::Logger, - ) -> Result { - // logger already initialized by the DrmDevice - info!(log, "Initializing DrmBackend"); - - let (w, h) = mode.size(); - - debug!(log, "Creating Surface"); - let surface = context - .create_surface(GbmSurfaceArguments { - size: (w as u32, h as u32), - format: GbmFormat::XRGB8888, - flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, - }).chain_err(|| ErrorKind::GbmInitFailed)?; - - // make it active for the first `crtc::set` - // (which is needed before the first page_flip) - unsafe { surface.make_current().chain_err(|| ErrorKind::FailedToSwap)? }; - surface.swap_buffers().chain_err(|| ErrorKind::FailedToSwap)?; - - // init the first screen - // (must be done before calling page_flip for the first time) - let mut front_bo = surface - .lock_front_buffer() - .chain_err(|| ErrorKind::FailedToSwap)?; - - debug!(log, "FrontBuffer color format: {:?}", front_bo.format()); - - // we need a framebuffer for the front buffer - let fb = framebuffer::create(&*context, &*front_bo).chain_err(|| { - ErrorKind::DrmDev(format!("Error creating framebuffer on {:?}", context.dev_path())) - })?; - - debug!(log, "Initialize screen"); - crtc::set(&*context, crtc, fb.handle(), &connectors, (0, 0), Some(mode)).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error setting crtc {:?} on {:?}", - crtc, - context.dev_path() - )) - })?; - front_bo.set_userdata(fb).unwrap(); - - let cursor = Cell::new(( - context - .create_buffer_object( - 1, - 1, - GbmFormat::ARGB8888, - BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, - ).chain_err(|| ErrorKind::GbmInitFailed)?, - (0, 0), - )); - - Ok(DrmBackend { - backend: Rc::new(DrmBackendInternal { - context, - cursor, - current_frame_buffer: Cell::new(fb), - front_buffer: Cell::new(front_bo), - next_buffer: Cell::new(None), - crtc, - logger: log, - }), - surface, - mode, - connectors, - }) - } - - pub(crate) fn weak(&self) -> Weak> { - Rc::downgrade(&self.backend) - } - - /// Add a connector to backend - /// - /// # Errors - /// - /// Errors if the new connector does not support the currently set `Mode` - pub fn add_connector(&mut self, connector: connector::Handle) -> Result<()> { - let info = connector::Info::load_from_device(&*self.backend.context, connector).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading connector info on {:?}", - self.backend.context.dev_path() - )) - })?; - - // check if the connector can handle the current mode - if info.modes().contains(&self.mode) { - // check if there is a valid encoder - let encoders = info - .encoders() - .iter() - .map(|encoder| { - encoder::Info::load_from_device(&*self.backend.context, *encoder).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading encoder info on {:?}", - self.backend.context.dev_path() - )) - }) - }).collect::>>()?; - - // and if any encoder supports the selected crtc - let resource_handles = self.backend.context.resource_handles().chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading resources on {:?}", - self.backend.context.dev_path() - )) - })?; - if !encoders - .iter() - .map(|encoder| encoder.possible_crtcs()) - .all(|crtc_list| { - resource_handles - .filter_crtcs(crtc_list) - .contains(&self.backend.crtc) - }) { - bail!(ErrorKind::NoSuitableEncoder(info, self.backend.crtc)); - } - - info!( - self.backend.logger, - "Adding new connector: {:?}", - info.connector_type() - ); - self.connectors.push(connector); - Ok(()) - } else { - bail!(ErrorKind::ModeNotSuitable(self.mode)) - } - } - - /// Returns the currently set connectors - pub fn used_connectors(&self) -> &[connector::Handle] { - &*self.connectors - } - - /// Removes a currently set connector - pub fn remove_connector(&mut self, connector: connector::Handle) { - if let Ok(info) = connector::Info::load_from_device(&*self.backend.context, connector) { - info!( - self.backend.logger, - "Removing connector: {:?}", - info.connector_type() - ); - } else { - info!(self.backend.logger, "Removing unknown connector"); - } - - self.connectors.retain(|x| *x != connector); - } - - /// Gets the currently used mode - pub fn current_mode(&self) -> Mode { - self.mode - } - - /// Changes the currently set mode - /// - /// # Errors - /// - /// This will fail if not all set connectors support the new `Mode`. - /// Several internal resources will need to be recreated to fit the new `Mode`. - /// Other errors might occur. - pub fn use_mode(&mut self, mode: Mode) -> Result<()> { - // check the connectors - for connector in &self.connectors { - if !connector::Info::load_from_device(&*self.backend.context, *connector) - .chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading connector info on {:?}", - self.backend.context.dev_path() - )) - })?.modes() - .contains(&mode) - { - bail!(ErrorKind::ModeNotSuitable(mode)); - } - } - - info!(self.backend.logger, "Setting new mode: {:?}", mode.name()); - let (w, h) = mode.size(); - - // Recreate the surface and the related resources to match the new - // resolution. - debug!( - self.backend.logger, - "Reinitializing surface for new mode: {}:{}", w, h - ); - let surface = self - .backend - .context - .create_surface(GbmSurfaceArguments { - size: (w as u32, h as u32), - format: GbmFormat::XRGB8888, - flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, - }).chain_err(|| ErrorKind::GbmInitFailed)?; - - // make it active for the first `crtc::set` - // (which is needed before the first page_flip) - unsafe { surface.make_current().chain_err(|| ErrorKind::FailedToSwap)? }; - surface.swap_buffers().chain_err(|| ErrorKind::FailedToSwap)?; - - // Clean up next_buffer - { - if let Some(mut old_bo) = self.backend.next_buffer.take() { - if let Ok(Some(fb)) = old_bo.take_userdata() { - if let Err(err) = framebuffer::destroy(&*self.backend.context, fb.handle()) { - warn!( - self.backend.logger, - "Error releasing old back_buffer framebuffer: {:?}", err - ); - } - } - } - } - - // Cleanup front_buffer and init the first screen on the new front_buffer - // (must be done before calling page_flip for the first time) - let mut old_front_bo = self.backend.front_buffer.replace({ - let mut front_bo = surface - .lock_front_buffer() - .chain_err(|| ErrorKind::FailedToSwap)?; - - debug!( - self.backend.logger, - "FrontBuffer color format: {:?}", - front_bo.format() - ); - - // we also need a new framebuffer for the front buffer - let dev_path = self.backend.context.dev_path(); - let fb = framebuffer::create(&*self.backend.context, &*front_bo) - .chain_err(|| ErrorKind::DrmDev(format!("Error creating framebuffer on {:?}", dev_path)))?; - - front_bo.set_userdata(fb).unwrap(); - - debug!(self.backend.logger, "Setting screen"); - crtc::set( - &*self.backend.context, - self.backend.crtc, - fb.handle(), - &self.connectors, - (0, 0), - Some(mode), - ).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error setting crtc {:?} on {:?}", - self.backend.crtc, - self.backend.context.dev_path() - )) - })?; - - front_bo - }); - if let Ok(Some(fb)) = old_front_bo.take_userdata() { - if let Err(err) = framebuffer::destroy(&*self.backend.context, fb.handle()) { - warn!( - self.backend.logger, - "Error releasing old front_buffer framebuffer: {:?}", err - ); - } - } - - // Drop the old surface after cleanup - self.surface = surface; - self.mode = mode; - Ok(()) - } - - /// Returns the crtc id used by this backend - pub fn crtc(&self) -> crtc::Handle { - self.backend.crtc - } -} - -impl DrmBackendInternal { - pub(crate) fn unlock_buffer(&self) { - // after the page swap is finished we need to release the rendered buffer. - // this is called from the PageFlipHandler - if let Some(next_buffer) = self.next_buffer.replace(None) { - trace!(self.logger, "Releasing old front buffer"); - self.front_buffer.set(next_buffer); - // drop and release the old buffer - } - } - - pub(crate) fn page_flip( - &self, - fb: Option<&framebuffer::Info>, - ) -> ::std::result::Result<(), SwapBuffersError> { - trace!(self.logger, "Queueing Page flip"); - - let fb = *fb.unwrap_or(&self.current_frame_buffer.get()); - - // and flip - crtc::page_flip( - &*self.context, - self.crtc, - fb.handle(), - &[crtc::PageFlipFlags::PageFlipEvent], - ).map_err(|_| SwapBuffersError::ContextLost)?; - - self.current_frame_buffer.set(fb); - - Ok(()) - } -} - -impl Drop for DrmBackend { - fn drop(&mut self) { - // Drop framebuffers attached to the userdata of the gbm surface buffers. - // (They don't implement drop, as they need the device) - if let Ok(Some(fb)) = { - if let Some(mut next) = self.backend.next_buffer.take() { - next.take_userdata() - } else if let Ok(mut next) = self.surface.lock_front_buffer() { - next.take_userdata() - } else { - Ok(None) - } - } { - // ignore failure at this point - let _ = framebuffer::destroy(&*self.backend.context, fb.handle()); - } - } -} - -impl Drop for DrmBackendInternal { - fn drop(&mut self) { - if let Ok(Some(fb)) = self.front_buffer.get_mut().take_userdata() { - // ignore failure at this point - let _ = framebuffer::destroy(&*self.context, fb.handle()); - } - - // ignore failure at this point - let _ = crtc::clear_cursor(&*self.context, self.crtc); - } -} - -impl GraphicsBackend for DrmBackend { - type CursorFormat = ImageBuffer, Vec>; - type Error = Error; - - fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { - trace!(self.backend.logger, "Move the cursor to {},{}", x, y); - crtc::move_cursor(&*self.backend.context, self.backend.crtc, (x as i32, y as i32)).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error moving cursor on {:?}", - self.backend.context.dev_path() - )) - }) - } - - fn set_cursor_representation( - &self, - buffer: &ImageBuffer, Vec>, - hotspot: (u32, u32), - ) -> Result<()> { - let (w, h) = buffer.dimensions(); - debug!(self.backend.logger, "Importing cursor"); - - // import the cursor into a buffer we can render - let mut cursor = self - .backend - .context - .create_buffer_object( - w, - h, - GbmFormat::ARGB8888, - BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, - ).chain_err(|| ErrorKind::GbmInitFailed)?; - cursor - .write(&**buffer) - .chain_err(|| ErrorKind::GbmInitFailed)? - .chain_err(|| ErrorKind::GbmInitFailed)?; - - trace!(self.backend.logger, "Setting the new imported cursor"); - - // and set it - if crtc::set_cursor2( - &*self.backend.context, - self.backend.crtc, - &cursor, - (hotspot.0 as i32, hotspot.1 as i32), - ).is_err() - { - crtc::set_cursor(&*self.backend.context, self.backend.crtc, &cursor).chain_err(|| { - ErrorKind::DrmDev(format!( - "Failed to set cursor on {:?}", - self.backend.context.dev_path() - )) - })?; - } - - // and store it - self.backend.cursor.set((cursor, hotspot)); - Ok(()) - } -} - -impl EGLGraphicsBackend for DrmBackend { - fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { - let res = { - let nb = self.backend.next_buffer.take(); - let res = nb.is_some(); - self.backend.next_buffer.set(nb); - res - }; - if res { - // We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done - warn!( - self.backend.logger, - "Tried to swap a DrmBackend with a queued flip" - ); - return Err(SwapBuffersError::AlreadySwapped); - } - - // flip normally - self.surface.swap_buffers()?; - - // supporting only one buffer would cause a lot of inconvinience and - // would most likely result in a lot of flickering. - // neither weston, wlc or wlroots bother with that as well. - // so we just assume we got at least two buffers to do flipping. - let mut next_bo = self - .surface - .lock_front_buffer() - .expect("Surface only has one front buffer. Not supported by smithay"); - - // create a framebuffer if the front buffer does not have one already - // (they are reused by gbm) - let maybe_fb = next_bo - .userdata() - .map_err(|_| SwapBuffersError::ContextLost)? - .cloned(); - let fb = if let Some(info) = maybe_fb { - info - } else { - let fb = framebuffer::create(&*self.backend.context, &*next_bo) - .map_err(|_| SwapBuffersError::ContextLost)?; - next_bo.set_userdata(fb).unwrap(); - fb - }; - self.backend.next_buffer.set(Some(next_bo)); - - self.backend.page_flip(Some(&fb)) - } - - unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { - self.backend.context.get_proc_address(symbol) - } - - fn get_framebuffer_dimensions(&self) -> (u32, u32) { - let (w, h) = self.mode.size(); - (w as u32, h as u32) - } - - fn is_current(&self) -> bool { - self.backend.context.is_current() && self.surface.is_current() - } - - unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> { - self.surface.make_current() - } - - fn get_pixel_format(&self) -> PixelFormat { - self.backend.context.get_pixel_format() - } -} - -// for users convenience -impl AsRawFd for DrmBackend { - fn as_raw_fd(&self) -> RawFd { - self.backend.context.as_raw_fd() - } -} - -impl BasicDevice for DrmBackend {} -impl Device for DrmBackend {} - -impl EGLWaylandExtensions for DrmBackend { - fn bind_wl_display(&self, display: &Display) -> EGLResult { - self.backend.context.bind_wl_display(display) - } -} diff --git a/src/backend/drm/egl/error.rs b/src/backend/drm/egl/error.rs new file mode 100644 index 0000000..07f0e94 --- /dev/null +++ b/src/backend/drm/egl/error.rs @@ -0,0 +1,19 @@ +//! +//! Errors thrown by the `DrmDevice` and `DrmBackend` +//! + +use backend::egl::error as egl; + +error_chain! { + errors { + #[doc = "Underlying backend failed"] + UnderlyingBackendError { + description("The underlying backend reported an error"), + display("The underlying backend reported an error"), + } + } + + links { + EGL(egl::Error, egl::ErrorKind) #[doc = "EGL error"]; + } +} diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs new file mode 100644 index 0000000..6f08942 --- /dev/null +++ b/src/backend/drm/egl/mod.rs @@ -0,0 +1,172 @@ +use drm::control::{crtc, Mode}; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::{Rc, Weak}; +use std::os::unix::io::{AsRawFd, RawFd}; +use wayland_server::Display; + +use backend::egl::{EGLContext, EGLGraphicsBackend, EGLDisplay}; +use backend::egl::context::GlAttributes; +use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; +use backend::egl::error::Result as EGLResult; +use super::{Device, Surface, DeviceHandler}; + +pub mod error; +use self::error::*; + +mod surface; +pub use self::surface::*; + +#[cfg(feature = "backend_session")] +pub mod session; + +/// Representation of an open gbm device to create rendering backends +pub struct EglDevice::Surface> + 'static, D: Device + NativeDisplay + 'static> + where ::Surface: NativeSurface +{ + dev: Rc>>, + backends: Rc>>>>, + logger: ::slog::Logger, +} + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> AsRawFd for EglDevice + where ::Surface: NativeSurface +{ + fn as_raw_fd(&self) -> RawFd { + self.dev.borrow().as_raw_fd() + } +} + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EglDevice + where ::Surface: NativeSurface +{ + /// Create a new `EglGbmDrmDevice` from an open drm node + /// + /// Returns an error if the file is no valid drm node or context creation was not + /// successful. + pub fn new(dev: D, logger: L) -> Result + where + L: Into>, + { + EglDevice::new_with_gl_attr( + dev, + GlAttributes { + version: None, + profile: None, + debug: cfg!(debug_assertions), + vsync: true, + }, + logger, + ) + } + + /// Create a new `EglGbmDrmDevice` from an open `RawDevice` and given `GlAttributes` + /// + /// Returns an error if the file is no valid drm node or context creation was not + /// successful. + pub fn new_with_gl_attr(mut dev: D, attributes: GlAttributes, logger: L) -> Result + where + L: Into>, + { + let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_egl")); + + dev.clear_handler(); + + debug!(log, "Creating egl context from device"); + Ok(EglDevice { + // Open the gbm device from the drm device and create a context based on that + dev: Rc::new(RefCell::new(EGLContext::new( + dev, + attributes, + Default::default(), + log.clone(), + ).map_err(Error::from)? + )), + backends: Rc::new(RefCell::new(HashMap::new())), + logger: log, + }) + } +} + +struct InternalDeviceHandler::Surface> + 'static, D: Device + NativeDisplay + 'static> + where ::Surface: NativeSurface +{ + handler: Box> + 'static>, + backends: Weak>>>>, + logger: ::slog::Logger, +} + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> DeviceHandler for InternalDeviceHandler + where + >::Arguments: From<(crtc::Handle, Mode, <::Surface as Surface>::Connectors)>, + ::Surface: NativeSurface, +{ + type Device=D; + + fn vblank(&mut self, surface: &::Surface) { + if let Some(backends) = self.backends.upgrade() { + if let Some(surface) = backends.borrow().get(&surface.crtc()) { + if let Some(surface) = surface.upgrade() { + self.handler.vblank(&*surface); + } + } else { + warn!(self.logger, "Surface ({:?}) not managed by egl, event not handled.", surface.crtc()); + } + } + } + fn error(&mut self, error: <::Surface as Surface>::Error) { + self.handler.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) + } +} + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Device for EglDevice + where + >::Arguments: From<(crtc::Handle, Mode, <::Surface as Surface>::Connectors)>, + ::Surface: NativeSurface, +{ + type Surface = EglSurface; + type Return = Rc>; + + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { + self.dev.borrow_mut().set_handler(InternalDeviceHandler { + handler: Box::new(handler), + backends: Rc::downgrade(&self.backends), + logger: self.logger.clone(), + }); + } + + fn clear_handler(&mut self) { + self.dev.borrow_mut().clear_handler() + } + + fn create_surface( + &mut self, + crtc: crtc::Handle, + mode: Mode, + connectors: impl Into<<::Surface as Surface>::Connectors>, + ) -> Result>> { + info!(self.logger, "Initializing EglSurface"); + + let surface = self.dev.borrow_mut().create_surface((crtc, mode, connectors.into()).into())?; + + let backend = Rc::new(EglSurface { + dev: self.dev.clone(), + surface, + }); + self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); + Ok(backend) + } + + + fn process_events(&mut self) { + self.dev.borrow_mut().process_events() + } +} + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EGLGraphicsBackend for EglDevice + where ::Surface: NativeSurface +{ + fn bind_wl_display(&self, display: &Display) -> EGLResult { + self.dev.borrow().bind_wl_display(display) + } +} \ No newline at end of file diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs new file mode 100644 index 0000000..f440544 --- /dev/null +++ b/src/backend/drm/egl/session.rs @@ -0,0 +1,35 @@ +use std::os::unix::io::RawFd; + +use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; +use backend::session::{AsSessionObserver, SessionObserver}; +use backend::drm::Device; +use super::{EglDevice}; + +/// `SessionObserver` linked to the `DrmDevice` it was created from. +pub struct EglDeviceObserver { + observer: S, +} + +impl< + S: SessionObserver + 'static, + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + AsSessionObserver + 'static, +> AsSessionObserver> for EglDevice + where ::Surface: NativeSurface +{ + fn observer(&mut self) -> EglDeviceObserver { + EglDeviceObserver { + observer: (**self.dev.borrow_mut()).observer(), + } + } +} + +impl SessionObserver for EglDeviceObserver { + fn pause(&mut self, devnum: Option<(u32, u32)>) { + self.observer.pause(devnum); + } + + fn activate(&mut self, devnum: Option<(u32, u32, Option)>) { + self.observer.activate(devnum); + } +} diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs new file mode 100644 index 0000000..3d62af6 --- /dev/null +++ b/src/backend/drm/egl/surface.rs @@ -0,0 +1,110 @@ +use drm::control::{connector, crtc, Mode}; +use nix::libc::c_void; +use std::cell::RefCell; +use std::rc::Rc; + +use backend::drm::{Device, Surface}; +use backend::egl::{EGLContext, EGLSurface}; +use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; +use backend::graphics::{CursorBackend, SwapBuffersError}; +use backend::graphics::gl::{GLGraphicsBackend, PixelFormat}; +use super::error::*; + +pub struct EglSurface::Surface> + 'static, D: Device + NativeDisplay + 'static> + where ::Surface: NativeSurface +{ + pub(in super) dev: Rc>>, + pub(in super) surface: EGLSurface, +} + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Surface for EglSurface + where ::Surface: NativeSurface +{ + type Error = Error; + type Connectors = <::Surface as Surface>::Connectors; + + fn crtc(&self) -> crtc::Handle { + (*self.surface).crtc() + } + + fn current_connectors(&self) -> Self::Connectors { + self.surface.current_connectors() + } + + fn pending_connectors(&self) -> Self::Connectors { + self.surface.pending_connectors() + } + + fn add_connector(&self, connector: connector::Handle) -> Result<()> { + self.surface.add_connector(connector).chain_err(|| ErrorKind::UnderlyingBackendError) + } + + fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + self.surface.remove_connector(connector).chain_err(|| ErrorKind::UnderlyingBackendError) + } + + fn current_mode(&self) -> Mode { + self.surface.current_mode() + } + + fn pending_mode(&self) -> Mode { + self.surface.pending_mode() + } + + fn use_mode(&self, mode: Mode) -> Result<()> { + self.surface.use_mode(mode).chain_err(|| ErrorKind::UnderlyingBackendError) + } +} + +impl<'a, B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static> CursorBackend<'a> for EglSurface + where + D: CursorBackend<'a>, + ::Surface: NativeSurface +{ + type CursorFormat = >::CursorFormat; + type Error = >::Error; + + fn set_cursor_position(&self, x: u32, y: u32) -> ::std::result::Result<(), Self::Error> { + self.dev.borrow().set_cursor_position(x, y) + } + + fn set_cursor_representation<'b>( + &'b self, + buffer: Self::CursorFormat, + hotspot: (u32, u32), + ) -> ::std::result::Result<(), Self::Error> + where 'a: 'b + { + let dev = self.dev.borrow(); + dev.set_cursor_representation(buffer, hotspot) + } +} + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> GLGraphicsBackend for EglSurface + where ::Surface: NativeSurface +{ + fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { + self.surface.swap_buffers() + } + + unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { + self.dev.borrow().get_proc_address(symbol) + } + + fn get_framebuffer_dimensions(&self) -> (u32, u32) { + let (w, h) = self.pending_mode().size(); + (w as u32, h as u32) + } + + fn is_current(&self) -> bool { + self.dev.borrow().is_current() && self.surface.is_current() + } + + unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> { + self.surface.make_current() + } + + fn get_pixel_format(&self) -> PixelFormat { + self.dev.borrow().get_pixel_format() + } +} \ No newline at end of file diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs new file mode 100644 index 0000000..915df9b --- /dev/null +++ b/src/backend/drm/gbm/egl.rs @@ -0,0 +1,118 @@ +use backend::drm::{RawDevice, Device, RawSurface, Surface}; +use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; +use backend::egl::error::{Result as EglResult}; +use backend::egl::ffi; +use backend::graphics::SwapBuffersError; + +use super::{GbmDevice, GbmSurface}; +use super::error::{Error, Result}; + +use drm::control::{crtc, Device as ControlDevice, Mode}; +use gbm::AsRaw; +use std::marker::PhantomData; +use std::rc::Rc; +use std::ptr; + +/// Gbm backend type +pub struct Gbm +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + _userdata: PhantomData, +} + +impl Backend for Gbm +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + type Surface = Rc>; + + unsafe fn get_display( + display: ffi::NativeDisplayType, + has_dp_extension: F, + log: ::slog::Logger, + ) -> ffi::egl::types::EGLDisplay + where + F: Fn(&str) -> bool, + { + if has_dp_extension("EGL_KHR_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() { + trace!(log, "EGL Display Initialization via EGL_KHR_platform_gbm"); + ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_KHR, display as *mut _, ptr::null()) + } else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplayEXT::is_loaded() { + trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm"); + ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null()) + } else if has_dp_extension("EGL_MESA_platform_gbm") && ffi::egl::GetPlatformDisplay::is_loaded() { + trace!(log, "EGL Display Initialization via EGL_MESA_platform_gbm"); + ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_GBM_MESA, display as *mut _, ptr::null()) + } else { + trace!(log, "Default EGL Display Initialization via GetDisplay"); + ffi::egl::GetDisplay(display as *mut _) + } + } +} + +/// Arguments necessary to construct a `GbmSurface` +pub struct SurfaceArguments +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + /// Crtc + pub crtc: crtc::Handle, + /// Mode + pub mode: Mode, + /// Connectors + pub connectors: as Surface>::Connectors, +} + +impl From<(crtc::Handle, Mode, as Surface>::Connectors)> for SurfaceArguments +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + fn from((crtc, mode, connectors): (crtc::Handle, Mode, as Surface>::Connectors)) -> Self { + SurfaceArguments { + crtc, + mode, + connectors, + } + } +} + +unsafe impl NativeDisplay> for GbmDevice +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + type Arguments = SurfaceArguments; + type Error = Error; + + fn is_backend(&self) -> bool { + true + } + + fn ptr(&self) -> EglResult { + Ok(self.dev.borrow().as_raw() as *const _) + } + + fn create_surface(&mut self, args: SurfaceArguments) -> Result>> { + Device::create_surface(self, args.crtc, args.mode, args.connectors) + } +} + +unsafe impl NativeSurface for Rc> +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + fn ptr(&self) -> ffi::NativeWindowType { + self.surface.borrow().as_raw() as *const _ + } + + fn swap_buffers(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> + where + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + { + if ::std::borrow::Borrow::borrow(&self.crtc).commit_pending() { + self.recreate(flip).map_err(|_| SwapBuffersError::ContextLost) + } else { + self.page_flip(flip) + } + } +} \ No newline at end of file diff --git a/src/backend/drm/gbm/error.rs b/src/backend/drm/gbm/error.rs new file mode 100644 index 0000000..e2fba7e --- /dev/null +++ b/src/backend/drm/gbm/error.rs @@ -0,0 +1,47 @@ +//! +//! Errors thrown by the `DrmDevice` and `DrmBackend` +//! + +error_chain! { + errors { + #[doc = "Creation of gbm device failed"] + InitFailed { + description("Creation of gbm device failed"), + display("Creation of gbm device failed"), + } + + #[doc = "Creation of gbm surface failed"] + SurfaceCreationFailed { + description("Creation of gbm surface failed"), + display("Creation of gbm surface failed"), + } + + #[doc = "Creation of gbm buffer object failed"] + BufferCreationFailed { + description("Creation of gbm buffer object failed"), + display("Creation of gbm buffer object failed"), + } + + #[doc = "Writing to gbm buffer failed"] + BufferWriteFailed { + description("Writing to gbm buffer failed"), + display("Writing to gbm buffer failed"), + } + + #[doc = "Lock of gbm surface front buffer failed"] + FrontBufferLockFailed { + description("Lock of gbm surface front buffer failed"), + display("Lock of gbm surface front buffer failed"), + } + + #[doc = "Underlying backend failed"] + UnderlyingBackendError { + description("The underlying backend reported an error"), + display("The underlying backend reported an error"), + } + } + + foreign_links { + FailedToSwap(::backend::graphics::SwapBuffersError); + } +} diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs new file mode 100644 index 0000000..43f501e --- /dev/null +++ b/src/backend/drm/gbm/mod.rs @@ -0,0 +1,191 @@ +use super::{Device, RawDevice, Surface, DeviceHandler}; + +use drm::control::{crtc, framebuffer, Device as ControlDevice, Mode}; +use gbm::{self, Format as GbmFormat, BufferObjectFlags}; + +use std::cell::{Cell, RefCell}; +use std::collections::HashMap; +use std::rc::{Rc, Weak}; +use std::sync::{Once, ONCE_INIT}; +use std::os::unix::io::{AsRawFd, RawFd}; + +pub mod error; +use self::error::*; + +mod surface; +pub use self::surface::GbmSurface; + +pub mod egl; + +#[cfg(feature = "backend_session")] +pub mod session; + +static LOAD: Once = ONCE_INIT; + +/// Representation of an open gbm device to create rendering backends +pub struct GbmDevice +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + pub(in self) dev: Rc>>, + backends: Rc>>>>, + logger: ::slog::Logger, +} + +impl GbmDevice +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + /// Create a new `GbmDevice` from an open drm node + /// + /// Returns an error if the file is no valid drm node or context creation was not + /// successful. + pub fn new(mut dev: D, logger: L) -> Result + where + L: Into>, + { + /* GBM will load a dri driver, but even though they need symbols from + * libglapi, in some version of Mesa they are not linked to it. Since + * only the gl-renderer module links to it, these symbols won't be + * globally available, and loading the DRI driver fails. + * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. + */ + LOAD.call_once(|| unsafe { + nix::libc::dlopen( + "libglapi.so.0".as_ptr() as *const _, + nix::libc::RTLD_LAZY | nix::libc::RTLD_GLOBAL, + ); + }); + + let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_gbm")); + + dev.clear_handler(); + + debug!(log, "Creating gbm device"); + Ok(GbmDevice { + // Open the gbm device from the drm device + dev: Rc::new(RefCell::new(gbm::Device::new(dev).chain_err(|| ErrorKind::InitFailed)?)), + backends: Rc::new(RefCell::new(HashMap::new())), + logger: log, + }) + } +} + +struct InternalDeviceHandler +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + handler: Box> + 'static>, + backends: Weak>>>>, + logger: ::slog::Logger, +} + +impl DeviceHandler for InternalDeviceHandler +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + type Device = D; + + fn vblank(&mut self, surface: &::Surface) { + if let Some(backends) = self.backends.upgrade() { + if let Some(surface) = backends.borrow().get(&surface.crtc()) { + if let Some(surface) = surface.upgrade() { + surface.unlock_buffer(); + self.handler.vblank(&*surface); + } + } else { + warn!(self.logger, "Surface ({:?}) not managed by gbm, event not handled.", surface.crtc()); + } + } + } + fn error(&mut self, error: <::Surface as Surface>::Error) { + self.handler.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) + } +} + +impl Device for GbmDevice +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + type Surface = GbmSurface; + type Return = Rc>; + + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { + self.dev.borrow_mut().set_handler(InternalDeviceHandler { + handler: Box::new(handler), + backends: Rc::downgrade(&self.backends), + logger: self.logger.clone(), + }); + } + + fn clear_handler(&mut self) { + self.dev.borrow_mut().clear_handler(); + } + + fn create_surface( + &mut self, + crtc: crtc::Handle, + mode: Mode, + connectors: impl Into<::Connectors> + ) -> Result>> { + info!(self.logger, "Initializing GbmSurface"); + + let (w, h) = mode.size(); + let surface = self.dev.borrow().create_surface( + w as u32, + h as u32, + GbmFormat::XRGB8888, + BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, + ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; + + // init the first screen + // (must be done before calling page_flip for the first time) + let mut front_bo = surface + .lock_front_buffer() + .chain_err(|| ErrorKind::FrontBufferLockFailed)?; + + debug!(self.logger, "FrontBuffer color format: {:?}", front_bo.format()); + + // we need a framebuffer for the front buffer + let fb = framebuffer::create(&*self.dev.borrow(), &*front_bo).chain_err(|| ErrorKind::UnderlyingBackendError)?; + front_bo.set_userdata(fb).unwrap(); + + let cursor = Cell::new(( + self.dev.borrow() + .create_buffer_object( + 1, + 1, + GbmFormat::ARGB8888, + BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, + ).chain_err(|| ErrorKind::BufferCreationFailed)?, + (0, 0), + )); + + let backend = Rc::new(GbmSurface { + dev: self.dev.clone(), + surface: RefCell::new(surface), + crtc: Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) + .chain_err(|| ErrorKind::UnderlyingBackendError)?, + cursor, + current_frame_buffer: Cell::new(fb), + front_buffer: Cell::new(front_bo), + next_buffer: Cell::new(None), + logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))), + }); + self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); + Ok(backend) + } + + fn process_events(&mut self) { + self.dev.borrow_mut().process_events() + } +} + +impl AsRawFd for GbmDevice +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + fn as_raw_fd(&self) -> RawFd { + self.dev.borrow().as_raw_fd() + } +} \ No newline at end of file diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs new file mode 100644 index 0000000..1a84c41 --- /dev/null +++ b/src/backend/drm/gbm/session.rs @@ -0,0 +1,89 @@ +use drm::control::{crtc, Device as ControlDevice, ResourceInfo}; +use gbm::BufferObject; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::{Rc, Weak}; +use std::os::unix::io::RawFd; + +use backend::session::{AsSessionObserver, SessionObserver}; +use backend::drm::{Device, RawDevice, RawSurface}; +use super::{GbmDevice, GbmSurface}; + +/// `SessionObserver` linked to the `DrmDevice` it was created from. +pub struct GbmDeviceObserver< + S: SessionObserver + 'static, + D: RawDevice + ControlDevice + AsSessionObserver + 'static, +> +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + observer: S, + backends: Weak>>>>, + logger: ::slog::Logger, +} + +impl< + S: SessionObserver + 'static, + D: RawDevice + ControlDevice + AsSessionObserver + 'static, +> AsSessionObserver> for GbmDevice +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + fn observer(&mut self) -> GbmDeviceObserver { + GbmDeviceObserver { + observer: (**self.dev.borrow_mut()).observer(), + backends: Rc::downgrade(&self.backends), + logger: self.logger.clone(), + } + } +} + +impl< + S: SessionObserver + 'static, + D: RawDevice + ControlDevice + AsSessionObserver + 'static, +> SessionObserver for GbmDeviceObserver +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + fn pause(&mut self, devnum: Option<(u32, u32)>) { + self.observer.pause(devnum); + } + + fn activate(&mut self, devnum: Option<(u32, u32, Option)>) { + self.observer.activate(devnum); + let mut crtcs = Vec::new(); + if let Some(backends) = self.backends.upgrade() { + for (crtc, backend) in backends.borrow().iter() { + if let Some(backend) = backend.upgrade() { + // restart rendering loop + if let Err(err) = + ::std::borrow::Borrow::borrow(&backend.crtc).page_flip(backend.current_frame_buffer.get().handle()) + { + warn!(self.logger, "Failed to restart rendering loop. Error: {}", err); + } + // reset cursor + { + let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) = + unsafe { &*backend.cursor.as_ptr() }; + if crtc::set_cursor2( + &*backend.dev.borrow(), + *crtc, + cursor, + ((*hotspot).0 as i32, (*hotspot).1 as i32), + ).is_err() + { + if let Err(err) = crtc::set_cursor(&*backend.dev.borrow(), *crtc, cursor) { + error!(self.logger, "Failed to reset cursor. Error: {}", err); + } + } + } + } else { + crtcs.push(*crtc); + } + } + for crtc in crtcs { + backends.borrow_mut().remove(&crtc); + } + } + } +} diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs new file mode 100644 index 0000000..c279a00 --- /dev/null +++ b/src/backend/drm/gbm/surface.rs @@ -0,0 +1,329 @@ +use super::error::*; +use super::super::{Device, RawDevice, Surface, RawSurface}; + +use drm::control::{crtc, connector, framebuffer, Mode, ResourceInfo}; +use gbm::{self, SurfaceBufferHandle, Format as GbmFormat, BufferObject, BufferObjectFlags}; +use image::{ImageBuffer, Rgba}; + +use std::cell::{Cell, RefCell}; +use std::rc::Rc; +use std::os::unix::io::AsRawFd; + +use backend::drm::legacy::{LegacyDrmDevice, LegacyDrmSurface}; +use backend::graphics::CursorBackend; +use backend::graphics::SwapBuffersError; + +pub struct GbmSurface +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + pub(in super) dev: Rc>>, + pub(in super) surface: RefCell>, + pub(in super) crtc: ::Return, + pub(in super) cursor: Cell<(BufferObject<()>, (u32, u32))>, + pub(in super) current_frame_buffer: Cell, + pub(in super) front_buffer: Cell>, + pub(in super) next_buffer: Cell>>, + pub(in super) logger: ::slog::Logger, +} + +impl GbmSurface +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + pub(in super) fn unlock_buffer(&self) { + // after the page swap is finished we need to release the rendered buffer. + // this is called from the PageFlipHandler + if let Some(next_buffer) = self.next_buffer.replace(None) { + trace!(self.logger, "Releasing old front buffer"); + self.front_buffer.set(next_buffer); + // drop and release the old buffer + } + } + + pub fn page_flip(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> + where + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + { + let res = { + let nb = self.next_buffer.take(); + let res = nb.is_some(); + self.next_buffer.set(nb); + res + }; + if res { + // We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done + warn!( + self.logger, + "Tried to swap with an already queued flip" + ); + return Err(SwapBuffersError::AlreadySwapped); + } + + // flip normally + flip()?; + + // supporting only one buffer would cause a lot of inconvinience and + // would most likely result in a lot of flickering. + // neither weston, wlc or wlroots bother with that as well. + // so we just assume we got at least two buffers to do flipping. + let mut next_bo = self + .surface + .borrow() + .lock_front_buffer() + .expect("Surface only has one front buffer. Not supported by smithay"); + + // create a framebuffer if the front buffer does not have one already + // (they are reused by gbm) + let maybe_fb = next_bo + .userdata() + .map_err(|_| SwapBuffersError::ContextLost)? + .cloned(); + let fb = if let Some(info) = maybe_fb { + info + } else { + let fb = framebuffer::create(::std::borrow::Borrow::borrow(&self.crtc), &*next_bo) + .map_err(|_| SwapBuffersError::ContextLost)?; + next_bo.set_userdata(fb).unwrap(); + fb + }; + self.next_buffer.set(Some(next_bo)); + + trace!(self.logger, "Queueing Page flip"); + ::std::borrow::Borrow::borrow(&self.crtc).page_flip(fb.handle())?; + + self.current_frame_buffer.set(fb); + + Ok(()) + } + + pub fn recreate(&self, flip: F) -> Result<()> + where + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + { + let (w, h) = self.pending_mode().size(); + + // Recreate the surface and the related resources to match the new + // resolution. + debug!( + self.logger, + "Reinitializing surface for new mode: {}:{}", w, h + ); + let surface = self + .dev + .borrow_mut() + .create_surface( + w as u32, + h as u32, + GbmFormat::XRGB8888, + BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, + ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; + + flip()?; + + // Clean up next_buffer + { + if let Some(mut old_bo) = self.next_buffer.take() { + if let Ok(Some(fb)) = old_bo.take_userdata() { + if let Err(err) = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()) { + warn!( + self.logger, + "Error releasing old back_buffer framebuffer: {:?}", err + ); + } + } + } + } + + // Cleanup front_buffer and init the first screen on the new front_buffer + // (must be done before calling page_flip for the first time) + let mut old_front_bo = self.front_buffer.replace({ + let mut front_bo = surface + .lock_front_buffer() + .chain_err(|| ErrorKind::FrontBufferLockFailed)?; + + debug!( + self.logger, + "FrontBuffer color format: {:?}", + front_bo.format() + ); + + // we also need a new framebuffer for the front buffer + let fb = framebuffer::create(::std::borrow::Borrow::borrow(&self.crtc), &*front_bo) + .chain_err(|| ErrorKind::UnderlyingBackendError)?; + + ::std::borrow::Borrow::borrow(&self.crtc).commit(fb.handle()) + .chain_err(|| ErrorKind::UnderlyingBackendError)?; + + front_bo.set_userdata(fb).unwrap(); + front_bo + }); + if let Ok(Some(fb)) = old_front_bo.take_userdata() { + if let Err(err) = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()) { + warn!( + self.logger, + "Error releasing old front_buffer framebuffer: {:?}", err + ); + } + } + + // Drop the old surface after cleanup + *self.surface.borrow_mut() = surface; + + Ok(()) + } +} + +impl Surface for GbmSurface +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + type Connectors = <::Surface as Surface>::Connectors; + type Error = Error; + + fn crtc(&self) -> crtc::Handle { + ::std::borrow::Borrow::borrow(&self.crtc) + .crtc() + } + + fn current_connectors(&self) -> Self::Connectors { + ::std::borrow::Borrow::borrow(&self.crtc) + .current_connectors() + } + + fn pending_connectors(&self) -> Self::Connectors { + ::std::borrow::Borrow::borrow(&self.crtc) + .pending_connectors() + } + + fn add_connector(&self, connector: connector::Handle) -> Result<()> { + ::std::borrow::Borrow::borrow(&self.crtc) + .add_connector(connector) + .chain_err(|| ErrorKind::UnderlyingBackendError) + } + + fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + ::std::borrow::Borrow::borrow(&self.crtc) + .remove_connector(connector) + .chain_err(|| ErrorKind::UnderlyingBackendError) + } + + fn current_mode(&self) -> Mode { + ::std::borrow::Borrow::borrow(&self.crtc) + .current_mode() + } + + fn pending_mode(&self) -> Mode { + ::std::borrow::Borrow::borrow(&self.crtc) + .pending_mode() + } + + fn use_mode(&self, mode: Mode) -> Result<()> { + ::std::borrow::Borrow::borrow(&self.crtc) + .use_mode(mode) + .chain_err(|| ErrorKind::UnderlyingBackendError) + } +} + +// FIXME: +// +// Option 1: When there is GAT support, impl `GraphicsBackend` for `LegacyDrmBackend` +// using a new generic `B: Buffer` and use this: +/* +impl<'a, D: RawDevice + 'static> CursorBackend<'a> for GbmSurface +where + ::Return: ::std::borrow::Borrow<::Surface>, + ::Surface: CursorBackend<'a>, + <::Surface as CursorBackend<'a>>::CursorFormat: Buffer, + <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send +{ +*/ +// +// Option 2: When equality checks in where clauses are supported, we could at least do this: +/* +impl<'a, D: RawDevice + 'static> GraphicsBackend<'a> for GbmSurface +where + ::Return: ::std::borrow::Borrow<::Surface>, + ::Surface: CursorBackend<'a>, + <::Surface as CursorBackend<'a>>::CursorFormat=&'a Buffer, + <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send +{ +*/ +// But for now got to do this: + +impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface> { + type CursorFormat = &'a ImageBuffer, Vec>; + type Error = Error; + + fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { + ResultExt::chain_err( + ::std::borrow::Borrow::>>::borrow(&self.crtc) + .set_cursor_position(x, y), + || ErrorKind::UnderlyingBackendError) + } + + fn set_cursor_representation<'b>( + &'b self, + buffer: &ImageBuffer, Vec>, + hotspot: (u32, u32), + ) -> Result<()> + where 'a: 'b + { + let (w, h) = buffer.dimensions(); + debug!(self.logger, "Importing cursor"); + + // import the cursor into a buffer we can render + let mut cursor = self + .dev + .borrow_mut() + .create_buffer_object( + w, + h, + GbmFormat::ARGB8888, + BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, + ).chain_err(|| ErrorKind::BufferCreationFailed)?; + + cursor + .write(&**buffer) + .chain_err(|| ErrorKind::BufferWriteFailed)? + .chain_err(|| ErrorKind::BufferWriteFailed)?; + + trace!(self.logger, "Setting the new imported cursor"); + + ResultExt::chain_err( + ::std::borrow::Borrow::>>::borrow(&self.crtc) + .set_cursor_representation(&cursor, hotspot), + || ErrorKind::UnderlyingBackendError)?; + + // and store it + self.cursor.set((cursor, hotspot)); + Ok(()) + } +} + +impl Drop for GbmSurface +where + ::Return: ::std::borrow::Borrow<::Surface> +{ + fn drop(&mut self) { + // Drop framebuffers attached to the userdata of the gbm surface buffers. + // (They don't implement drop, as they need the device) + if let Ok(Some(fb)) = { + if let Some(mut next) = self.next_buffer.take() { + next.take_userdata() + } else if let Ok(mut next) = self.surface.borrow().lock_front_buffer() { + next.take_userdata() + } else { + Ok(None) + } + } { + // ignore failure at this point + let _ = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()); + } + + if let Ok(Some(fb)) = self.front_buffer.get_mut().take_userdata() { + // ignore failure at this point + let _ = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()); + } + } +} \ No newline at end of file diff --git a/src/backend/drm/error.rs b/src/backend/drm/legacy/error.rs similarity index 76% rename from src/backend/drm/error.rs rename to src/backend/drm/legacy/error.rs index 3c9b589..4e14eaf 100644 --- a/src/backend/drm/error.rs +++ b/src/backend/drm/legacy/error.rs @@ -1,8 +1,7 @@ //! -//! Errors thrown by the `DrmDevice` and `DrmBackend` +//! Errors thrown by the `LegacyDrmDevice` and `LegacyDrmSurface` //! -use backend::graphics::egl::error as egl; use drm::control::{connector, crtc, Mode}; error_chain! { @@ -23,18 +22,6 @@ error_chain! { description("Unable to determine device id of drm device"), } - #[doc = "Creation of gbm resource failed"] - GbmInitFailed { - description("Creation of gbm resource failed"), - display("Creation of gbm resource failed"), - } - - #[doc = "Swapping front buffers failed"] - FailedToSwap { - description("Swapping front buffers failed"), - display("Swapping front buffers failed"), - } - #[doc = "Device is currently paused"] DeviceInactive { description("Device is currently paused, operation rejected"), @@ -60,7 +47,7 @@ error_chain! { } } - links { - EGL(egl::Error, egl::ErrorKind) #[doc = "EGL error"]; + foreign_links { + FailedToSwap(::backend::graphics::SwapBuffersError) #[doc = "Swapping front buffers failed"]; } } diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs new file mode 100644 index 0000000..166e664 --- /dev/null +++ b/src/backend/drm/legacy/mod.rs @@ -0,0 +1,257 @@ +use super::{Device, RawDevice, Surface, DeviceHandler, DevPath}; + +use drm::Device as BasicDevice; +use drm::control::{crtc, connector, encoder, Device as ControlDevice, Mode, ResourceInfo}; +use nix::libc::dev_t; +use nix::sys::stat::fstat; + +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::rc::{Rc, Weak}; +use std::os::unix::io::{AsRawFd, RawFd}; +use std::sync::{Arc, RwLock}; +use std::sync::atomic::{AtomicBool, Ordering}; + +mod surface; +pub use self::surface::LegacyDrmSurface; +use self::surface::State; + +pub mod error; +use self::error::*; + +#[cfg(feature = "backend_session")] +pub mod session; + +pub struct LegacyDrmDevice { + dev: Rc>, + dev_id: dev_t, + priviledged: bool, + active: Arc, + old_state: HashMap)>, + backends: Rc>>>>, + handler: Option>>>>, + logger: ::slog::Logger, +} + +pub(in crate::backend::drm) struct Dev(A); +impl AsRawFd for Dev { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +impl BasicDevice for Dev {} +impl ControlDevice for Dev {} + +impl LegacyDrmDevice { + /// Create a new `LegacyDrmDevice` from an open drm node + /// + /// Returns an error if the file is no valid drm node or context creation was not + /// successful. + pub fn new(dev: A, logger: L) -> Result + where + L: Into>, + { + let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm")); + + let dev_id = fstat(dev.as_raw_fd()) + .chain_err(|| ErrorKind::UnableToGetDeviceId)? + .st_rdev; + + let mut drm = LegacyDrmDevice { + // Open the drm device and create a context based on that + dev: Rc::new(Dev(dev)), + dev_id, + priviledged: true, + active: Arc::new(AtomicBool::new(true)), + old_state: HashMap::new(), + backends: Rc::new(RefCell::new(HashMap::new())), + handler: None, + logger: log.clone(), + }; + + info!(log, "DrmDevice initializing"); + + // we want to modeset, so we better be the master, if we run via a tty session + if drm.set_master().is_err() { + warn!(log, "Unable to become drm master, assuming unpriviledged mode"); + drm.priviledged = false; + }; + + let res_handles = drm.resource_handles().chain_err(|| { + ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path())) + })?; + for &con in res_handles.connectors() { + let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path())) + })?; + if let Some(enc) = con_info.current_encoder() { + let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path())) + })?; + if let Some(crtc) = enc_info.current_crtc() { + let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", drm.dev_path())) + })?; + drm.old_state + .entry(crtc) + .or_insert((info, Vec::new())) + .1 + .push(con); + } + } + } + + Ok(drm) + } + + pub fn dev_id(&self) -> dev_t { + self.dev_id + } +} + +impl AsRawFd for LegacyDrmDevice { + fn as_raw_fd(&self) -> RawFd { + self.dev.0.as_raw_fd() + } +} + +impl BasicDevice for LegacyDrmDevice {} +impl ControlDevice for LegacyDrmDevice {} + +impl Device for LegacyDrmDevice { + type Surface = LegacyDrmSurface; + type Return = Rc>; + + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { + self.handler = Some(RefCell::new(Box::new(handler))); + } + + fn clear_handler(&mut self) { + let _ = self.handler.take(); + } + + fn create_surface( + &mut self, + crtc: crtc::Handle, + mode: Mode, + connectors: impl Into<::Connectors> + ) -> Result>> { + if self.backends.borrow().contains_key(&crtc) { + bail!(ErrorKind::CrtcAlreadyInUse(crtc)); + } + + if !self.active.load(Ordering::SeqCst) { + bail!(ErrorKind::DeviceInactive); + } + + let connectors: HashSet<_> = connectors.into(); + // check if we have an encoder for every connector and the mode mode + for connector in &connectors { + let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) + })?; + + // check the mode + if !con_info.modes().contains(&mode) { + bail!(ErrorKind::ModeNotSuitable(mode)); + } + + // check for every connector which encoders it does support + let encoders = con_info + .encoders() + .iter() + .map(|encoder| { + encoder::Info::load_from_device(self, *encoder).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) + }) + }).collect::>>()?; + + // and if any encoder supports the selected crtc + let resource_handles = self.resource_handles().chain_err(|| { + ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) + })?; + if !encoders + .iter() + .map(|encoder| encoder.possible_crtcs()) + .any(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&crtc)) + { + bail!(ErrorKind::NoSuitableEncoder(con_info, crtc)) + } + } + + // configuration is valid, the kernel will figure out the rest + let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc))); + + let state = State { + mode, + connectors, + }; + + let backend = Rc::new(LegacyDrmSurface { + dev: self.dev.clone(), + crtc, + state: RwLock::new(state.clone()), + pending: RwLock::new(state), + logger, + }); + + self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); + Ok(backend) + } + + fn process_events(&mut self) { + match crtc::receive_events(self) { + Ok(events) => for event in events { + if let crtc::Event::PageFlip(event) = event { + if self.active.load(Ordering::SeqCst) { + if let Some(backend) = self.backends.borrow().get(&event.crtc).iter().flat_map(|x| x.upgrade()).next() { + trace!(self.logger, "Handling event for backend {:?}", event.crtc); + if let Some(handler) = self.handler.as_ref() { + handler.borrow_mut().vblank(&backend); + } + } else { + self.backends.borrow_mut().remove(&event.crtc); + } + } + } + }, + Err(err) => if let Some(handler) = self.handler.as_ref() { + handler.borrow_mut().error(ResultExt::<()>::chain_err(Err(err), || + ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path())) + ).unwrap_err()); + } + } + } +} + +impl RawDevice for LegacyDrmDevice { + type Surface = LegacyDrmSurface; +} + +impl Drop for LegacyDrmDevice { + fn drop(&mut self) { + self.backends.borrow_mut().clear(); + if Rc::strong_count(&self.dev) > 1 { + panic!("Pending DrmBackends. You need to free all backends before the DrmDevice gets destroyed"); + } + if self.active.load(Ordering::SeqCst) { + for (handle, (info, connectors)) in self.old_state.drain() { + if let Err(err) = crtc::set( + &*self.dev, + handle, + info.fb(), + &connectors, + info.position(), + info.mode(), + ) { + error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); + } + } + if self.priviledged { + if let Err(err) = self.drop_master() { + error!(self.logger, "Failed to drop drm master state. Error: {}", err); + } + } + } + } +} diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs new file mode 100644 index 0000000..bc80c09 --- /dev/null +++ b/src/backend/drm/legacy/session.rs @@ -0,0 +1,97 @@ +use drm::Device as BasicDevice; +use drm::control::{crtc, connector, Device as ControlDevice}; +use nix::libc::dev_t; +use nix::sys::stat; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::{Rc, Weak}; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::os::unix::io::{AsRawFd, RawFd}; + +use backend::session::{AsSessionObserver, SessionObserver}; +use super::{LegacyDrmDevice, LegacyDrmSurface, Dev}; + +/// `SessionObserver` linked to the `DrmDevice` it was created from. +pub struct LegacyDrmDeviceObserver { + dev: Weak>, + dev_id: dev_t, + priviledged: bool, + active: Arc, + old_state: HashMap)>, + backends: Weak>>>>, + logger: ::slog::Logger, +} + +impl AsSessionObserver> for LegacyDrmDevice { + fn observer(&mut self) -> LegacyDrmDeviceObserver { + LegacyDrmDeviceObserver { + dev: Rc::downgrade(&self.dev), + dev_id: self.dev_id, + old_state: self.old_state.clone(), + active: self.active.clone(), + priviledged: self.priviledged, + backends: Rc::downgrade(&self.backends), + logger: self.logger.clone(), + } + } +} + +impl SessionObserver for LegacyDrmDeviceObserver { + fn pause(&mut self, devnum: Option<(u32, u32)>) { + if let Some((major, minor)) = devnum { + if major as u64 != stat::major(self.dev_id) || minor as u64 != stat::minor(self.dev_id) { + return; + } + } + if let Some(device) = self.dev.upgrade() { + if let Some(backends) = self.backends.upgrade() { + for surface in backends.borrow().values().filter_map(Weak::upgrade) { + let _ = crtc::clear_cursor(&*device, surface.crtc); + } + } + for (handle, &(ref info, ref connectors)) in &self.old_state { + if let Err(err) = crtc::set( + &*device, + *handle, + info.fb(), + connectors, + info.position(), + info.mode(), + ) { + error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); + } + } + } + self.active.store(false, Ordering::SeqCst); + if self.priviledged { + if let Some(device) = self.dev.upgrade() { + if let Err(err) = device.drop_master() { + error!(self.logger, "Failed to drop drm master state. Error: {}", err); + } + } + } + } + + fn activate(&mut self, devnum: Option<(u32, u32, Option)>) { + if let Some((major, minor, fd)) = devnum { + if major as u64 != stat::major(self.dev_id) || minor as u64 != stat::minor(self.dev_id) { + return; + } else if let Some(fd) = fd { + info!(self.logger, "Replacing fd"); + if let Some(device) = self.dev.upgrade() { + ::nix::unistd::dup2(device.as_raw_fd(), fd) + .expect("Failed to replace file descriptor of drm device"); + } + } + } + self.active.store(true, Ordering::SeqCst); + if self.priviledged { + if let Some(device) = self.dev.upgrade() { + if let Err(err) = device.set_master() { + crit!(self.logger, "Failed to acquire drm master again. Error: {}", err); + } + } + } + } +} diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs new file mode 100644 index 0000000..6f4b057 --- /dev/null +++ b/src/backend/drm/legacy/surface.rs @@ -0,0 +1,264 @@ +use drm::Device as BasicDevice; +use drm::control::{connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, ResourceInfo}; +pub use drm::buffer::Buffer; + +use std::collections::HashSet; +use std::rc::Rc; +use std::os::unix::io::{AsRawFd, RawFd}; +use std::sync::RwLock; + +use backend::drm::{RawSurface, Surface, DevPath}; +use backend::graphics::CursorBackend; +use backend::graphics::SwapBuffersError; + +use super::{Dev, error::*}; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct State { + pub mode: Mode, + pub connectors: HashSet, +} + +pub struct LegacyDrmSurface { + pub(in super) dev: Rc>, + pub(in super) crtc: crtc::Handle, + pub(in super) state: RwLock, + pub(in super) pending: RwLock, + pub(in super) logger: ::slog::Logger, +} + +impl AsRawFd for LegacyDrmSurface { + fn as_raw_fd(&self) -> RawFd { + self.dev.as_raw_fd() + } +} + +impl BasicDevice for LegacyDrmSurface {} +impl ControlDevice for LegacyDrmSurface {} + +impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { + type CursorFormat = &'a Buffer; + type Error = Error; + + fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { + trace!(self.logger, "Move the cursor to {},{}", x, y); + crtc::move_cursor(self, self.crtc, (x as i32, y as i32)).chain_err(|| { + ErrorKind::DrmDev(format!( + "Error moving cursor on {:?}", + self.dev_path() + )) + }) + } + + fn set_cursor_representation<'b>( + &'b self, + buffer: Self::CursorFormat, + hotspot: (u32, u32), + ) -> Result<()> + where 'a: 'b + { + trace!(self.logger, "Setting the new imported cursor"); + + if crtc::set_cursor2( + self, + self.crtc, + buffer, + (hotspot.0 as i32, hotspot.1 as i32), + ).is_err() + { + crtc::set_cursor(self, self.crtc, buffer).chain_err(|| { + ErrorKind::DrmDev(format!( + "Failed to set cursor on {:?}", + self.dev_path() + )) + })?; + } + + Ok(()) + } +} + +impl Surface for LegacyDrmSurface { + type Error = Error; + type Connectors = HashSet; + + fn crtc(&self) -> crtc::Handle { + self.crtc + } + + fn current_connectors(&self) -> Self::Connectors { + self.state.read().unwrap().connectors.clone() + } + + fn pending_connectors(&self) -> Self::Connectors { + self.pending.read().unwrap().connectors.clone() + } + + fn current_mode(&self) -> Mode { + self.state.read().unwrap().mode.clone() + } + + fn pending_mode(&self) -> Mode { + self.pending.read().unwrap().mode.clone() + } + + fn add_connector(&self, connector: connector::Handle) -> Result<()> { + let info = connector::Info::load_from_device(self, connector).chain_err(|| { + ErrorKind::DrmDev(format!( + "Error loading connector info on {:?}", + self.dev_path() + )) + })?; + + let mut pending = self.pending.write().unwrap(); + + // check if the connector can handle the current mode + if info.modes().contains(&pending.mode) { + // check if there is a valid encoder + let encoders = info + .encoders() + .iter() + .map(|encoder| { + encoder::Info::load_from_device(self, *encoder).chain_err(|| { + ErrorKind::DrmDev(format!( + "Error loading encoder info on {:?}", + self.dev_path() + )) + }) + }).collect::>>()?; + + // and if any encoder supports the selected crtc + let resource_handles = self.resource_handles().chain_err(|| { + ErrorKind::DrmDev(format!( + "Error loading resources on {:?}", + self.dev_path() + )) + })?; + if !encoders + .iter() + .map(|encoder| encoder.possible_crtcs()) + .all(|crtc_list| { + resource_handles + .filter_crtcs(crtc_list) + .contains(&self.crtc) + }) { + bail!(ErrorKind::NoSuitableEncoder(info, self.crtc)); + } + + pending.connectors.insert(connector); + Ok(()) + } else { + bail!(ErrorKind::ModeNotSuitable(pending.mode)); + } + } + + fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + self.pending.write().unwrap().connectors.remove(&connector); + Ok(()) + } + + fn use_mode(&self, mode: Mode) -> Result<()> { + let mut pending = self.pending.write().unwrap(); + + // check the connectors + for connector in &pending.connectors { + if !connector::Info::load_from_device(self, *connector) + .chain_err(|| { + ErrorKind::DrmDev(format!( + "Error loading connector info on {:?}", + self.dev_path() + )) + })?.modes() + .contains(&mode) + { + bail!(ErrorKind::ModeNotSuitable(mode)); + } + } + + pending.mode = mode; + + Ok(()) + } +} + +impl RawSurface for LegacyDrmSurface { + fn commit_pending(&self) -> bool { + *self.pending.read().unwrap() != *self.state.read().unwrap() + } + + fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> { + let mut current = self.state.write().unwrap(); + let pending = self.pending.read().unwrap(); + + { + let removed = current.connectors.difference(&pending.connectors); + let added = pending.connectors.difference(¤t.connectors); + + for conn in removed { + if let Ok(info) = connector::Info::load_from_device(self, *conn) { + info!( + self.logger, + "Removing connector: {:?}", + info.connector_type() + ); + } else { + info!(self.logger, "Removing unknown connector"); + } + } + + for conn in added { + if let Ok(info) = connector::Info::load_from_device(self, *conn) { + info!( + self.logger, + "Adding connector: {:?}", + info.connector_type() + ); + } else { + info!(self.logger, "Adding unknown connector"); + } + } + + if current.mode != pending.mode { + info!(self.logger, "Setting new mode: {:?}", pending.mode.name()); + } + } + + debug!(self.logger, "Setting screen"); + crtc::set( + self, + self.crtc, + framebuffer, + &pending.connectors.iter().map(|x| *x).collect::>(), + (0, 0), + Some(pending.mode), + ).chain_err(|| { + ErrorKind::DrmDev(format!( + "Error setting crtc {:?} on {:?}", + self.crtc, + self.dev_path() + )) + })?; + + *current = pending.clone(); + + Ok(()) + } + + fn page_flip(&self, framebuffer: framebuffer::Handle) -> ::std::result::Result<(), SwapBuffersError> { + trace!(self.logger, "Queueing Page flip"); + + crtc::page_flip( + self, + self.crtc, + framebuffer, + &[crtc::PageFlipFlags::PageFlipEvent], + ).map_err(|_| SwapBuffersError::ContextLost) + } +} + +impl Drop for LegacyDrmSurface { + fn drop(&mut self) { + // ignore failure at this point + let _ = crtc::clear_cursor(self, self.crtc); + } +} diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 39ec1cc..05f5e21 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -1,454 +1,77 @@ -//! Drm/Kms types and backend implementations -//! -//! This module provide a `DrmDevice` which acts as a representation for any DRM -//! device and can be used to create the second provided structure a `DrmBackend`. -//! -//! Initialization happens through the types provided by [`drm-rs`](https://docs.rs/drm/). -//! -//! Three entities are relevant for the initialization procedure. -//! -//! "Crtc"s represent scanout engines of the device pointer to one framebuffer. There responsibility -//! is to read the data of the framebuffer and export it into an "Encoder". The number of crtc's -//! represent the number of independent output devices the hardware may handle. -//! -//! An "Encoder" encodes the data of connected crtcs into a video signal for a fixed set -//! of connectors. E.g. you might have an analog encoder based on a DAG for VGA ports, but another -//! one for digital ones. Also not every encoder might be connected to every crtc. -//! -//! The last entity the "Connector" represents a port on your computer, possibly with a connected -//! monitor, TV, capture card, etc. -//! -//! The `DrmBackend` created from a `DrmDevice` represents a crtc of the device you can render to -//! and that feeds a given set of connectors, that can be manipulated at runtime. -//! -//! From these circumstances it becomes clear, that one crtc might only send it's data to a connector, -//! that is attached to any encoder that is attached to the crtc itself. It is the responsibility of the -//! user to ensure that a given set of a crtc with it's connectors is valid or an error will be thrown. -//! -//! For more details refer to the [`drm-rs` documentation](https://docs.rs/drm). -//! -//! -//! ## How to use it -//! -//! ### Initialization -//! -//! To initialize the `DrmDevice` you need either a `RawFd` or a `File` of -//! your DRM node. The `File` is recommended as it represents the save API. -//! -//! Once you got your `DrmDevice` you can then use it to create `DrmBackend`s. -//! You will need to use the `drm` crate to provide the required types to create -//! a backend. -//! -//! ```rust,no_run -//! extern crate drm; -//! extern crate smithay; -//! extern crate wayland_server; -//! -//! use drm::Device as BasicDevice; -//! use drm::control::{Device as ControlDevice, ResourceInfo}; -//! use drm::control::connector::{Info as ConnectorInfo, State as ConnectorState}; -//! use drm::control::encoder::{Info as EncoderInfo}; -//! use std::fs::{File, OpenOptions}; -//! use std::os::unix::io::RawFd; -//! use std::os::unix::io::AsRawFd; -//! use smithay::backend::drm::{DrmDevice, DrmBackend}; -//! -//! #[derive(Debug)] -//! pub struct Card(File); -//! -//! impl AsRawFd for Card { -//! fn as_raw_fd(&self) -> RawFd { -//! self.0.as_raw_fd() -//! } -//! } -//! -//! impl BasicDevice for Card {} -//! impl ControlDevice for Card {} -//! -//! # fn main() { -//! // Open the drm device -//! let mut options = OpenOptions::new(); -//! options.read(true); -//! options.write(true); -//! let mut device = DrmDevice::new( -//! Card(options.open("/dev/dri/card0").unwrap()), // try to detect it properly -//! None /*put a logger here*/ -//! ).unwrap(); -//! -//! // Get a set of all modesetting resource handles -//! let res_handles = device.resource_handles().unwrap(); -//! -//! // Use first connected connector for this example -//! let connector_info = res_handles.connectors().iter() -//! .map(|conn| ConnectorInfo::load_from_device(&device, *conn).unwrap()) -//! .find(|conn| conn.connection_state() == ConnectorState::Connected) -//! .unwrap(); -//! -//! // Use the first encoder -//! let encoder_info = EncoderInfo::load_from_device(&device, connector_info.encoders()[0]).unwrap(); -//! -//! // use the connected crtc if any -//! let crtc = encoder_info.current_crtc() -//! // or use the first one that is compatible with the encoder -//! .unwrap_or_else(|| -//! *res_handles.filter_crtcs(encoder_info.possible_crtcs()) -//! .iter() -//! .next() -//! .unwrap()); -//! -//! // Use first mode (usually the highest resolution) -//! let mode = connector_info.modes()[0]; -//! -//! // Create the backend -//! let backend = device.create_backend( -//! crtc, -//! mode, -//! vec![connector_info.handle()] -//! ).unwrap(); -//! # } -//! ``` -//! -//! ### Page Flips / Tear-free video -//! Calling the usual `EglGraphicsBackend::swap_buffers` function on a -//! `DrmBackend` works the same to finish the rendering, but will return -//! `SwapBuffersError::AlreadySwapped` for any new calls until the page flip of the -//! crtc has happened. -//! -//! You can monitor the page flips by registering the `DrmDevice` as and -//! `FdEventSourceHandler` and setting a `DrmHandler` on it. You will be notified -//! whenever a page flip has happened, so you can render the next frame immediately -//! and get a tear-free representation on the display. -//! -//! You need to render at least once to successfully trigger the first event. -//! -//! ```rust,no_run -//! # extern crate drm; -//! # extern crate smithay; -//! # extern crate wayland_server; -//! # -//! # use drm::Device as BasicDevice; -//! # use drm::control::{Device as ControlDevice, ResourceInfo}; -//! # use drm::control::connector::{Info as ConnectorInfo, State as ConnectorState}; -//! use drm::control::crtc::{Handle as CrtcHandle}; -//! use drm::result::Error as DrmError; -//! # use std::fs::{File, OpenOptions}; -//! # use std::os::unix::io::RawFd; -//! # use std::os::unix::io::AsRawFd; -//! # use std::time::Duration; -//! use smithay::backend::drm::{DrmDevice, DrmBackend, DrmHandler, drm_device_bind}; -//! use smithay::backend::graphics::egl::EGLGraphicsBackend; -//! # -//! # #[derive(Debug)] -//! # pub struct Card(File); -//! # impl AsRawFd for Card { -//! # fn as_raw_fd(&self) -> RawFd { -//! # self.0.as_raw_fd() -//! # } -//! # } -//! # impl BasicDevice for Card {} -//! # impl ControlDevice for Card {} -//! # -//! # fn main() { -//! # -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); -//! # -//! # let mut options = OpenOptions::new(); -//! # options.read(true); -//! # options.write(true); -//! # let mut device = DrmDevice::new( -//! # Card(options.open("/dev/dri/card0").unwrap()), // try to detect it properly -//! # None /*put a logger here*/ -//! # ).unwrap(); -//! # -//! # let res_handles = device.resource_handles().unwrap(); -//! # let connector_info = res_handles.connectors().iter() -//! # .map(|conn| ConnectorInfo::load_from_device(&device, *conn).unwrap()) -//! # .find(|conn| conn.connection_state() == ConnectorState::Connected) -//! # .unwrap(); -//! # let crtc = res_handles.crtcs()[0]; -//! # let mode = connector_info.modes()[0]; -//! # let backend = device.create_backend( -//! # crtc, -//! # mode, -//! # vec![connector_info.handle()] -//! # ).unwrap(); -//! -//! struct MyDrmHandler(DrmBackend); -//! -//! impl DrmHandler for MyDrmHandler { -//! fn ready( -//! &mut self, -//! _device: &mut DrmDevice, -//! _crtc: CrtcHandle, -//! _frame: u32, -//! _duration: Duration) -//! { -//! // render surfaces and swap again -//! self.0.swap_buffers().unwrap(); -//! } -//! fn error( -//! &mut self, -//! device: &mut DrmDevice, -//! error: DrmError) -//! { -//! panic!("DrmDevice errored: {}", error); -//! } -//! } -//! -//! // render something (like clear_color) -//! backend.swap_buffers().unwrap(); -//! -//! let (_source, _device_rc) = drm_device_bind( -//! &event_loop.handle(), -//! device, -//! MyDrmHandler(backend) -//! ).map_err(|(err, _)| err).unwrap(); -//! -//! /* And then run the event loop once all your setup is done */ -//! # } -//! ``` +use drm::Device as BasicDevice; +use drm::control::Device as ControlDevice; +pub use drm::control::crtc; +pub use drm::control::connector; +pub use drm::control::framebuffer; +pub use drm::control::Mode; -use backend::graphics::egl::{ - context::{EGLContext, GlAttributes}, - error::Result as EGLResult, - native::Gbm, - wayland::{EGLDisplay, EGLWaylandExtensions}, -}; -#[cfg(feature = "backend_session")] -use backend::session::{AsSessionObserver, SessionObserver}; -use drm::{ - control::{connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, ResourceInfo}, - result::Error as DrmError, - Device as BasicDevice, -}; -use gbm::{BufferObject, Device as GbmDevice}; -use nix::{ - self, - sys::stat::{self, dev_t, fstat}, -}; -use std::{ - cell::RefCell, - collections::HashMap, - hash::{Hash, Hasher}, - io::Error as IoError, - os::unix::io::{AsRawFd, RawFd}, - path::PathBuf, - rc::{Rc, Weak}, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, Once, ONCE_INIT, - }, - time::Duration, -}; +use std::borrow::Borrow; +use std::error::Error; +use std::path::PathBuf; +use std::os::unix::io::AsRawFd; -use wayland_server::{ - calloop::{ - generic::{EventedRawFd, Generic}, - mio::Ready, - LoopHandle, Source, - }, - Display, -}; +use wayland_server::calloop::generic::{EventedFd, Generic}; +use wayland_server::calloop::{LoopHandle, Source}; +use wayland_server::calloop::mio::Ready; +pub use wayland_server::calloop::InsertError; -mod backend; -pub mod error; +use super::graphics::SwapBuffersError; -pub use self::backend::DrmBackend; -use self::{backend::DrmBackendInternal, error::*}; +#[cfg(feature = "backend_drm_legacy")] +pub mod legacy; +#[cfg(feature = "backend_drm_gbm")] +pub mod gbm; +#[cfg(feature = "backend_drm_egl")] +pub mod egl; -static LOAD: Once = ONCE_INIT; - -/// Representation of an open DRM device node to create rendering backends -pub struct DrmDevice { - context: Rc, GbmDevice>>, - old_state: HashMap)>, - device_id: dev_t, - backends: Rc>>>>, - active: Arc, - privileged: bool, - logger: ::slog::Logger, +pub trait DeviceHandler { + type Device: Device + ?Sized; + fn vblank(&mut self, surface: &<::Device as Device>::Surface); + fn error(&mut self, error: <<::Device as Device>::Surface as Surface>::Error); } -impl DrmDevice { - /// Create a new `DrmDevice` from an open DRM node - /// - /// Returns an error if the file is no valid DRM node or context creation was not - /// successful. - pub fn new(dev: A, logger: L) -> Result - where - L: Into>, - { - DrmDevice::new_with_gl_attr( - dev, - GlAttributes { - version: None, - profile: None, - debug: cfg!(debug_assertions), - vsync: true, - }, - logger, - ) - } +pub trait Device: AsRawFd + DevPath { + type Surface: Surface; + type Return: Borrow; - /// Create a new `DrmDevice` from an open DRM node and given `GlAttributes` - /// - /// Returns an error if the file is no valid DRM node or context creation was not - /// successful. - pub fn new_with_gl_attr(dev: A, attributes: GlAttributes, logger: L) -> Result - where - L: Into>, - { - let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm")); - - /* GBM will load a dri driver, but even though they need symbols from - * libglapi, in some version of Mesa they are not linked to it. Since - * only the gl-renderer module links to it, these symbols won't be globally available, - * and loading the DRI driver fails. - * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. - */ - LOAD.call_once(|| unsafe { - nix::libc::dlopen( - "libglapi.so.0".as_ptr() as *const _, - nix::libc::RTLD_LAZY | nix::libc::RTLD_GLOBAL, - ); - }); - - let device_id = fstat(dev.as_raw_fd()) - .chain_err(|| ErrorKind::UnableToGetDeviceId)? - .st_rdev; - - let mut drm = DrmDevice { - // Open the gbm device from the DRM device and create a context based on that - context: Rc::new( - EGLContext::new( - { - debug!(log, "Creating gbm device"); - let gbm = GbmDevice::new(dev).chain_err(|| ErrorKind::GbmInitFailed)?; - debug!(log, "Creating egl context from gbm device"); - gbm - }, - attributes, - Default::default(), - log.clone(), - ).map_err(Error::from)?, - ), - backends: Rc::new(RefCell::new(HashMap::new())), - device_id, - old_state: HashMap::new(), - active: Arc::new(AtomicBool::new(true)), - privileged: true, - logger: log.clone(), - }; - - info!(log, "DrmDevice initializing"); - - // we want to mode-set, so we better be the master, if we run via a tty session - if drm.set_master().is_err() { - warn!(log, "Unable to become drm master, assuming unprivileged mode"); - drm.privileged = false; - }; - - let res_handles = drm.resource_handles().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path())) - })?; - for &con in res_handles.connectors() { - let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path())) - })?; - if let Some(enc) = con_info.current_encoder() { - let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path())) - })?; - if let Some(crtc) = enc_info.current_crtc() { - let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", drm.dev_path())) - })?; - drm.old_state - .entry(crtc) - .or_insert((info, Vec::new())) - .1 - .push(con); - } - } - } - - Ok(drm) - } - - /// Create a new backend on a given crtc with a given `Mode` for a given amount - /// of `connectors` (mirroring). - /// - /// Errors if initialization fails or the mode is not available on all given - /// connectors. - pub fn create_backend( + fn set_handler(&mut self, handler: impl DeviceHandler + 'static); + fn clear_handler(&mut self); + fn create_surface( &mut self, - crtc: crtc::Handle, + ctrc: crtc::Handle, mode: Mode, - connectors: I, - ) -> Result> - where - I: Into>, - { - if self.backends.borrow().contains_key(&crtc) { - bail!(ErrorKind::CrtcAlreadyInUse(crtc)); - } - - if !self.active.load(Ordering::SeqCst) { - bail!(ErrorKind::DeviceInactive); - } - - // check if the given connectors and crtc match - let connectors = connectors.into(); - - // check if we have an encoder for every connector and the mode mode - for connector in &connectors { - let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) - })?; - - // check the mode - if !con_info.modes().contains(&mode) { - bail!(ErrorKind::ModeNotSuitable(mode)); - } - - // check for every connector which encoders it does support - let encoders = con_info - .encoders() - .iter() - .map(|encoder| { - encoder::Info::load_from_device(self, *encoder).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) - }) - }).collect::>>()?; - - // and if any encoder supports the selected crtc - let resource_handles = self.resource_handles().chain_err(|| { - ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) - })?; - if !encoders - .iter() - .map(|encoder| encoder.possible_crtcs()) - .any(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&crtc)) - { - bail!(ErrorKind::NoSuitableEncoder(con_info, crtc)) - } - } - - // configuration is valid, the kernel will figure out the rest - - let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc))); - let backend = DrmBackend::new(self.context.clone(), crtc, mode, connectors, logger)?; - self.backends.borrow_mut().insert(crtc, backend.weak()); - Ok(backend) - } - - /// Returns an internal device id, that is unique per boot per system - pub fn device_id(&self) -> u64 { - self.device_id - } + connectors: impl Into<::Connectors> + ) -> Result::Error>; + fn process_events(&mut self); } +pub trait RawDevice: Device::Surface> +where + ::Return: Borrow<::Surface> +{ + type Surface: RawSurface; +} + +pub trait Surface { + type Connectors: IntoIterator; + type Error: Error + Send; + + fn crtc(&self) -> crtc::Handle; + fn current_connectors(&self) -> Self::Connectors; + fn pending_connectors(&self) -> Self::Connectors; + fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; + fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; + fn current_mode(&self) -> Mode; + fn pending_mode(&self) -> Mode; + fn use_mode(&self, mode: Mode) -> Result<(), Self::Error>; +} + +pub trait RawSurface: Surface + ControlDevice + BasicDevice { + fn commit_pending(&self) -> bool; + fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), ::Error>; + fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError>; +} + /// Trait for types representing open devices pub trait DevPath { /// Returns the path of the open device if possible @@ -459,247 +82,25 @@ impl DevPath for A { fn dev_path(&self) -> Option { use std::fs; - fs::read_link(format!("/proc/self/fd/{:?}", self.as_raw_fd())).ok() + fs::read_link(format!("/proc/self/fd/{:?}", self.as_raw_fd())).ok() } } -impl PartialEq for DrmDevice { - fn eq(&self, other: &DrmDevice) -> bool { - self.device_id == other.device_id - } -} -impl Eq for DrmDevice {} - -impl Hash for DrmDevice { - fn hash(&self, state: &mut H) { - self.device_id.hash(state); - } -} - -// for users convenience and FdEventSource registering -impl AsRawFd for DrmDevice { - fn as_raw_fd(&self) -> RawFd { - self.context.as_raw_fd() - } -} - -impl BasicDevice for DrmDevice {} -impl ControlDevice for DrmDevice {} - -impl EGLWaylandExtensions for DrmDevice { - fn bind_wl_display(&self, display: &Display) -> EGLResult { - self.context.bind_wl_display(display) - } -} - -impl Drop for DrmDevice { - fn drop(&mut self) { - if Rc::strong_count(&self.context) > 1 { - panic!("Pending DrmBackends. You need to free all backends before the DrmDevice gets destroyed"); - } - for (handle, (info, connectors)) in self.old_state.drain() { - if let Err(err) = crtc::set( - &*self.context, - handle, - info.fb(), - &connectors, - info.position(), - info.mode(), - ) { - error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); - } - } - if self.privileged { - if let Err(err) = self.drop_master() { - error!(self.logger, "Failed to drop drm master state. Error: {}", err); - } - } - } -} - -/// Handler for DRM node events +/// Bind a `Device` to an `EventLoop`, /// -/// See module-level documentation for its use -pub trait DrmHandler { - /// The `DrmBackend` of crtc has finished swapping buffers and new frame can now - /// (and should be immediately) be rendered. - fn ready(&mut self, device: &mut DrmDevice, crtc: crtc::Handle, frame: u32, duration: Duration); - /// The `DrmDevice` has thrown an error. - /// - /// The related backends are most likely *not* usable anymore and - /// the whole stack has to be recreated.. - fn error(&mut self, device: &mut DrmDevice, error: DrmError); -} - -/// Bind a `DrmDevice` to an `EventLoop`, -/// -/// This will cause it to recieve events and feed them into an `DrmHandler` -pub fn drm_device_bind( +/// This will cause it to recieve events and feed them into an `DeviceHandler` +pub fn device_bind( handle: &LoopHandle, - device: DrmDevice, - mut handler: H, -) -> ::std::result::Result<(Source>, Rc>>), (IoError, DrmDevice)> + device: D, +) -> ::std::result::Result>>, InsertError>>> where - A: ControlDevice + 'static, - H: DrmHandler + 'static, + D: Device, + Data: 'static, { - let fd = device.as_raw_fd(); - let device = Rc::new(RefCell::new(device)); - - let mut source = Generic::from_raw_fd(fd); + let mut source = Generic::from_fd_source(device); source.set_interest(Ready::readable()); - match handle.insert_source(source, { - let device = device.clone(); - move |_evt, _| { - let mut device = device.borrow_mut(); - process_events(&mut *device, &mut handler); - } - }) { - Ok(source) => Ok((source, device)), - Err(e) => { - let device = Rc::try_unwrap(device).unwrap_or_else(|_| unreachable!()); - Err((e.into(), device.into_inner())) - } - } -} - -fn process_events(device: &mut DrmDevice, handler: &mut H) -where - A: ControlDevice + 'static, - H: DrmHandler + 'static, -{ - match crtc::receive_events(&*device) { - Ok(events) => for event in events { - if let crtc::Event::PageFlip(event) = event { - if device.active.load(Ordering::SeqCst) { - let backends = device.backends.borrow().clone(); - if let Some(backend) = backends.get(&event.crtc).iter().flat_map(|x| x.upgrade()).next() { - // we can now unlock the buffer - backend.unlock_buffer(); - trace!(device.logger, "Handling event for backend {:?}", event.crtc); - // and then call the user to render the next frame - handler.ready(device, event.crtc, event.frame, event.duration); - } else { - device.backends.borrow_mut().remove(&event.crtc); - } - } - } - }, - Err(err) => handler.error(device, err), - } -} - -/// `SessionObserver` linked to the `DrmDevice` it was created from. -pub struct DrmDeviceObserver { - context: Weak, GbmDevice>>, - device_id: dev_t, - backends: Rc>>>>, - old_state: HashMap)>, - active: Arc, - privileged: bool, - logger: ::slog::Logger, -} - -#[cfg(feature = "backend_session")] -impl AsSessionObserver> for DrmDevice { - fn observer(&mut self) -> DrmDeviceObserver { - DrmDeviceObserver { - context: Rc::downgrade(&self.context), - device_id: self.device_id, - backends: self.backends.clone(), - old_state: self.old_state.clone(), - active: self.active.clone(), - privileged: self.privileged, - logger: self.logger.clone(), - } - } -} - -#[cfg(feature = "backend_session")] -impl SessionObserver for DrmDeviceObserver { - fn pause(&mut self, devnum: Option<(u32, u32)>) { - if let Some((major, minor)) = devnum { - if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) { - return; - } - } - if let Some(device) = self.context.upgrade() { - for (handle, &(ref info, ref connectors)) in &self.old_state { - if let Err(err) = crtc::set( - &*device, - *handle, - info.fb(), - connectors, - info.position(), - info.mode(), - ) { - error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); - } - } - } - self.active.store(false, Ordering::SeqCst); - if self.privileged { - if let Some(device) = self.context.upgrade() { - if let Err(err) = device.drop_master() { - error!(self.logger, "Failed to drop drm master state. Error: {}", err); - } - } - } - } - - fn activate(&mut self, devnum: Option<(u32, u32, Option)>) { - if let Some((major, minor, fd)) = devnum { - if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) { - return; - } else if let Some(fd) = fd { - info!(self.logger, "Replacing fd"); - if let Some(device) = self.context.upgrade() { - nix::unistd::dup2(device.as_raw_fd(), fd) - .expect("Failed to replace file descriptor of drm device"); - } - } - } - self.active.store(true, Ordering::SeqCst); - if self.privileged { - if let Some(device) = self.context.upgrade() { - if let Err(err) = device.set_master() { - crit!(self.logger, "Failed to acquire drm master again. Error: {}", err); - } - } - } - let mut crtcs = Vec::new(); - for (crtc, backend) in self.backends.borrow().iter() { - if let Some(backend) = backend.upgrade() { - backend.unlock_buffer(); - if let Err(err) = backend.page_flip(None) { - error!( - self.logger, - "Failed to activate crtc ({:?}) again. Error: {}", crtc, err - ); - } - // reset cursor - { - let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) = - unsafe { &*backend.cursor.as_ptr() }; - if crtc::set_cursor2( - &*backend.context, - *crtc, - cursor, - ((*hotspot).0 as i32, (*hotspot).1 as i32), - ).is_err() - { - if let Err(err) = crtc::set_cursor(&*backend.context, *crtc, cursor) { - error!(self.logger, "Failed to reset cursor. Error: {}", err); - } - } - } - } else { - crtcs.push(*crtc); - } - } - for crtc in crtcs { - self.backends.borrow_mut().remove(&crtc); - } - } + handle.insert_source(source, |evt, _| { + evt.source.borrow_mut().0.process_events(); + }) } From 9ee44672a01e38ef5c4fe506b08d78db17092185 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 10:41:55 +0100 Subject: [PATCH 10/56] cargo fmt --- src/backend/drm/egl/mod.rs | 101 +++++++++++++++++----------- src/backend/drm/egl/session.rs | 15 +++-- src/backend/drm/egl/surface.rs | 65 +++++++++++------- src/backend/drm/gbm/egl.rs | 29 ++++---- src/backend/drm/gbm/error.rs | 6 +- src/backend/drm/gbm/mod.rs | 68 +++++++++++-------- src/backend/drm/gbm/session.rs | 37 +++++----- src/backend/drm/gbm/surface.rs | 98 ++++++++++++--------------- src/backend/drm/legacy/mod.rs | 46 +++++++------ src/backend/drm/legacy/session.rs | 10 +-- src/backend/drm/legacy/surface.rs | 108 ++++++++++-------------------- src/backend/drm/mod.rs | 32 ++++----- src/backend/egl/context.rs | 40 +++++------ src/backend/egl/mod.rs | 13 ++-- src/backend/egl/native.rs | 5 +- src/backend/egl/surface.rs | 2 +- src/backend/graphics/cursor.rs | 5 +- src/backend/graphics/errors.rs | 3 +- src/backend/graphics/gl.rs | 4 +- src/backend/graphics/glium.rs | 5 +- src/backend/libinput.rs | 14 ++-- src/backend/udev.rs | 17 ++--- src/backend/winit.rs | 17 ++--- 23 files changed, 372 insertions(+), 368 deletions(-) diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 6f08942..e4570c4 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -1,15 +1,15 @@ use drm::control::{crtc, Mode}; use std::cell::RefCell; use std::collections::HashMap; -use std::rc::{Rc, Weak}; use std::os::unix::io::{AsRawFd, RawFd}; +use std::rc::{Rc, Weak}; use wayland_server::Display; -use backend::egl::{EGLContext, EGLGraphicsBackend, EGLDisplay}; +use super::{Device, DeviceHandler, Surface}; use backend::egl::context::GlAttributes; -use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use backend::egl::error::Result as EGLResult; -use super::{Device, Surface, DeviceHandler}; +use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; +use backend::egl::{EGLContext, EGLDisplay, EGLGraphicsBackend}; pub mod error; use self::error::*; @@ -21,24 +21,31 @@ pub use self::surface::*; pub mod session; /// Representation of an open gbm device to create rendering backends -pub struct EglDevice::Surface> + 'static, D: Device + NativeDisplay + 'static> - where ::Surface: NativeSurface +pub struct EglDevice< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, +> where + ::Surface: NativeSurface, { dev: Rc>>, backends: Rc>>>>, logger: ::slog::Logger, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> AsRawFd for EglDevice - where ::Surface: NativeSurface +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> AsRawFd + for EglDevice +where + ::Surface: NativeSurface, { fn as_raw_fd(&self) -> RawFd { self.dev.borrow().as_raw_fd() } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EglDevice - where ::Surface: NativeSurface +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> + EglDevice +where + ::Surface: NativeSurface, { /// Create a new `EglGbmDrmDevice` from an open drm node /// @@ -75,12 +82,8 @@ impl::Surface> + 'static, D: Device + NativeDis debug!(log, "Creating egl context from device"); Ok(EglDevice { // Open the gbm device from the drm device and create a context based on that - dev: Rc::new(RefCell::new(EGLContext::new( - dev, - attributes, - Default::default(), - log.clone(), - ).map_err(Error::from)? + dev: Rc::new(RefCell::new( + EGLContext::new(dev, attributes, Default::default(), log.clone()).map_err(Error::from)?, )), backends: Rc::new(RefCell::new(HashMap::new())), logger: log, @@ -88,20 +91,28 @@ impl::Surface> + 'static, D: Device + NativeDis } } -struct InternalDeviceHandler::Surface> + 'static, D: Device + NativeDisplay + 'static> - where ::Surface: NativeSurface +struct InternalDeviceHandler< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, +> where + ::Surface: NativeSurface, { - handler: Box> + 'static>, + handler: Box> + 'static>, backends: Weak>>>>, logger: ::slog::Logger, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> DeviceHandler for InternalDeviceHandler - where - >::Arguments: From<(crtc::Handle, Mode, <::Surface as Surface>::Connectors)>, - ::Surface: NativeSurface, +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> + DeviceHandler for InternalDeviceHandler +where + >::Arguments: From<( + crtc::Handle, + Mode, + <::Surface as Surface>::Connectors, + )>, + ::Surface: NativeSurface, { - type Device=D; + type Device = D; fn vblank(&mut self, surface: &::Surface) { if let Some(backends) = self.backends.upgrade() { @@ -110,31 +121,41 @@ impl::Surface> + 'static, D: Device + NativeDis self.handler.vblank(&*surface); } } else { - warn!(self.logger, "Surface ({:?}) not managed by egl, event not handled.", surface.crtc()); + warn!( + self.logger, + "Surface ({:?}) not managed by egl, event not handled.", + surface.crtc() + ); } } } fn error(&mut self, error: <::Surface as Surface>::Error) { - self.handler.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) + self.handler + .error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Device for EglDevice - where - >::Arguments: From<(crtc::Handle, Mode, <::Surface as Surface>::Connectors)>, - ::Surface: NativeSurface, +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Device + for EglDevice +where + >::Arguments: From<( + crtc::Handle, + Mode, + <::Surface as Surface>::Connectors, + )>, + ::Surface: NativeSurface, { type Surface = EglSurface; type Return = Rc>; - fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.dev.borrow_mut().set_handler(InternalDeviceHandler { handler: Box::new(handler), backends: Rc::downgrade(&self.backends), logger: self.logger.clone(), }); } - + fn clear_handler(&mut self) { self.dev.borrow_mut().clear_handler() } @@ -147,7 +168,10 @@ impl::Surface> + 'static, D: Device + NativeDis ) -> Result>> { info!(self.logger, "Initializing EglSurface"); - let surface = self.dev.borrow_mut().create_surface((crtc, mode, connectors.into()).into())?; + let surface = self + .dev + .borrow_mut() + .create_surface((crtc, mode, connectors.into()).into())?; let backend = Rc::new(EglSurface { dev: self.dev.clone(), @@ -157,16 +181,17 @@ impl::Surface> + 'static, D: Device + NativeDis Ok(backend) } - fn process_events(&mut self) { - self.dev.borrow_mut().process_events() + self.dev.borrow_mut().process_events() } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EGLGraphicsBackend for EglDevice - where ::Surface: NativeSurface +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> + EGLGraphicsBackend for EglDevice +where + ::Surface: NativeSurface, { fn bind_wl_display(&self, display: &Display) -> EGLResult { self.dev.borrow().bind_wl_display(display) } -} \ No newline at end of file +} diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index f440544..338865d 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -1,9 +1,9 @@ use std::os::unix::io::RawFd; +use super::EglDevice; +use backend::drm::Device; use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use backend::session::{AsSessionObserver, SessionObserver}; -use backend::drm::Device; -use super::{EglDevice}; /// `SessionObserver` linked to the `DrmDevice` it was created from. pub struct EglDeviceObserver { @@ -11,11 +11,12 @@ pub struct EglDeviceObserver { } impl< - S: SessionObserver + 'static, - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + AsSessionObserver + 'static, -> AsSessionObserver> for EglDevice - where ::Surface: NativeSurface + S: SessionObserver + 'static, + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + AsSessionObserver + 'static, + > AsSessionObserver> for EglDevice +where + ::Surface: NativeSurface, { fn observer(&mut self) -> EglDeviceObserver { EglDeviceObserver { diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 3d62af6..9e97168 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -3,22 +3,27 @@ use nix::libc::c_void; use std::cell::RefCell; use std::rc::Rc; -use backend::drm::{Device, Surface}; -use backend::egl::{EGLContext, EGLSurface}; -use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; -use backend::graphics::{CursorBackend, SwapBuffersError}; -use backend::graphics::gl::{GLGraphicsBackend, PixelFormat}; use super::error::*; +use backend::drm::{Device, Surface}; +use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; +use backend::egl::{EGLContext, EGLSurface}; +use backend::graphics::gl::{GLGraphicsBackend, PixelFormat}; +use backend::graphics::{CursorBackend, SwapBuffersError}; -pub struct EglSurface::Surface> + 'static, D: Device + NativeDisplay + 'static> - where ::Surface: NativeSurface +pub struct EglSurface< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, +> where + ::Surface: NativeSurface, { - pub(in super) dev: Rc>>, - pub(in super) surface: EGLSurface, + pub(super) dev: Rc>>, + pub(super) surface: EGLSurface, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Surface for EglSurface - where ::Surface: NativeSurface +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Surface + for EglSurface +where + ::Surface: NativeSurface, { type Error = Error; type Connectors = <::Surface as Surface>::Connectors; @@ -30,36 +35,43 @@ impl::Surface> + 'static, D: Device + NativeDis fn current_connectors(&self) -> Self::Connectors { self.surface.current_connectors() } - + fn pending_connectors(&self) -> Self::Connectors { self.surface.pending_connectors() } fn add_connector(&self, connector: connector::Handle) -> Result<()> { - self.surface.add_connector(connector).chain_err(|| ErrorKind::UnderlyingBackendError) + self.surface + .add_connector(connector) + .chain_err(|| ErrorKind::UnderlyingBackendError) } fn remove_connector(&self, connector: connector::Handle) -> Result<()> { - self.surface.remove_connector(connector).chain_err(|| ErrorKind::UnderlyingBackendError) + self.surface + .remove_connector(connector) + .chain_err(|| ErrorKind::UnderlyingBackendError) } - + fn current_mode(&self) -> Mode { self.surface.current_mode() } - + fn pending_mode(&self) -> Mode { self.surface.pending_mode() } fn use_mode(&self, mode: Mode) -> Result<()> { - self.surface.use_mode(mode).chain_err(|| ErrorKind::UnderlyingBackendError) + self.surface + .use_mode(mode) + .chain_err(|| ErrorKind::UnderlyingBackendError) } } -impl<'a, B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static> CursorBackend<'a> for EglSurface - where - D: CursorBackend<'a>, - ::Surface: NativeSurface +impl<'a, B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static> + CursorBackend<'a> for EglSurface +where + D: CursorBackend<'a>, + ::Surface: NativeSurface, { type CursorFormat = >::CursorFormat; type Error = >::Error; @@ -73,15 +85,18 @@ impl<'a, B: Backend::Surface> + 'static, D: Device + Nativ buffer: Self::CursorFormat, hotspot: (u32, u32), ) -> ::std::result::Result<(), Self::Error> - where 'a: 'b + where + 'a: 'b, { let dev = self.dev.borrow(); dev.set_cursor_representation(buffer, hotspot) } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> GLGraphicsBackend for EglSurface - where ::Surface: NativeSurface +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> + GLGraphicsBackend for EglSurface +where + ::Surface: NativeSurface, { fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { self.surface.swap_buffers() @@ -107,4 +122,4 @@ impl::Surface> + 'static, D: Device + NativeDis fn get_pixel_format(&self) -> PixelFormat { self.dev.borrow().get_pixel_format() } -} \ No newline at end of file +} diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 915df9b..edac7ec 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -1,29 +1,29 @@ -use backend::drm::{RawDevice, Device, RawSurface, Surface}; -use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; -use backend::egl::error::{Result as EglResult}; +use backend::drm::{Device, RawDevice, RawSurface, Surface}; +use backend::egl::error::Result as EglResult; use backend::egl::ffi; +use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use backend::graphics::SwapBuffersError; -use super::{GbmDevice, GbmSurface}; use super::error::{Error, Result}; +use super::{GbmDevice, GbmSurface}; use drm::control::{crtc, Device as ControlDevice, Mode}; use gbm::AsRaw; use std::marker::PhantomData; -use std::rc::Rc; use std::ptr; +use std::rc::Rc; /// Gbm backend type pub struct Gbm where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { _userdata: PhantomData, } impl Backend for Gbm where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { type Surface = Rc>; @@ -54,7 +54,7 @@ where /// Arguments necessary to construct a `GbmSurface` pub struct SurfaceArguments where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { /// Crtc pub crtc: crtc::Handle, @@ -64,9 +64,10 @@ where pub connectors: as Surface>::Connectors, } -impl From<(crtc::Handle, Mode, as Surface>::Connectors)> for SurfaceArguments +impl From<(crtc::Handle, Mode, as Surface>::Connectors)> + for SurfaceArguments where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { fn from((crtc, mode, connectors): (crtc::Handle, Mode, as Surface>::Connectors)) -> Self { SurfaceArguments { @@ -79,7 +80,7 @@ where unsafe impl NativeDisplay> for GbmDevice where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { type Arguments = SurfaceArguments; type Error = Error; @@ -99,7 +100,7 @@ where unsafe impl NativeSurface for Rc> where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { fn ptr(&self) -> ffi::NativeWindowType { self.surface.borrow().as_raw() as *const _ @@ -107,7 +108,7 @@ where fn swap_buffers(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, { if ::std::borrow::Borrow::borrow(&self.crtc).commit_pending() { self.recreate(flip).map_err(|_| SwapBuffersError::ContextLost) @@ -115,4 +116,4 @@ where self.page_flip(flip) } } -} \ No newline at end of file +} diff --git a/src/backend/drm/gbm/error.rs b/src/backend/drm/gbm/error.rs index e2fba7e..484e79c 100644 --- a/src/backend/drm/gbm/error.rs +++ b/src/backend/drm/gbm/error.rs @@ -9,19 +9,19 @@ error_chain! { description("Creation of gbm device failed"), display("Creation of gbm device failed"), } - + #[doc = "Creation of gbm surface failed"] SurfaceCreationFailed { description("Creation of gbm surface failed"), display("Creation of gbm surface failed"), } - + #[doc = "Creation of gbm buffer object failed"] BufferCreationFailed { description("Creation of gbm buffer object failed"), display("Creation of gbm buffer object failed"), } - + #[doc = "Writing to gbm buffer failed"] BufferWriteFailed { description("Writing to gbm buffer failed"), diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 43f501e..d13f06a 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -1,13 +1,13 @@ -use super::{Device, RawDevice, Surface, DeviceHandler}; +use super::{Device, DeviceHandler, RawDevice, Surface}; use drm::control::{crtc, framebuffer, Device as ControlDevice, Mode}; -use gbm::{self, Format as GbmFormat, BufferObjectFlags}; +use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use std::cell::{Cell, RefCell}; use std::collections::HashMap; +use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::{Rc, Weak}; use std::sync::{Once, ONCE_INIT}; -use std::os::unix::io::{AsRawFd, RawFd}; pub mod error; use self::error::*; @@ -25,16 +25,16 @@ static LOAD: Once = ONCE_INIT; /// Representation of an open gbm device to create rendering backends pub struct GbmDevice where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { - pub(in self) dev: Rc>>, + pub(self) dev: Rc>>, backends: Rc>>>>, logger: ::slog::Logger, } impl GbmDevice where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { /// Create a new `GbmDevice` from an open drm node /// @@ -56,7 +56,7 @@ where nix::libc::RTLD_LAZY | nix::libc::RTLD_GLOBAL, ); }); - + let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_gbm")); dev.clear_handler(); @@ -64,7 +64,9 @@ where debug!(log, "Creating gbm device"); Ok(GbmDevice { // Open the gbm device from the drm device - dev: Rc::new(RefCell::new(gbm::Device::new(dev).chain_err(|| ErrorKind::InitFailed)?)), + dev: Rc::new(RefCell::new( + gbm::Device::new(dev).chain_err(|| ErrorKind::InitFailed)?, + )), backends: Rc::new(RefCell::new(HashMap::new())), logger: log, }) @@ -73,16 +75,16 @@ where struct InternalDeviceHandler where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { - handler: Box> + 'static>, + handler: Box> + 'static>, backends: Weak>>>>, logger: ::slog::Logger, } impl DeviceHandler for InternalDeviceHandler where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { type Device = D; @@ -94,30 +96,35 @@ where self.handler.vblank(&*surface); } } else { - warn!(self.logger, "Surface ({:?}) not managed by gbm, event not handled.", surface.crtc()); + warn!( + self.logger, + "Surface ({:?}) not managed by gbm, event not handled.", + surface.crtc() + ); } } } fn error(&mut self, error: <::Surface as Surface>::Error) { - self.handler.error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) + self.handler + .error(ResultExt::<()>::chain_err(Err(error), || ErrorKind::UnderlyingBackendError).unwrap_err()) } } impl Device for GbmDevice where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { type Surface = GbmSurface; type Return = Rc>; - fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.dev.borrow_mut().set_handler(InternalDeviceHandler { handler: Box::new(handler), backends: Rc::downgrade(&self.backends), logger: self.logger.clone(), }); } - + fn clear_handler(&mut self) { self.dev.borrow_mut().clear_handler(); } @@ -126,17 +133,20 @@ where &mut self, crtc: crtc::Handle, mode: Mode, - connectors: impl Into<::Connectors> + connectors: impl Into<::Connectors>, ) -> Result>> { info!(self.logger, "Initializing GbmSurface"); let (w, h) = mode.size(); - let surface = self.dev.borrow().create_surface( - w as u32, - h as u32, - GbmFormat::XRGB8888, - BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, - ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; + let surface = self + .dev + .borrow() + .create_surface( + w as u32, + h as u32, + GbmFormat::XRGB8888, + BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, + ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; // init the first screen // (must be done before calling page_flip for the first time) @@ -147,11 +157,13 @@ where debug!(self.logger, "FrontBuffer color format: {:?}", front_bo.format()); // we need a framebuffer for the front buffer - let fb = framebuffer::create(&*self.dev.borrow(), &*front_bo).chain_err(|| ErrorKind::UnderlyingBackendError)?; + let fb = framebuffer::create(&*self.dev.borrow(), &*front_bo) + .chain_err(|| ErrorKind::UnderlyingBackendError)?; front_bo.set_userdata(fb).unwrap(); let cursor = Cell::new(( - self.dev.borrow() + self.dev + .borrow() .create_buffer_object( 1, 1, @@ -177,15 +189,15 @@ where } fn process_events(&mut self) { - self.dev.borrow_mut().process_events() + self.dev.borrow_mut().process_events() } } impl AsRawFd for GbmDevice where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { fn as_raw_fd(&self) -> RawFd { self.dev.borrow().as_raw_fd() } -} \ No newline at end of file +} diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs index 1a84c41..70b1059 100644 --- a/src/backend/drm/gbm/session.rs +++ b/src/backend/drm/gbm/session.rs @@ -2,32 +2,29 @@ use drm::control::{crtc, Device as ControlDevice, ResourceInfo}; use gbm::BufferObject; use std::cell::RefCell; use std::collections::HashMap; -use std::rc::{Rc, Weak}; use std::os::unix::io::RawFd; +use std::rc::{Rc, Weak}; -use backend::session::{AsSessionObserver, SessionObserver}; -use backend::drm::{Device, RawDevice, RawSurface}; use super::{GbmDevice, GbmSurface}; +use backend::drm::{Device, RawDevice, RawSurface}; +use backend::session::{AsSessionObserver, SessionObserver}; /// `SessionObserver` linked to the `DrmDevice` it was created from. pub struct GbmDeviceObserver< S: SessionObserver + 'static, D: RawDevice + ControlDevice + AsSessionObserver + 'static, -> -where - ::Return: ::std::borrow::Borrow<::Surface> +> where + ::Return: ::std::borrow::Borrow<::Surface>, { observer: S, backends: Weak>>>>, logger: ::slog::Logger, } -impl< - S: SessionObserver + 'static, - D: RawDevice + ControlDevice + AsSessionObserver + 'static, -> AsSessionObserver> for GbmDevice +impl + 'static> + AsSessionObserver> for GbmDevice where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { fn observer(&mut self) -> GbmDeviceObserver { GbmDeviceObserver { @@ -38,12 +35,10 @@ where } } -impl< - S: SessionObserver + 'static, - D: RawDevice + ControlDevice + AsSessionObserver + 'static, -> SessionObserver for GbmDeviceObserver +impl + 'static> + SessionObserver for GbmDeviceObserver where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { fn pause(&mut self, devnum: Option<(u32, u32)>) { self.observer.pause(devnum); @@ -56,15 +51,17 @@ where for (crtc, backend) in backends.borrow().iter() { if let Some(backend) = backend.upgrade() { // restart rendering loop - if let Err(err) = - ::std::borrow::Borrow::borrow(&backend.crtc).page_flip(backend.current_frame_buffer.get().handle()) + if let Err(err) = ::std::borrow::Borrow::borrow(&backend.crtc) + .page_flip(backend.current_frame_buffer.get().handle()) { warn!(self.logger, "Failed to restart rendering loop. Error: {}", err); } // reset cursor { - let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) = - unsafe { &*backend.cursor.as_ptr() }; + let &(ref cursor, ref hotspot): &( + BufferObject<()>, + (u32, u32), + ) = unsafe { &*backend.cursor.as_ptr() }; if crtc::set_cursor2( &*backend.dev.borrow(), *crtc, diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index c279a00..f8ab680 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -1,13 +1,13 @@ +use super::super::{Device, RawDevice, RawSurface, Surface}; use super::error::*; -use super::super::{Device, RawDevice, Surface, RawSurface}; -use drm::control::{crtc, connector, framebuffer, Mode, ResourceInfo}; -use gbm::{self, SurfaceBufferHandle, Format as GbmFormat, BufferObject, BufferObjectFlags}; +use drm::control::{connector, crtc, framebuffer, Mode, ResourceInfo}; +use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle}; use image::{ImageBuffer, Rgba}; use std::cell::{Cell, RefCell}; -use std::rc::Rc; use std::os::unix::io::AsRawFd; +use std::rc::Rc; use backend::drm::legacy::{LegacyDrmDevice, LegacyDrmSurface}; use backend::graphics::CursorBackend; @@ -15,23 +15,23 @@ use backend::graphics::SwapBuffersError; pub struct GbmSurface where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { - pub(in super) dev: Rc>>, - pub(in super) surface: RefCell>, - pub(in super) crtc: ::Return, - pub(in super) cursor: Cell<(BufferObject<()>, (u32, u32))>, - pub(in super) current_frame_buffer: Cell, - pub(in super) front_buffer: Cell>, - pub(in super) next_buffer: Cell>>, - pub(in super) logger: ::slog::Logger, + pub(super) dev: Rc>>, + pub(super) surface: RefCell>, + pub(super) crtc: ::Return, + pub(super) cursor: Cell<(BufferObject<()>, (u32, u32))>, + pub(super) current_frame_buffer: Cell, + pub(super) front_buffer: Cell>, + pub(super) next_buffer: Cell>>, + pub(super) logger: ::slog::Logger, } impl GbmSurface where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { - pub(in super) fn unlock_buffer(&self) { + pub(super) fn unlock_buffer(&self) { // after the page swap is finished we need to release the rendered buffer. // this is called from the PageFlipHandler if let Some(next_buffer) = self.next_buffer.replace(None) { @@ -43,7 +43,7 @@ where pub fn page_flip(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, { let res = { let nb = self.next_buffer.take(); @@ -53,10 +53,7 @@ where }; if res { // We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done - warn!( - self.logger, - "Tried to swap with an already queued flip" - ); + warn!(self.logger, "Tried to swap with an already queued flip"); return Err(SwapBuffersError::AlreadySwapped); } @@ -99,16 +96,13 @@ where pub fn recreate(&self, flip: F) -> Result<()> where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, { let (w, h) = self.pending_mode().size(); // Recreate the surface and the related resources to match the new // resolution. - debug!( - self.logger, - "Reinitializing surface for new mode: {}:{}", w, h - ); + debug!(self.logger, "Reinitializing surface for new mode: {}:{}", w, h); let surface = self .dev .borrow_mut() @@ -125,7 +119,9 @@ where { if let Some(mut old_bo) = self.next_buffer.take() { if let Ok(Some(fb)) = old_bo.take_userdata() { - if let Err(err) = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()) { + if let Err(err) = + framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()) + { warn!( self.logger, "Error releasing old back_buffer framebuffer: {:?}", err @@ -142,17 +138,14 @@ where .lock_front_buffer() .chain_err(|| ErrorKind::FrontBufferLockFailed)?; - debug!( - self.logger, - "FrontBuffer color format: {:?}", - front_bo.format() - ); + debug!(self.logger, "FrontBuffer color format: {:?}", front_bo.format()); // we also need a new framebuffer for the front buffer let fb = framebuffer::create(::std::borrow::Borrow::borrow(&self.crtc), &*front_bo) .chain_err(|| ErrorKind::UnderlyingBackendError)?; - ::std::borrow::Borrow::borrow(&self.crtc).commit(fb.handle()) + ::std::borrow::Borrow::borrow(&self.crtc) + .commit(fb.handle()) .chain_err(|| ErrorKind::UnderlyingBackendError)?; front_bo.set_userdata(fb).unwrap(); @@ -169,31 +162,28 @@ where // Drop the old surface after cleanup *self.surface.borrow_mut() = surface; - + Ok(()) } } impl Surface for GbmSurface where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { type Connectors = <::Surface as Surface>::Connectors; type Error = Error; fn crtc(&self) -> crtc::Handle { - ::std::borrow::Borrow::borrow(&self.crtc) - .crtc() + ::std::borrow::Borrow::borrow(&self.crtc).crtc() } fn current_connectors(&self) -> Self::Connectors { - ::std::borrow::Borrow::borrow(&self.crtc) - .current_connectors() + ::std::borrow::Borrow::borrow(&self.crtc).current_connectors() } - + fn pending_connectors(&self) -> Self::Connectors { - ::std::borrow::Borrow::borrow(&self.crtc) - .pending_connectors() + ::std::borrow::Borrow::borrow(&self.crtc).pending_connectors() } fn add_connector(&self, connector: connector::Handle) -> Result<()> { @@ -207,15 +197,13 @@ where .remove_connector(connector) .chain_err(|| ErrorKind::UnderlyingBackendError) } - + fn current_mode(&self) -> Mode { - ::std::borrow::Borrow::borrow(&self.crtc) - .current_mode() + ::std::borrow::Borrow::borrow(&self.crtc).current_mode() } - + fn pending_mode(&self) -> Mode { - ::std::borrow::Borrow::borrow(&self.crtc) - .pending_mode() + ::std::borrow::Borrow::borrow(&self.crtc).pending_mode() } fn use_mode(&self, mode: Mode) -> Result<()> { @@ -257,9 +245,9 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface Result<()> { ResultExt::chain_err( - ::std::borrow::Borrow::>>::borrow(&self.crtc) - .set_cursor_position(x, y), - || ErrorKind::UnderlyingBackendError) + ::std::borrow::Borrow::>>::borrow(&self.crtc).set_cursor_position(x, y), + || ErrorKind::UnderlyingBackendError, + ) } fn set_cursor_representation<'b>( @@ -267,7 +255,8 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface, Vec>, hotspot: (u32, u32), ) -> Result<()> - where 'a: 'b + where + 'a: 'b, { let (w, h) = buffer.dimensions(); debug!(self.logger, "Importing cursor"); @@ -293,7 +282,8 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface>>::borrow(&self.crtc) .set_cursor_representation(&cursor, hotspot), - || ErrorKind::UnderlyingBackendError)?; + || ErrorKind::UnderlyingBackendError, + )?; // and store it self.cursor.set((cursor, hotspot)); @@ -303,7 +293,7 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface Drop for GbmSurface where - ::Return: ::std::borrow::Borrow<::Surface> + ::Return: ::std::borrow::Borrow<::Surface>, { fn drop(&mut self) { // Drop framebuffers attached to the userdata of the gbm surface buffers. @@ -326,4 +316,4 @@ where let _ = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()); } } -} \ No newline at end of file +} diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 166e664..1bea1ad 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -1,16 +1,16 @@ -use super::{Device, RawDevice, Surface, DeviceHandler, DevPath}; +use super::{DevPath, Device, DeviceHandler, RawDevice, Surface}; +use drm::control::{connector, crtc, encoder, Device as ControlDevice, Mode, ResourceInfo}; use drm::Device as BasicDevice; -use drm::control::{crtc, connector, encoder, Device as ControlDevice, Mode, ResourceInfo}; use nix::libc::dev_t; use nix::sys::stat::fstat; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; -use std::rc::{Rc, Weak}; use std::os::unix::io::{AsRawFd, RawFd}; -use std::sync::{Arc, RwLock}; +use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, RwLock}; mod surface; pub use self::surface::LegacyDrmSurface; @@ -29,7 +29,7 @@ pub struct LegacyDrmDevice { active: Arc, old_state: HashMap)>, backends: Rc>>>>, - handler: Option>>>>, + handler: Option>>>>, logger: ::slog::Logger, } @@ -122,10 +122,10 @@ impl Device for LegacyDrmDevice { type Surface = LegacyDrmSurface; type Return = Rc>; - fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.handler = Some(RefCell::new(Box::new(handler))); } - + fn clear_handler(&mut self) { let _ = self.handler.take(); } @@ -134,7 +134,7 @@ impl Device for LegacyDrmDevice { &mut self, crtc: crtc::Handle, mode: Mode, - connectors: impl Into<::Connectors> + connectors: impl Into<::Connectors>, ) -> Result>> { if self.backends.borrow().contains_key(&crtc) { bail!(ErrorKind::CrtcAlreadyInUse(crtc)); @@ -181,11 +181,8 @@ impl Device for LegacyDrmDevice { // configuration is valid, the kernel will figure out the rest let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc))); - - let state = State { - mode, - connectors, - }; + + let state = State { mode, connectors }; let backend = Rc::new(LegacyDrmSurface { dev: self.dev.clone(), @@ -194,17 +191,24 @@ impl Device for LegacyDrmDevice { pending: RwLock::new(state), logger, }); - + self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); Ok(backend) } - + fn process_events(&mut self) { match crtc::receive_events(self) { Ok(events) => for event in events { if let crtc::Event::PageFlip(event) = event { if self.active.load(Ordering::SeqCst) { - if let Some(backend) = self.backends.borrow().get(&event.crtc).iter().flat_map(|x| x.upgrade()).next() { + if let Some(backend) = self + .backends + .borrow() + .get(&event.crtc) + .iter() + .flat_map(|x| x.upgrade()) + .next() + { trace!(self.logger, "Handling event for backend {:?}", event.crtc); if let Some(handler) = self.handler.as_ref() { handler.borrow_mut().vblank(&backend); @@ -216,10 +220,12 @@ impl Device for LegacyDrmDevice { } }, Err(err) => if let Some(handler) = self.handler.as_ref() { - handler.borrow_mut().error(ResultExt::<()>::chain_err(Err(err), || - ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path())) - ).unwrap_err()); - } + handler.borrow_mut().error( + ResultExt::<()>::chain_err(Err(err), || { + ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path())) + }).unwrap_err(), + ); + }, } } } diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs index bc80c09..dc319c0 100644 --- a/src/backend/drm/legacy/session.rs +++ b/src/backend/drm/legacy/session.rs @@ -1,16 +1,16 @@ +use drm::control::{connector, crtc, Device as ControlDevice}; use drm::Device as BasicDevice; -use drm::control::{crtc, connector, Device as ControlDevice}; use nix::libc::dev_t; use nix::sys::stat; use std::cell::RefCell; use std::collections::HashMap; -use std::rc::{Rc, Weak}; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::os::unix::io::{AsRawFd, RawFd}; +use std::rc::{Rc, Weak}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use super::{Dev, LegacyDrmDevice, LegacyDrmSurface}; use backend::session::{AsSessionObserver, SessionObserver}; -use super::{LegacyDrmDevice, LegacyDrmSurface, Dev}; /// `SessionObserver` linked to the `DrmDevice` it was created from. pub struct LegacyDrmDeviceObserver { diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index 6f4b057..6b6d021 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -1,17 +1,17 @@ -use drm::Device as BasicDevice; -use drm::control::{connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, ResourceInfo}; pub use drm::buffer::Buffer; +use drm::control::{connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, ResourceInfo}; +use drm::Device as BasicDevice; use std::collections::HashSet; -use std::rc::Rc; use std::os::unix::io::{AsRawFd, RawFd}; +use std::rc::Rc; use std::sync::RwLock; -use backend::drm::{RawSurface, Surface, DevPath}; +use backend::drm::{DevPath, RawSurface, Surface}; use backend::graphics::CursorBackend; use backend::graphics::SwapBuffersError; -use super::{Dev, error::*}; +use super::{error::*, Dev}; #[derive(Debug, PartialEq, Eq, Clone)] pub struct State { @@ -20,11 +20,11 @@ pub struct State { } pub struct LegacyDrmSurface { - pub(in super) dev: Rc>, - pub(in super) crtc: crtc::Handle, - pub(in super) state: RwLock, - pub(in super) pending: RwLock, - pub(in super) logger: ::slog::Logger, + pub(super) dev: Rc>, + pub(super) crtc: crtc::Handle, + pub(super) state: RwLock, + pub(super) pending: RwLock, + pub(super) logger: ::slog::Logger, } impl AsRawFd for LegacyDrmSurface { @@ -42,36 +42,19 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { trace!(self.logger, "Move the cursor to {},{}", x, y); - crtc::move_cursor(self, self.crtc, (x as i32, y as i32)).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error moving cursor on {:?}", - self.dev_path() - )) - }) + crtc::move_cursor(self, self.crtc, (x as i32, y as i32)) + .chain_err(|| ErrorKind::DrmDev(format!("Error moving cursor on {:?}", self.dev_path()))) } - fn set_cursor_representation<'b>( - &'b self, - buffer: Self::CursorFormat, - hotspot: (u32, u32), - ) -> Result<()> - where 'a: 'b + fn set_cursor_representation<'b>(&'b self, buffer: Self::CursorFormat, hotspot: (u32, u32)) -> Result<()> + where + 'a: 'b, { trace!(self.logger, "Setting the new imported cursor"); - if crtc::set_cursor2( - self, - self.crtc, - buffer, - (hotspot.0 as i32, hotspot.1 as i32), - ).is_err() - { - crtc::set_cursor(self, self.crtc, buffer).chain_err(|| { - ErrorKind::DrmDev(format!( - "Failed to set cursor on {:?}", - self.dev_path() - )) - })?; + if crtc::set_cursor2(self, self.crtc, buffer, (hotspot.0 as i32, hotspot.1 as i32)).is_err() { + crtc::set_cursor(self, self.crtc, buffer) + .chain_err(|| ErrorKind::DrmDev(format!("Failed to set cursor on {:?}", self.dev_path())))?; } Ok(()) @@ -85,11 +68,11 @@ impl Surface for LegacyDrmSurface { fn crtc(&self) -> crtc::Handle { self.crtc } - + fn current_connectors(&self) -> Self::Connectors { self.state.read().unwrap().connectors.clone() } - + fn pending_connectors(&self) -> Self::Connectors { self.pending.read().unwrap().connectors.clone() } @@ -104,10 +87,7 @@ impl Surface for LegacyDrmSurface { fn add_connector(&self, connector: connector::Handle) -> Result<()> { let info = connector::Info::load_from_device(self, connector).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading connector info on {:?}", - self.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) })?; let mut pending = self.pending.write().unwrap(); @@ -120,28 +100,19 @@ impl Surface for LegacyDrmSurface { .iter() .map(|encoder| { encoder::Info::load_from_device(self, *encoder).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading encoder info on {:?}", - self.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) }) }).collect::>>()?; // and if any encoder supports the selected crtc let resource_handles = self.resource_handles().chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading resources on {:?}", - self.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading resources on {:?}", self.dev_path())) })?; if !encoders .iter() .map(|encoder| encoder.possible_crtcs()) - .all(|crtc_list| { - resource_handles - .filter_crtcs(crtc_list) - .contains(&self.crtc) - }) { + .all(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&self.crtc)) + { bail!(ErrorKind::NoSuitableEncoder(info, self.crtc)); } @@ -159,15 +130,12 @@ impl Surface for LegacyDrmSurface { fn use_mode(&self, mode: Mode) -> Result<()> { let mut pending = self.pending.write().unwrap(); - + // check the connectors for connector in &pending.connectors { if !connector::Info::load_from_device(self, *connector) .chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading connector info on {:?}", - self.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) })?.modes() .contains(&mode) { @@ -185,7 +153,7 @@ impl RawSurface for LegacyDrmSurface { fn commit_pending(&self) -> bool { *self.pending.read().unwrap() != *self.state.read().unwrap() } - + fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> { let mut current = self.state.write().unwrap(); let pending = self.pending.read().unwrap(); @@ -196,11 +164,7 @@ impl RawSurface for LegacyDrmSurface { for conn in removed { if let Ok(info) = connector::Info::load_from_device(self, *conn) { - info!( - self.logger, - "Removing connector: {:?}", - info.connector_type() - ); + info!(self.logger, "Removing connector: {:?}", info.connector_type()); } else { info!(self.logger, "Removing unknown connector"); } @@ -208,11 +172,7 @@ impl RawSurface for LegacyDrmSurface { for conn in added { if let Ok(info) = connector::Info::load_from_device(self, *conn) { - info!( - self.logger, - "Adding connector: {:?}", - info.connector_type() - ); + info!(self.logger, "Adding connector: {:?}", info.connector_type()); } else { info!(self.logger, "Adding unknown connector"); } @@ -228,7 +188,11 @@ impl RawSurface for LegacyDrmSurface { self, self.crtc, framebuffer, - &pending.connectors.iter().map(|x| *x).collect::>(), + &pending + .connectors + .iter() + .map(|x| *x) + .collect::>(), (0, 0), Some(pending.mode), ).chain_err(|| { @@ -243,7 +207,7 @@ impl RawSurface for LegacyDrmSurface { Ok(()) } - + fn page_flip(&self, framebuffer: framebuffer::Handle) -> ::std::result::Result<(), SwapBuffersError> { trace!(self.logger, "Queueing Page flip"); diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 05f5e21..1a2d05c 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -1,28 +1,28 @@ -use drm::Device as BasicDevice; -use drm::control::Device as ControlDevice; -pub use drm::control::crtc; pub use drm::control::connector; +pub use drm::control::crtc; pub use drm::control::framebuffer; +use drm::control::Device as ControlDevice; pub use drm::control::Mode; +use drm::Device as BasicDevice; use std::borrow::Borrow; use std::error::Error; -use std::path::PathBuf; use std::os::unix::io::AsRawFd; +use std::path::PathBuf; use wayland_server::calloop::generic::{EventedFd, Generic}; -use wayland_server::calloop::{LoopHandle, Source}; use wayland_server::calloop::mio::Ready; pub use wayland_server::calloop::InsertError; +use wayland_server::calloop::{LoopHandle, Source}; use super::graphics::SwapBuffersError; -#[cfg(feature = "backend_drm_legacy")] -pub mod legacy; -#[cfg(feature = "backend_drm_gbm")] -pub mod gbm; #[cfg(feature = "backend_drm_egl")] pub mod egl; +#[cfg(feature = "backend_drm_gbm")] +pub mod gbm; +#[cfg(feature = "backend_drm_legacy")] +pub mod legacy; pub trait DeviceHandler { type Device: Device + ?Sized; @@ -34,26 +34,26 @@ pub trait Device: AsRawFd + DevPath { type Surface: Surface; type Return: Borrow; - fn set_handler(&mut self, handler: impl DeviceHandler + 'static); + fn set_handler(&mut self, handler: impl DeviceHandler + 'static); fn clear_handler(&mut self); fn create_surface( &mut self, ctrc: crtc::Handle, mode: Mode, - connectors: impl Into<::Connectors> + connectors: impl Into<::Connectors>, ) -> Result::Error>; fn process_events(&mut self); } -pub trait RawDevice: Device::Surface> +pub trait RawDevice: Device::Surface> where - ::Return: Borrow<::Surface> + ::Return: Borrow<::Surface>, { type Surface: RawSurface; } pub trait Surface { - type Connectors: IntoIterator; + type Connectors: IntoIterator; type Error: Error + Send; fn crtc(&self) -> crtc::Handle; @@ -70,7 +70,7 @@ pub trait RawSurface: Surface + ControlDevice + BasicDevice { fn commit_pending(&self) -> bool; fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), ::Error>; fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError>; -} +} /// Trait for types representing open devices pub trait DevPath { @@ -82,7 +82,7 @@ impl DevPath for A { fn dev_path(&self) -> Option { use std::fs; - fs::read_link(format!("/proc/self/fd/{:?}", self.as_raw_fd())).ok() + fs::read_link(format!("/proc/self/fd/{:?}", self.as_raw_fd())).ok() } } diff --git a/src/backend/egl/context.rs b/src/backend/egl/context.rs index 4c64afc..070c07a 100644 --- a/src/backend/egl/context.rs +++ b/src/backend/egl/context.rs @@ -52,14 +52,8 @@ impl> EGLContext { { let log = ::slog_or_stdlog(logger.into()).new(o!("smithay_module" => "renderer_egl")); let ptr = native.ptr()?; - let ( - context, - display, - config_id, - surface_attributes, - pixel_format, - wl_drm_support, - ) = unsafe { EGLContext::::new_internal(ptr, attributes, reqs, log.clone()) }?; + let (context, display, config_id, surface_attributes, pixel_format, wl_drm_support) = + unsafe { EGLContext::::new_internal(ptr, attributes, reqs, log.clone()) }?; Ok(EGLContext { native, @@ -117,15 +111,15 @@ impl> EGLContext { bail!(ErrorKind::OpenGlVersionNotSupported(version)); } }; - - fn constrain(f: F) -> F - where - F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void, - { - f - }; - + ffi::egl::LOAD.call_once(|| { + fn constrain(f: F) -> F + where + F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void, + { + f + }; + ffi::egl::load_with(|sym| { let name = CString::new(sym).unwrap(); let symbol = ffi::egl::LIB.get::<*mut c_void>(name.as_bytes()); @@ -144,7 +138,7 @@ impl> EGLContext { ffi::egl::UnbindWaylandDisplayWL::load_with(&proc_address); ffi::egl::QueryWaylandBufferWL::load_with(&proc_address); }); - + // the first step is to query the list of extensions without any display, if supported let dp_extensions = { let p = ffi::egl::QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32); @@ -437,13 +431,11 @@ impl> EGLContext { /// Creates a surface for rendering pub fn create_surface(&mut self, args: N::Arguments) -> Result> { trace!(self.logger, "Creating EGL window surface."); - let surface = self.native - .create_surface(args) - .chain_err(|| ErrorKind::SurfaceCreationFailed)?; - EGLSurface::new( - self, - surface, - ).map(|x| { + let surface = self + .native + .create_surface(args) + .chain_err(|| ErrorKind::SurfaceCreationFailed)?; + EGLSurface::new(self, surface).map(|x| { debug!(self.logger, "EGL surface successfully created"); x }) diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index 9335b7c..3516c15 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -181,7 +181,9 @@ impl ::std::error::Error for TextureCreationError { match *self { TextureCreationError::ContextLost => "The context has been lost, it needs to be recreated", TextureCreationError::PlaneIndexOutOfBounds => "This buffer is not managed by EGL", - TextureCreationError::GLExtensionNotSupported(_) => "Required OpenGL Extension for texture creation is missing", + TextureCreationError::GLExtensionNotSupported(_) => { + "Required OpenGL Extension for texture creation is missing" + } TextureCreationError::TextureBindingFailed(_) => "Failed to create EGLImages from the buffer", } } @@ -263,7 +265,7 @@ impl EGLImages { if !self.egl_to_texture_support { return Err(TextureCreationError::GLExtensionNotSupported("GL_OES_EGL_image")); } - + let mut old_tex_id: i32 = 0; self.gl.GetIntegerv(gl_ffi::TEXTURE_BINDING_2D, &mut old_tex_id); self.gl.BindTexture(gl_ffi::TEXTURE_2D, tex_id); @@ -343,11 +345,12 @@ impl EGLDisplay { #[cfg(feature = "renderer_gl")] egl_to_texture_support: { // the list of gl extensions supported by the context - let data = unsafe { CStr::from_ptr(gl.GetString(gl_ffi::EXTENSIONS) as *const _ )} + let data = unsafe { CStr::from_ptr(gl.GetString(gl_ffi::EXTENSIONS) as *const _) } .to_bytes() .to_vec(); let list = String::from_utf8(data).unwrap(); - list.split(' ').any(|s| s == "GL_OES_EGL_image" || s == "GL_OES_EGL_image_base") + list.split(' ') + .any(|s| s == "GL_OES_EGL_image" || s == "GL_OES_EGL_image_base") }, #[cfg(feature = "renderer_gl")] gl, @@ -496,4 +499,4 @@ impl> EGLGraphicsBackend for EGL } Ok(EGLDisplay::new(self, display.c_ptr())) } -} \ No newline at end of file +} diff --git a/src/backend/egl/native.rs b/src/backend/egl/native.rs index 6e4e79e..2cfb9f7 100644 --- a/src/backend/egl/native.rs +++ b/src/backend/egl/native.rs @@ -169,9 +169,10 @@ pub unsafe trait NativeSurface { fn ptr(&self) -> ffi::NativeWindowType; /// Adds additional semantics when calling EGLSurface::swap_buffers /// - /// Only implement if required by the backend, flip must be called during this call. + /// Only implement if required by the backend, flip must be called during this call. fn swap_buffers(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> - where F: FnOnce() -> ::std::result::Result<(), SwapBuffersError> + where + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, { flip() } diff --git a/src/backend/egl/surface.rs b/src/backend/egl/surface.rs index 71970cb..3e11ce5 100644 --- a/src/backend/egl/surface.rs +++ b/src/backend/egl/surface.rs @@ -66,7 +66,7 @@ impl EGLSurface { err => Err(SwapBuffersError::Unknown(err)), } } else { - Ok(()) + Ok(()) } } else { Err(SwapBuffersError::ContextLost) diff --git a/src/backend/graphics/cursor.rs b/src/backend/graphics/cursor.rs index fe2ab8c..e08c5cc 100644 --- a/src/backend/graphics/cursor.rs +++ b/src/backend/graphics/cursor.rs @@ -29,5 +29,6 @@ pub trait CursorBackend<'a> { cursor: Self::CursorFormat, hotspot: (u32, u32), ) -> Result<(), Self::Error> - where 'a: 'b; -} \ No newline at end of file + where + 'a: 'b; +} diff --git a/src/backend/graphics/errors.rs b/src/backend/graphics/errors.rs index 4b0b56a..fa9e9a7 100644 --- a/src/backend/graphics/errors.rs +++ b/src/backend/graphics/errors.rs @@ -1,5 +1,5 @@ -use std::fmt; use std::error::Error; +use std::fmt; /// Error that can happen when swapping buffers. #[derive(Debug, Clone, PartialEq)] @@ -43,4 +43,3 @@ impl Error for SwapBuffersError { None } } - diff --git a/src/backend/graphics/gl.rs b/src/backend/graphics/gl.rs index 5f120b5..78c3c9f 100644 --- a/src/backend/graphics/gl.rs +++ b/src/backend/graphics/gl.rs @@ -67,10 +67,10 @@ pub trait GLGraphicsBackend { } /// Loads a Raw GLES Interface for a given `GLGraphicsBackend` -/// +/// /// This remains valid as long as the underlying `GLGraphicsBackend` is alive /// and may only be used in combination with the backend. Using this with any /// other gl context may cause undefined behavior. pub fn load_raw_gl(backend: &B) -> Gles2 { Gles2::load_with(|s| unsafe { backend.get_proc_address(s) as *const _ }) -} \ No newline at end of file +} diff --git a/src/backend/graphics/glium.rs b/src/backend/graphics/glium.rs index caf1b1f..ab83d86 100644 --- a/src/backend/graphics/glium.rs +++ b/src/backend/graphics/glium.rs @@ -1,9 +1,6 @@ //! Glium compatibility module -use backend::graphics::{ - gl::GLGraphicsBackend, - SwapBuffersError, -}; +use backend::graphics::{gl::GLGraphicsBackend, SwapBuffersError}; use glium::{ backend::{Backend, Context, Facade}, debug::DebugCallbackBehavior, diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index 4e62ca7..8ffc7e1 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -16,13 +16,16 @@ use std::{ use wayland_server::calloop::{ generic::{EventedFd, Generic}, mio::Ready, - LoopHandle, Source, InsertError, + InsertError, LoopHandle, Source, }; // No idea if this is the same across unix platforms // Lets make this linux exclusive for now, once someone tries to build it for // any BSD-like system, they can verify if this is right and make a PR to change this. -#[cfg(all(any(target_os = "linux", target_os = "android"), feature = "backend_session"))] +#[cfg(all( + any(target_os = "linux", target_os = "android"), + feature = "backend_session" +))] const INPUT_MAJOR: u32 = 13; /// Libinput based `InputBackend`. @@ -600,13 +603,16 @@ impl AsRawFd for LibinputInputBackend { pub fn libinput_bind( backend: LibinputInputBackend, handle: LoopHandle, -) -> ::std::result::Result>>, InsertError>>> { +) -> ::std::result::Result< + Source>>, + InsertError>>, +> { let mut source = Generic::from_fd_source(backend); source.set_interest(Ready::readable()); handle.insert_source(source, move |evt, _| { use backend::input::InputBackend; - + let mut backend = evt.source.borrow_mut(); if let Err(error) = backend.0.dispatch_new_events() { warn!(backend.0.logger, "Libinput errored: {}", error); diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 3f94d95..4ae69a8 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -21,7 +21,7 @@ use udev::{Context, Enumerator, EventType, MonitorBuilder, MonitorSocket, Result use wayland_server::calloop::{ generic::{EventedFd, Generic}, mio::Ready, - LoopHandle, Source, InsertError, + InsertError, LoopHandle, Source, }; /// Backend to monitor available drm devices. @@ -48,7 +48,7 @@ impl UdevBackend { /// ## Arguments /// `context` - An initialized udev context /// `handler` - User-provided handler to respond to any detected changes - /// `seat` - + /// `seat` - /// `logger` - slog Logger to be used by the backend and its `DrmDevices`. pub fn new>( context: &Context, @@ -66,15 +66,14 @@ impl UdevBackend { // Create devices .flat_map(|path| match stat(&path) { Ok(stat) => { - handler.device_added(stat.st_rdev, path); + handler.device_added(stat.st_rdev, path); Some(stat.st_rdev) - }, + } Err(err) => { warn!(log, "Unable to get id of {:?}, Error: {:?}. Skipping", path, err); None } - }) - .collect(); + }).collect(); let mut builder = MonitorBuilder::new(context)?; builder.match_subsystem("drm")?; @@ -89,8 +88,7 @@ impl UdevBackend { } } -impl Drop for UdevBackend -{ +impl Drop for UdevBackend { fn drop(&mut self) { for device in &self.devices { self.handler.device_removed(*device); @@ -105,8 +103,7 @@ impl Drop for UdevBackend pub fn udev_backend_bind( handle: &LoopHandle, udev: UdevBackend, -) -> Result>>>, InsertError>>>> -{ +) -> Result>>>, InsertError>>>> { let mut source = Generic::from_fd_source(udev); source.set_interest(Ready::readable()); diff --git a/src/backend/winit.rs b/src/backend/winit.rs index f7d3a41..fef1f74 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -1,17 +1,13 @@ //! Implementation of backend traits for types provided by `winit` use backend::{ + egl::{ + context::GlAttributes, error as egl_error, error::Result as EGLResult, native, EGLContext, + EGLDisplay, EGLGraphicsBackend, EGLSurface, + }, graphics::{ gl::{GLGraphicsBackend, PixelFormat}, - CursorBackend, - SwapBuffersError, - }, - egl::{ - context::GlAttributes, - error as egl_error, - error::Result as EGLResult, - native, - EGLDisplay, EGLContext, EGLGraphicsBackend, EGLSurface, + CursorBackend, SwapBuffersError, }, input::{ Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, @@ -246,7 +242,8 @@ impl<'a> CursorBackend<'a> for WinitGraphicsBackend { cursor: Self::CursorFormat, _hotspot: (u32, u32), ) -> ::std::result::Result<(), ()> - where 'a: 'b + where + 'a: 'b, { // Cannot log this one, as `CursorFormat` is not `Debug` and should not be debug!(self.logger, "Changing cursor representation"); From e92044d213f33c35cc4f12d0ddaac95fddc228c9 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 10:44:52 +0100 Subject: [PATCH 11/56] Change travis to test new features --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index f714af3..dad47e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,10 +36,15 @@ env: # test individual features - FEATURES="backend_winit" - FEATURES="backend_drm" + - FEATURES="backend_drm_legacy" + - FEATURES="backend_drm_gbm" + - FEATURES="backend_drm_egl" + - FEATURES="backend_egl" - FEATURES="backend_libinput" - FEATURES="backend_udev" - FEATURES="backend_session" - FEATURES="backend_session_logind" + - FEATURES="renderer_gl" - FEATURES="renderer_glium" - FEATURES="xwayland" # test default features From f74af7ba18d9dfbea6aab72e874248c8e76bdf11 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 09:43:08 +0100 Subject: [PATCH 12/56] udev: use same order for bind arguments --- src/backend/udev.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 4ae69a8..0bdc487 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -101,8 +101,8 @@ impl Drop for UdevBackend { /// Allows the backend to receive kernel events and thus to drive the `UdevHandler`. /// No runtime functionality can be provided without using this function. pub fn udev_backend_bind( - handle: &LoopHandle, udev: UdevBackend, + handle: &LoopHandle, ) -> Result>>>, InsertError>>>> { let mut source = Generic::from_fd_source(udev); source.set_interest(Ready::readable()); From 9e5dad4c2351625330002ac2a8e667e0e533dacc Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 09:43:39 +0100 Subject: [PATCH 13/56] session: export OFlag --- src/backend/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/session/mod.rs b/src/backend/session/mod.rs index d6c07cb..2eeeee8 100644 --- a/src/backend/session/mod.rs +++ b/src/backend/session/mod.rs @@ -10,7 +10,7 @@ //! The following mechanisms are currently provided: //! - direct - legacy tty / virtual terminal kernel API //! -use nix::fcntl::OFlag; +pub use nix::fcntl::OFlag; use std::{ cell::RefCell, os::unix::io::RawFd, From f8499e533a1c8658bfa4dcb06de8d4cc3ced6ebc Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 09:44:05 +0100 Subject: [PATCH 14/56] libinput: fix warning when not building backend_session --- src/backend/libinput.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index 8ffc7e1..199575e 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -6,6 +6,8 @@ use backend::{input as backend, input::Axis}; use input as libinput; use input::event; +#[cfg(feature = "backend_session")] +use std::path::Path; use std::{ collections::hash_map::{DefaultHasher, Entry, HashMap}, hash::{Hash, Hasher}, From f17e37465b69b890ad31a4a8d14e29d27d3fa7a3 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 10:04:19 +0100 Subject: [PATCH 15/56] drm: Remove associated Return type from Device --- src/backend/drm/egl/mod.rs | 51 +++------- src/backend/drm/gbm/egl.rs | 51 +++------- src/backend/drm/gbm/mod.rs | 55 ++++------- src/backend/drm/gbm/session.rs | 17 ++-- src/backend/drm/gbm/surface.rs | 159 ++++++++++++++++++++---------- src/backend/drm/legacy/mod.rs | 21 ++-- src/backend/drm/legacy/session.rs | 4 +- src/backend/drm/legacy/surface.rs | 94 ++++++++++++++++-- src/backend/drm/mod.rs | 13 +-- 9 files changed, 262 insertions(+), 203 deletions(-) diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index e4570c4..ccd7fd2 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -1,8 +1,8 @@ use drm::control::{crtc, Mode}; use std::cell::RefCell; -use std::collections::HashMap; +use std::iter::FromIterator; use std::os::unix::io::{AsRawFd, RawFd}; -use std::rc::{Rc, Weak}; +use std::rc::Rc; use wayland_server::Display; use super::{Device, DeviceHandler, Surface}; @@ -28,7 +28,6 @@ pub struct EglDevice< ::Surface: NativeSurface, { dev: Rc>>, - backends: Rc>>>>, logger: ::slog::Logger, } @@ -85,7 +84,6 @@ where dev: Rc::new(RefCell::new( EGLContext::new(dev, attributes, Default::default(), log.clone()).map_err(Error::from)?, )), - backends: Rc::new(RefCell::new(HashMap::new())), logger: log, }) } @@ -98,36 +96,18 @@ struct InternalDeviceHandler< ::Surface: NativeSurface, { handler: Box> + 'static>, - backends: Weak>>>>, - logger: ::slog::Logger, } impl::Surface> + 'static, D: Device + NativeDisplay + 'static> DeviceHandler for InternalDeviceHandler where - >::Arguments: From<( - crtc::Handle, - Mode, - <::Surface as Surface>::Connectors, - )>, + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { type Device = D; - fn vblank(&mut self, surface: &::Surface) { - if let Some(backends) = self.backends.upgrade() { - if let Some(surface) = backends.borrow().get(&surface.crtc()) { - if let Some(surface) = surface.upgrade() { - self.handler.vblank(&*surface); - } - } else { - warn!( - self.logger, - "Surface ({:?}) not managed by egl, event not handled.", - surface.crtc() - ); - } - } + fn vblank(&mut self, crtc: crtc::Handle) { + self.handler.vblank(crtc) } fn error(&mut self, error: <::Surface as Surface>::Error) { self.handler @@ -138,21 +118,14 @@ where impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Device for EglDevice where - >::Arguments: From<( - crtc::Handle, - Mode, - <::Surface as Surface>::Connectors, - )>, + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { type Surface = EglSurface; - type Return = Rc>; fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.dev.borrow_mut().set_handler(InternalDeviceHandler { handler: Box::new(handler), - backends: Rc::downgrade(&self.backends), - logger: self.logger.clone(), }); } @@ -164,21 +137,19 @@ where &mut self, crtc: crtc::Handle, mode: Mode, - connectors: impl Into<<::Surface as Surface>::Connectors>, - ) -> Result>> { + connectors: impl IntoIterator, + ) -> Result> { info!(self.logger, "Initializing EglSurface"); let surface = self .dev .borrow_mut() - .create_surface((crtc, mode, connectors.into()).into())?; + .create_surface((crtc, mode, Vec::from_iter(connectors)).into())?; - let backend = Rc::new(EglSurface { + Ok(EglSurface { dev: self.dev.clone(), surface, - }); - self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); - Ok(backend) + }) } fn process_events(&mut self) { diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index edac7ec..742f66b 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -1,4 +1,4 @@ -use backend::drm::{Device, RawDevice, RawSurface, Surface}; +use backend::drm::{connector, Device, RawDevice, RawSurface, Surface}; use backend::egl::error::Result as EglResult; use backend::egl::ffi; use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; @@ -9,23 +9,17 @@ use super::{GbmDevice, GbmSurface}; use drm::control::{crtc, Device as ControlDevice, Mode}; use gbm::AsRaw; +use std::iter::{FromIterator, IntoIterator}; use std::marker::PhantomData; use std::ptr; -use std::rc::Rc; /// Gbm backend type -pub struct Gbm -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +pub struct Gbm { _userdata: PhantomData, } -impl Backend for Gbm -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ - type Surface = Rc>; +impl Backend for Gbm { + type Surface = GbmSurface; unsafe fn get_display( display: ffi::NativeDisplayType, @@ -52,37 +46,27 @@ where } /// Arguments necessary to construct a `GbmSurface` -pub struct SurfaceArguments -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +pub struct SurfaceArguments { /// Crtc pub crtc: crtc::Handle, /// Mode pub mode: Mode, /// Connectors - pub connectors: as Surface>::Connectors, + pub connectors: Vec, } -impl From<(crtc::Handle, Mode, as Surface>::Connectors)> - for SurfaceArguments -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ - fn from((crtc, mode, connectors): (crtc::Handle, Mode, as Surface>::Connectors)) -> Self { +impl From<(crtc::Handle, Mode, Vec)> for SurfaceArguments { + fn from((crtc, mode, connectors): (crtc::Handle, Mode, Vec)) -> Self { SurfaceArguments { crtc, mode, - connectors, + connectors: Vec::from_iter(connectors), } } } -unsafe impl NativeDisplay> for GbmDevice -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ - type Arguments = SurfaceArguments; +unsafe impl NativeDisplay> for GbmDevice { + type Arguments = SurfaceArguments; type Error = Error; fn is_backend(&self) -> bool { @@ -93,24 +77,21 @@ where Ok(self.dev.borrow().as_raw() as *const _) } - fn create_surface(&mut self, args: SurfaceArguments) -> Result>> { + fn create_surface(&mut self, args: SurfaceArguments) -> Result> { Device::create_surface(self, args.crtc, args.mode, args.connectors) } } -unsafe impl NativeSurface for Rc> -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +unsafe impl NativeSurface for GbmSurface { fn ptr(&self) -> ffi::NativeWindowType { - self.surface.borrow().as_raw() as *const _ + self.0.surface.borrow().as_raw() as *const _ } fn swap_buffers(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> where F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, { - if ::std::borrow::Borrow::borrow(&self.crtc).commit_pending() { + if self.0.crtc.commit_pending() { self.recreate(flip).map_err(|_| SwapBuffersError::ContextLost) } else { self.page_flip(flip) diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index d13f06a..212d8e1 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -1,6 +1,6 @@ use super::{Device, DeviceHandler, RawDevice, Surface}; -use drm::control::{crtc, framebuffer, Device as ControlDevice, Mode}; +use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use std::cell::{Cell, RefCell}; @@ -14,6 +14,7 @@ use self::error::*; mod surface; pub use self::surface::GbmSurface; +use self::surface::GbmSurfaceInternal; pub mod egl; @@ -23,19 +24,13 @@ pub mod session; static LOAD: Once = ONCE_INIT; /// Representation of an open gbm device to create rendering backends -pub struct GbmDevice -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +pub struct GbmDevice { pub(self) dev: Rc>>, - backends: Rc>>>>, + backends: Rc>>>>, logger: ::slog::Logger, } -impl GbmDevice -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +impl GbmDevice { /// Create a new `GbmDevice` from an open drm node /// /// Returns an error if the file is no valid drm node or context creation was not @@ -73,33 +68,26 @@ where } } -struct InternalDeviceHandler -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +struct InternalDeviceHandler { handler: Box> + 'static>, - backends: Weak>>>>, + backends: Weak>>>>, logger: ::slog::Logger, } -impl DeviceHandler for InternalDeviceHandler -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +impl DeviceHandler for InternalDeviceHandler { type Device = D; - fn vblank(&mut self, surface: &::Surface) { + fn vblank(&mut self, crtc: crtc::Handle) { if let Some(backends) = self.backends.upgrade() { - if let Some(surface) = backends.borrow().get(&surface.crtc()) { + if let Some(surface) = backends.borrow().get(&crtc) { if let Some(surface) = surface.upgrade() { surface.unlock_buffer(); - self.handler.vblank(&*surface); + self.handler.vblank(crtc); } } else { warn!( self.logger, - "Surface ({:?}) not managed by gbm, event not handled.", - surface.crtc() + "Surface ({:?}) not managed by gbm, event not handled.", crtc ); } } @@ -110,12 +98,8 @@ where } } -impl Device for GbmDevice -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +impl Device for GbmDevice { type Surface = GbmSurface; - type Return = Rc>; fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.dev.borrow_mut().set_handler(InternalDeviceHandler { @@ -133,8 +117,8 @@ where &mut self, crtc: crtc::Handle, mode: Mode, - connectors: impl Into<::Connectors>, - ) -> Result>> { + connectors: impl IntoIterator, + ) -> Result> { info!(self.logger, "Initializing GbmSurface"); let (w, h) = mode.size(); @@ -173,7 +157,7 @@ where (0, 0), )); - let backend = Rc::new(GbmSurface { + let backend = Rc::new(GbmSurfaceInternal { dev: self.dev.clone(), surface: RefCell::new(surface), crtc: Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) @@ -185,7 +169,7 @@ where logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))), }); self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); - Ok(backend) + Ok(GbmSurface(backend)) } fn process_events(&mut self) { @@ -193,10 +177,7 @@ where } } -impl AsRawFd for GbmDevice -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +impl AsRawFd for GbmDevice { fn as_raw_fd(&self) -> RawFd { self.dev.borrow().as_raw_fd() } diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs index 70b1059..ffb1948 100644 --- a/src/backend/drm/gbm/session.rs +++ b/src/backend/drm/gbm/session.rs @@ -5,26 +5,22 @@ use std::collections::HashMap; use std::os::unix::io::RawFd; use std::rc::{Rc, Weak}; -use super::{GbmDevice, GbmSurface}; -use backend::drm::{Device, RawDevice, RawSurface}; +use super::{GbmDevice, GbmSurfaceInternal}; +use backend::drm::{RawDevice, RawSurface}; use backend::session::{AsSessionObserver, SessionObserver}; /// `SessionObserver` linked to the `DrmDevice` it was created from. pub struct GbmDeviceObserver< S: SessionObserver + 'static, D: RawDevice + ControlDevice + AsSessionObserver + 'static, -> where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +> { observer: S, - backends: Weak>>>>, + backends: Weak>>>>, logger: ::slog::Logger, } impl + 'static> AsSessionObserver> for GbmDevice -where - ::Return: ::std::borrow::Borrow<::Surface>, { fn observer(&mut self) -> GbmDeviceObserver { GbmDeviceObserver { @@ -37,8 +33,6 @@ where impl + 'static> SessionObserver for GbmDeviceObserver -where - ::Return: ::std::borrow::Borrow<::Surface>, { fn pause(&mut self, devnum: Option<(u32, u32)>) { self.observer.pause(devnum); @@ -51,7 +45,8 @@ where for (crtc, backend) in backends.borrow().iter() { if let Some(backend) = backend.upgrade() { // restart rendering loop - if let Err(err) = ::std::borrow::Borrow::borrow(&backend.crtc) + if let Err(err) = &backend + .crtc .page_flip(backend.current_frame_buffer.get().handle()) { warn!(self.logger, "Failed to restart rendering loop. Error: {}", err); diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index f8ab680..bff5f2c 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -1,7 +1,7 @@ use super::super::{Device, RawDevice, RawSurface, Surface}; use super::error::*; -use drm::control::{connector, crtc, framebuffer, Mode, ResourceInfo}; +use drm::control::{connector, crtc, framebuffer, Mode, ResourceHandles, ResourceInfo}; use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle}; use image::{ImageBuffer, Rgba}; @@ -9,17 +9,14 @@ use std::cell::{Cell, RefCell}; use std::os::unix::io::AsRawFd; use std::rc::Rc; -use backend::drm::legacy::{LegacyDrmDevice, LegacyDrmSurface}; +use backend::drm::legacy::LegacyDrmDevice; use backend::graphics::CursorBackend; use backend::graphics::SwapBuffersError; -pub struct GbmSurface -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +pub(super) struct GbmSurfaceInternal { pub(super) dev: Rc>>, pub(super) surface: RefCell>, - pub(super) crtc: ::Return, + pub(super) crtc: ::Surface, pub(super) cursor: Cell<(BufferObject<()>, (u32, u32))>, pub(super) current_frame_buffer: Cell, pub(super) front_buffer: Cell>, @@ -27,10 +24,7 @@ where pub(super) logger: ::slog::Logger, } -impl GbmSurface -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +impl GbmSurfaceInternal { pub(super) fn unlock_buffer(&self) { // after the page swap is finished we need to release the rendered buffer. // this is called from the PageFlipHandler @@ -79,15 +73,14 @@ where let fb = if let Some(info) = maybe_fb { info } else { - let fb = framebuffer::create(::std::borrow::Borrow::borrow(&self.crtc), &*next_bo) - .map_err(|_| SwapBuffersError::ContextLost)?; + let fb = framebuffer::create(&self.crtc, &*next_bo).map_err(|_| SwapBuffersError::ContextLost)?; next_bo.set_userdata(fb).unwrap(); fb }; self.next_buffer.set(Some(next_bo)); trace!(self.logger, "Queueing Page flip"); - ::std::borrow::Borrow::borrow(&self.crtc).page_flip(fb.handle())?; + self.crtc.page_flip(fb.handle())?; self.current_frame_buffer.set(fb); @@ -119,9 +112,7 @@ where { if let Some(mut old_bo) = self.next_buffer.take() { if let Ok(Some(fb)) = old_bo.take_userdata() { - if let Err(err) = - framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()) - { + if let Err(err) = framebuffer::destroy(&self.crtc, fb.handle()) { warn!( self.logger, "Error releasing old back_buffer framebuffer: {:?}", err @@ -141,10 +132,10 @@ where debug!(self.logger, "FrontBuffer color format: {:?}", front_bo.format()); // we also need a new framebuffer for the front buffer - let fb = framebuffer::create(::std::borrow::Borrow::borrow(&self.crtc), &*front_bo) + let fb = framebuffer::create(&self.crtc, &*front_bo) .chain_err(|| ErrorKind::UnderlyingBackendError)?; - ::std::borrow::Borrow::borrow(&self.crtc) + self.crtc .commit(fb.handle()) .chain_err(|| ErrorKind::UnderlyingBackendError)?; @@ -152,7 +143,7 @@ where front_bo }); if let Ok(Some(fb)) = old_front_bo.take_userdata() { - if let Err(err) = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()) { + if let Err(err) = framebuffer::destroy(&self.crtc, fb.handle()) { warn!( self.logger, "Error releasing old front_buffer framebuffer: {:?}", err @@ -167,47 +158,44 @@ where } } -impl Surface for GbmSurface -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +impl Surface for GbmSurfaceInternal { type Connectors = <::Surface as Surface>::Connectors; type Error = Error; fn crtc(&self) -> crtc::Handle { - ::std::borrow::Borrow::borrow(&self.crtc).crtc() + self.crtc.crtc() } fn current_connectors(&self) -> Self::Connectors { - ::std::borrow::Borrow::borrow(&self.crtc).current_connectors() + self.crtc.current_connectors() } fn pending_connectors(&self) -> Self::Connectors { - ::std::borrow::Borrow::borrow(&self.crtc).pending_connectors() + self.crtc.pending_connectors() } fn add_connector(&self, connector: connector::Handle) -> Result<()> { - ::std::borrow::Borrow::borrow(&self.crtc) + self.crtc .add_connector(connector) .chain_err(|| ErrorKind::UnderlyingBackendError) } fn remove_connector(&self, connector: connector::Handle) -> Result<()> { - ::std::borrow::Borrow::borrow(&self.crtc) + self.crtc .remove_connector(connector) .chain_err(|| ErrorKind::UnderlyingBackendError) } fn current_mode(&self) -> Mode { - ::std::borrow::Borrow::borrow(&self.crtc).current_mode() + self.crtc.current_mode() } fn pending_mode(&self) -> Mode { - ::std::borrow::Borrow::borrow(&self.crtc).pending_mode() + self.crtc.pending_mode() } fn use_mode(&self, mode: Mode) -> Result<()> { - ::std::borrow::Borrow::borrow(&self.crtc) + self.crtc .use_mode(mode) .chain_err(|| ErrorKind::UnderlyingBackendError) } @@ -218,9 +206,8 @@ where // Option 1: When there is GAT support, impl `GraphicsBackend` for `LegacyDrmBackend` // using a new generic `B: Buffer` and use this: /* -impl<'a, D: RawDevice + 'static> CursorBackend<'a> for GbmSurface +impl<'a, D: RawDevice + 'static> CursorBackend<'a> for GbmSurfaceInternal where - ::Return: ::std::borrow::Borrow<::Surface>, ::Surface: CursorBackend<'a>, <::Surface as CursorBackend<'a>>::CursorFormat: Buffer, <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send @@ -229,9 +216,8 @@ where // // Option 2: When equality checks in where clauses are supported, we could at least do this: /* -impl<'a, D: RawDevice + 'static> GraphicsBackend<'a> for GbmSurface +impl<'a, D: RawDevice + 'static> GraphicsBackend<'a> for GbmSurfaceInternal where - ::Return: ::std::borrow::Borrow<::Surface>, ::Surface: CursorBackend<'a>, <::Surface as CursorBackend<'a>>::CursorFormat=&'a Buffer, <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send @@ -239,15 +225,14 @@ where */ // But for now got to do this: -impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface> { +impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal> { type CursorFormat = &'a ImageBuffer, Vec>; type Error = Error; fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { - ResultExt::chain_err( - ::std::borrow::Borrow::>>::borrow(&self.crtc).set_cursor_position(x, y), - || ErrorKind::UnderlyingBackendError, - ) + ResultExt::chain_err(self.crtc.set_cursor_position(x, y), || { + ErrorKind::UnderlyingBackendError + }) } fn set_cursor_representation<'b>( @@ -279,11 +264,9 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface>>::borrow(&self.crtc) - .set_cursor_representation(&cursor, hotspot), - || ErrorKind::UnderlyingBackendError, - )?; + ResultExt::chain_err(self.crtc.set_cursor_representation(&cursor, hotspot), || { + ErrorKind::UnderlyingBackendError + })?; // and store it self.cursor.set((cursor, hotspot)); @@ -291,10 +274,7 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface Drop for GbmSurface -where - ::Return: ::std::borrow::Borrow<::Surface>, -{ +impl Drop for GbmSurfaceInternal { fn drop(&mut self) { // Drop framebuffers attached to the userdata of the gbm surface buffers. // (They don't implement drop, as they need the device) @@ -308,12 +288,87 @@ where } } { // ignore failure at this point - let _ = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()); + let _ = framebuffer::destroy(&self.crtc, fb.handle()); } if let Ok(Some(fb)) = self.front_buffer.get_mut().take_userdata() { // ignore failure at this point - let _ = framebuffer::destroy(::std::borrow::Borrow::borrow(&self.crtc), fb.handle()); + let _ = framebuffer::destroy(&self.crtc, fb.handle()); } } } + +pub struct GbmSurface(pub(super) Rc>); + +impl GbmSurface { + pub fn page_flip(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> + where + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, + { + self.0.page_flip(flip) + } + + pub fn recreate(&self, flip: F) -> Result<()> + where + F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, + { + self.0.recreate(flip) + } +} + +impl Surface for GbmSurface { + type Connectors = <::Surface as Surface>::Connectors; + type Error = Error; + + fn crtc(&self) -> crtc::Handle { + self.0.crtc() + } + + fn current_connectors(&self) -> Self::Connectors { + self.0.current_connectors() + } + + fn pending_connectors(&self) -> Self::Connectors { + self.0.pending_connectors() + } + + fn add_connector(&self, connector: connector::Handle) -> Result<()> { + self.0.add_connector(connector) + } + + fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + self.0.remove_connector(connector) + } + + fn current_mode(&self) -> Mode { + self.0.current_mode() + } + + fn pending_mode(&self) -> Mode { + self.0.pending_mode() + } + + fn use_mode(&self, mode: Mode) -> Result<()> { + self.0.use_mode(mode) + } +} + +impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface> { + type CursorFormat = &'a ImageBuffer, Vec>; + type Error = Error; + + fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { + self.0.set_cursor_position(x, y) + } + + fn set_cursor_representation<'b>( + &'b self, + buffer: &ImageBuffer, Vec>, + hotspot: (u32, u32), + ) -> Result<()> + where + 'a: 'b, + { + self.0.set_cursor_representation(buffer, hotspot) + } +} diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 1bea1ad..bb2e50a 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -7,6 +7,7 @@ use nix::sys::stat::fstat; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; +use std::iter::FromIterator; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -14,7 +15,7 @@ use std::sync::{Arc, RwLock}; mod surface; pub use self::surface::LegacyDrmSurface; -use self::surface::State; +use self::surface::{LegacyDrmSurfaceInternal, State}; pub mod error; use self::error::*; @@ -28,7 +29,7 @@ pub struct LegacyDrmDevice { priviledged: bool, active: Arc, old_state: HashMap)>, - backends: Rc>>>>, + backends: Rc>>>>, handler: Option>>>>, logger: ::slog::Logger, } @@ -120,7 +121,6 @@ impl ControlDevice for LegacyDrmDevice {} impl Device for LegacyDrmDevice { type Surface = LegacyDrmSurface; - type Return = Rc>; fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.handler = Some(RefCell::new(Box::new(handler))); @@ -134,8 +134,8 @@ impl Device for LegacyDrmDevice { &mut self, crtc: crtc::Handle, mode: Mode, - connectors: impl Into<::Connectors>, - ) -> Result>> { + connectors: impl IntoIterator, + ) -> Result> { if self.backends.borrow().contains_key(&crtc) { bail!(ErrorKind::CrtcAlreadyInUse(crtc)); } @@ -144,7 +144,7 @@ impl Device for LegacyDrmDevice { bail!(ErrorKind::DeviceInactive); } - let connectors: HashSet<_> = connectors.into(); + let connectors = HashSet::from_iter(connectors); // check if we have an encoder for every connector and the mode mode for connector in &connectors { let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| { @@ -184,7 +184,7 @@ impl Device for LegacyDrmDevice { let state = State { mode, connectors }; - let backend = Rc::new(LegacyDrmSurface { + let backend = Rc::new(LegacyDrmSurfaceInternal { dev: self.dev.clone(), crtc, state: RwLock::new(state.clone()), @@ -193,7 +193,7 @@ impl Device for LegacyDrmDevice { }); self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); - Ok(backend) + Ok(LegacyDrmSurface(backend)) } fn process_events(&mut self) { @@ -201,17 +201,18 @@ impl Device for LegacyDrmDevice { Ok(events) => for event in events { if let crtc::Event::PageFlip(event) = event { if self.active.load(Ordering::SeqCst) { - if let Some(backend) = self + if self .backends .borrow() .get(&event.crtc) .iter() .flat_map(|x| x.upgrade()) .next() + .is_some() { trace!(self.logger, "Handling event for backend {:?}", event.crtc); if let Some(handler) = self.handler.as_ref() { - handler.borrow_mut().vblank(&backend); + handler.borrow_mut().vblank(event.crtc); } } else { self.backends.borrow_mut().remove(&event.crtc); diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs index dc319c0..5d00f0a 100644 --- a/src/backend/drm/legacy/session.rs +++ b/src/backend/drm/legacy/session.rs @@ -9,7 +9,7 @@ use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use super::{Dev, LegacyDrmDevice, LegacyDrmSurface}; +use super::{Dev, LegacyDrmDevice, LegacyDrmSurfaceInternal}; use backend::session::{AsSessionObserver, SessionObserver}; /// `SessionObserver` linked to the `DrmDevice` it was created from. @@ -19,7 +19,7 @@ pub struct LegacyDrmDeviceObserver { priviledged: bool, active: Arc, old_state: HashMap)>, - backends: Weak>>>>, + backends: Weak>>>>, logger: ::slog::Logger, } diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index 6b6d021..36a58d7 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -19,7 +19,7 @@ pub struct State { pub connectors: HashSet, } -pub struct LegacyDrmSurface { +pub(super) struct LegacyDrmSurfaceInternal { pub(super) dev: Rc>, pub(super) crtc: crtc::Handle, pub(super) state: RwLock, @@ -27,16 +27,16 @@ pub struct LegacyDrmSurface { pub(super) logger: ::slog::Logger, } -impl AsRawFd for LegacyDrmSurface { +impl AsRawFd for LegacyDrmSurfaceInternal { fn as_raw_fd(&self) -> RawFd { self.dev.as_raw_fd() } } -impl BasicDevice for LegacyDrmSurface {} -impl ControlDevice for LegacyDrmSurface {} +impl BasicDevice for LegacyDrmSurfaceInternal {} +impl ControlDevice for LegacyDrmSurfaceInternal {} -impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { +impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurfaceInternal { type CursorFormat = &'a Buffer; type Error = Error; @@ -61,7 +61,7 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { } } -impl Surface for LegacyDrmSurface { +impl Surface for LegacyDrmSurfaceInternal { type Error = Error; type Connectors = HashSet; @@ -149,7 +149,7 @@ impl Surface for LegacyDrmSurface { } } -impl RawSurface for LegacyDrmSurface { +impl RawSurface for LegacyDrmSurfaceInternal { fn commit_pending(&self) -> bool { *self.pending.read().unwrap() != *self.state.read().unwrap() } @@ -220,9 +220,87 @@ impl RawSurface for LegacyDrmSurface { } } -impl Drop for LegacyDrmSurface { +impl Drop for LegacyDrmSurfaceInternal { fn drop(&mut self) { // ignore failure at this point let _ = crtc::clear_cursor(self, self.crtc); } } + +pub struct LegacyDrmSurface(pub(super) Rc>); + +impl AsRawFd for LegacyDrmSurface { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl BasicDevice for LegacyDrmSurface {} +impl ControlDevice for LegacyDrmSurface {} + +impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { + type CursorFormat = &'a Buffer; + type Error = Error; + + fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { + self.0.set_cursor_position(x, y) + } + + fn set_cursor_representation<'b>(&'b self, buffer: Self::CursorFormat, hotspot: (u32, u32)) -> Result<()> + where + 'a: 'b, + { + self.0.set_cursor_representation(buffer, hotspot) + } +} + +impl Surface for LegacyDrmSurface { + type Error = Error; + type Connectors = HashSet; + + fn crtc(&self) -> crtc::Handle { + self.0.crtc() + } + + fn current_connectors(&self) -> Self::Connectors { + self.0.current_connectors() + } + + fn pending_connectors(&self) -> Self::Connectors { + self.0.pending_connectors() + } + + fn current_mode(&self) -> Mode { + self.0.current_mode() + } + + fn pending_mode(&self) -> Mode { + self.0.pending_mode() + } + + fn add_connector(&self, connector: connector::Handle) -> Result<()> { + self.0.add_connector(connector) + } + + fn remove_connector(&self, connector: connector::Handle) -> Result<()> { + self.0.remove_connector(connector) + } + + fn use_mode(&self, mode: Mode) -> Result<()> { + self.0.use_mode(mode) + } +} + +impl RawSurface for LegacyDrmSurface { + fn commit_pending(&self) -> bool { + self.0.commit_pending() + } + + fn commit(&self, framebuffer: framebuffer::Handle) -> Result<()> { + self.0.commit(framebuffer) + } + + fn page_flip(&self, framebuffer: framebuffer::Handle) -> ::std::result::Result<(), SwapBuffersError> { + self.0.page_flip(framebuffer) + } +} diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 1a2d05c..0912051 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -7,6 +7,7 @@ use drm::Device as BasicDevice; use std::borrow::Borrow; use std::error::Error; +use std::iter::IntoIterator; use std::os::unix::io::AsRawFd; use std::path::PathBuf; @@ -26,13 +27,12 @@ pub mod legacy; pub trait DeviceHandler { type Device: Device + ?Sized; - fn vblank(&mut self, surface: &<::Device as Device>::Surface); + fn vblank(&mut self, crtc: crtc::Handle); fn error(&mut self, error: <<::Device as Device>::Surface as Surface>::Error); } pub trait Device: AsRawFd + DevPath { type Surface: Surface; - type Return: Borrow; fn set_handler(&mut self, handler: impl DeviceHandler + 'static); fn clear_handler(&mut self); @@ -40,15 +40,12 @@ pub trait Device: AsRawFd + DevPath { &mut self, ctrc: crtc::Handle, mode: Mode, - connectors: impl Into<::Connectors>, - ) -> Result::Error>; + connectors: impl IntoIterator, + ) -> Result::Error>; fn process_events(&mut self); } -pub trait RawDevice: Device::Surface> -where - ::Return: Borrow<::Surface>, -{ +pub trait RawDevice: Device::Surface> { type Surface: RawSurface; } From 2675cf94dce4f1c9021d51ab381d3a44b20cb1f5 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 10:06:59 +0100 Subject: [PATCH 16/56] egl_surface: fix CursorBackend implementation --- src/backend/drm/egl/surface.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 9e97168..634310b 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -70,14 +70,13 @@ where impl<'a, B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static> CursorBackend<'a> for EglSurface where - D: CursorBackend<'a>, - ::Surface: NativeSurface, + ::Surface: NativeSurface + CursorBackend<'a>, { - type CursorFormat = >::CursorFormat; - type Error = >::Error; + type CursorFormat = >::CursorFormat; + type Error = >::Error; fn set_cursor_position(&self, x: u32, y: u32) -> ::std::result::Result<(), Self::Error> { - self.dev.borrow().set_cursor_position(x, y) + self.surface.set_cursor_position(x, y) } fn set_cursor_representation<'b>( @@ -88,8 +87,7 @@ where where 'a: 'b, { - let dev = self.dev.borrow(); - dev.set_cursor_representation(buffer, hotspot) + self.surface.set_cursor_representation(buffer, hotspot) } } From de526f4b2316867daad87e12f61ce8251e9844c9 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 10:07:17 +0100 Subject: [PATCH 17/56] drm: Add functions to query device state --- src/backend/drm/egl/mod.rs | 21 ++++++++++++++++++++- src/backend/drm/gbm/mod.rs | 21 ++++++++++++++++++++- src/backend/drm/legacy/mod.rs | 24 +++++++++++++++++------- src/backend/drm/mod.rs | 18 +++++++++++------- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index ccd7fd2..802cf30 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -1,4 +1,5 @@ -use drm::control::{crtc, Mode}; +use drm::control::{connector, crtc, Mode, ResourceHandles, ResourceInfo}; +use nix::libc::dev_t; use std::cell::RefCell; use std::iter::FromIterator; use std::os::unix::io::{AsRawFd, RawFd}; @@ -123,6 +124,10 @@ where { type Surface = EglSurface; + fn device_id(&self) -> dev_t { + self.dev.borrow().device_id() + } + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.dev.borrow_mut().set_handler(InternalDeviceHandler { handler: Box::new(handler), @@ -155,6 +160,20 @@ where fn process_events(&mut self) { self.dev.borrow_mut().process_events() } + + fn resource_info(&self, handle: T::Handle) -> Result { + self.dev + .borrow() + .resource_info(handle) + .chain_err(|| ErrorKind::UnderlyingBackendError) + } + + fn resource_handles(&self) -> Result { + self.dev + .borrow() + .resource_handles() + .chain_err(|| ErrorKind::UnderlyingBackendError) + } } impl::Surface> + 'static, D: Device + NativeDisplay + 'static> diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 212d8e1..34d0fe0 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -1,7 +1,8 @@ -use super::{Device, DeviceHandler, RawDevice, Surface}; +use super::{Device, DeviceHandler, RawDevice, ResourceHandles, ResourceInfo, Surface}; use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; use gbm::{self, BufferObjectFlags, Format as GbmFormat}; +use nix::libc::dev_t; use std::cell::{Cell, RefCell}; use std::collections::HashMap; @@ -101,6 +102,10 @@ impl DeviceHandler for InternalDeviceHan impl Device for GbmDevice { type Surface = GbmSurface; + fn device_id(&self) -> dev_t { + self.dev.borrow().device_id() + } + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.dev.borrow_mut().set_handler(InternalDeviceHandler { handler: Box::new(handler), @@ -175,6 +180,20 @@ impl Device for GbmDevice { fn process_events(&mut self) { self.dev.borrow_mut().process_events() } + + fn resource_info(&self, handle: T::Handle) -> Result { + self.dev + .borrow() + .resource_info(handle) + .chain_err(|| ErrorKind::UnderlyingBackendError) + } + + fn resource_handles(&self) -> Result { + self.dev + .borrow() + .resource_handles() + .chain_err(|| ErrorKind::UnderlyingBackendError) + } } impl AsRawFd for GbmDevice { diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index bb2e50a..4459c15 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -1,6 +1,6 @@ use super::{DevPath, Device, DeviceHandler, RawDevice, Surface}; -use drm::control::{connector, crtc, encoder, Device as ControlDevice, Mode, ResourceInfo}; +use drm::control::{connector, crtc, encoder, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo}; use drm::Device as BasicDevice; use nix::libc::dev_t; use nix::sys::stat::fstat; @@ -78,7 +78,7 @@ impl LegacyDrmDevice { drm.priviledged = false; }; - let res_handles = drm.resource_handles().chain_err(|| { + let res_handles = ControlDevice::resource_handles(&drm).chain_err(|| { ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path())) })?; for &con in res_handles.connectors() { @@ -104,10 +104,6 @@ impl LegacyDrmDevice { Ok(drm) } - - pub fn dev_id(&self) -> dev_t { - self.dev_id - } } impl AsRawFd for LegacyDrmDevice { @@ -122,6 +118,10 @@ impl ControlDevice for LegacyDrmDevice {} impl Device for LegacyDrmDevice { type Surface = LegacyDrmSurface; + fn device_id(&self) -> dev_t { + self.dev_id + } + fn set_handler(&mut self, handler: impl DeviceHandler + 'static) { self.handler = Some(RefCell::new(Box::new(handler))); } @@ -167,7 +167,7 @@ impl Device for LegacyDrmDevice { }).collect::>>()?; // and if any encoder supports the selected crtc - let resource_handles = self.resource_handles().chain_err(|| { + let resource_handles = ControlDevice::resource_handles(self).chain_err(|| { ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) })?; if !encoders @@ -229,6 +229,16 @@ impl Device for LegacyDrmDevice { }, } } + + fn resource_info(&self, handle: T::Handle) -> Result { + T::load_from_device(self, handle) + .chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path()))) + } + + fn resource_handles(&self) -> Result { + ControlDevice::resource_handles(self) + .chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path()))) + } } impl RawDevice for LegacyDrmDevice { diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 0912051..2b60f5d 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -1,11 +1,9 @@ -pub use drm::control::connector; -pub use drm::control::crtc; -pub use drm::control::framebuffer; -use drm::control::Device as ControlDevice; -pub use drm::control::Mode; -use drm::Device as BasicDevice; +pub use drm::{ + control::{connector, crtc, framebuffer, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo}, + Device as BasicDevice, +}; +pub use nix::libc::dev_t; -use std::borrow::Borrow; use std::error::Error; use std::iter::IntoIterator; use std::os::unix::io::AsRawFd; @@ -34,6 +32,7 @@ pub trait DeviceHandler { pub trait Device: AsRawFd + DevPath { type Surface: Surface; + fn device_id(&self) -> dev_t; fn set_handler(&mut self, handler: impl DeviceHandler + 'static); fn clear_handler(&mut self); fn create_surface( @@ -43,6 +42,11 @@ pub trait Device: AsRawFd + DevPath { connectors: impl IntoIterator, ) -> Result::Error>; fn process_events(&mut self); + fn resource_info( + &self, + handle: T::Handle, + ) -> Result::Error>; + fn resource_handles(&self) -> Result::Error>; } pub trait RawDevice: Device::Surface> { From 91e237f697442696664493e11bc66fcd4feeb42f Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 10:08:09 +0100 Subject: [PATCH 18/56] anvil: remove raw_tty backend --- anvil/src/main.rs | 11 --- anvil/src/raw_drm.rs | 169 ------------------------------------------- 2 files changed, 180 deletions(-) delete mode 100644 anvil/src/raw_drm.rs diff --git a/anvil/src/main.rs b/anvil/src/main.rs index ce4523e..b920d2e 100644 --- a/anvil/src/main.rs +++ b/anvil/src/main.rs @@ -16,8 +16,6 @@ use smithay::wayland_server::{calloop::EventLoop, Display}; mod shaders; mod glium_drawer; mod input_handler; -#[cfg(feature = "tty_launch")] -mod raw_drm; mod shell; mod shm_load; #[cfg(feature = "udev")] @@ -29,8 +27,6 @@ mod winit; static POSSIBLE_BACKENDS: &'static [&'static str] = &[ #[cfg(feature = "winit")] "--winit : Run anvil as a X11 or Wayland client using winit.", - #[cfg(feature = "tty_launch")] - "--tty-raw : Run anvil as a raw DRM client (requires root).", #[cfg(feature = "udev")] "--tty-udev : Run anvil as a tty udev client (requires root if without logind).", ]; @@ -54,13 +50,6 @@ fn main() { crit!(log, "Failed to initialize winit backend."); } } - #[cfg(feature = "tty_launch")] - Some("--tty-raw") => { - info!(log, "Starting anvil on a tty using raw DRM"); - if let Err(()) = raw_drm::run_raw_drm(display, event_loop, log.clone()) { - crit!(log, "Failed to initialize tty backend."); - } - } #[cfg(feature = "udev")] Some("--tty-udev") => { info!(log, "Starting anvil on a tty using udev"); diff --git a/anvil/src/raw_drm.rs b/anvil/src/raw_drm.rs deleted file mode 100644 index 0d0388f..0000000 --- a/anvil/src/raw_drm.rs +++ /dev/null @@ -1,169 +0,0 @@ -use std::{ - cell::RefCell, - fs::{File, OpenOptions}, - os::unix::io::{AsRawFd, RawFd}, - rc::Rc, - time::Duration, -}; - -use smithay::{ - backend::{ - drm::{drm_device_bind, DrmBackend, DrmDevice, DrmHandler}, - graphics::egl::wayland::EGLWaylandExtensions, - }, - drm::{ - control::{ - connector::{Info as ConnectorInfo, State as ConnectorState}, - crtc, - encoder::Info as EncoderInfo, - Device as ControlDevice, ResourceInfo, - }, - result::Error as DrmError, - Device as BasicDevice, - }, - wayland::{compositor::CompositorToken, shm::init_shm_global}, - wayland_server::{calloop::EventLoop, Display}, -}; - -use glium::Surface; -use slog::Logger; - -use glium_drawer::GliumDrawer; -use shell::{init_shell, MyWindowMap, Roles, SurfaceData}; - -#[derive(Debug)] -pub struct Card(File); - -impl AsRawFd for Card { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl BasicDevice for Card {} -impl ControlDevice for Card {} - -pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop<()>, log: Logger) -> Result<(), ()> { - /* - * Initialize the drm backend - */ - // "Find" a suitable drm device - let mut options = OpenOptions::new(); - options.read(true); - options.write(true); - let mut device = - DrmDevice::new(Card(options.clone().open("/dev/dri/card0").unwrap()), log.clone()).unwrap(); - - // Get a set of all modesetting resource handles (excluding planes): - let res_handles = device.resource_handles().unwrap(); - - // Use first connected connector - let connector_info = res_handles - .connectors() - .iter() - .map(|conn| ConnectorInfo::load_from_device(&device, *conn).unwrap()) - .find(|conn| conn.connection_state() == ConnectorState::Connected) - .unwrap(); - - // Use the first encoder - let encoder_info = EncoderInfo::load_from_device(&device, connector_info.encoders()[0]).unwrap(); - - // use the connected crtc if any - let crtc = encoder_info - .current_crtc() - // or use the first one that is compatible with the encoder - .unwrap_or_else(|| { - *res_handles - .filter_crtcs(encoder_info.possible_crtcs()) - .iter() - .next() - .unwrap() - }); - - // Assuming we found a good connector and loaded the info into `connector_info` - let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) - - // Initialize the hardware backend - let backend = device - .create_backend(crtc, mode, vec![connector_info.handle()]) - .unwrap(); - let egl_display = Rc::new(RefCell::new( - if let Ok(egl_display) = backend.bind_wl_display(&display) { - info!(log, "EGL hardware-acceleration enabled"); - Some(egl_display) - } else { - None - }, - )); - let renderer = GliumDrawer::init(backend, egl_display, log.clone()); - { - /* - * Initialize Glium - */ - let mut frame = renderer.draw(); - frame.clear_color(0.8, 0.8, 0.9, 1.0); - frame.finish().unwrap(); - } - - /* - * Initialize the globals - */ - - init_shm_global(&mut display, vec![], log.clone()); - - let (compositor_token, _, _, window_map) = init_shell(&mut display, log.clone()); - - /* - * Add a listening socket: - */ - let name = display.add_socket_auto().unwrap().into_string().unwrap(); - println!("Listening on socket: {}", name); - - /* - * Register the DrmDevice on the EventLoop - */ - let _source = drm_device_bind( - &event_loop.handle(), - device, - DrmHandlerImpl { - compositor_token, - window_map: window_map.clone(), - drawer: renderer, - logger: log, - }, - ).map_err(|(err, _)| err) - .unwrap(); - - loop { - event_loop - .dispatch(Some(::std::time::Duration::from_millis(16)), &mut ()) - .unwrap(); - display.flush_clients(); - - window_map.borrow_mut().refresh(); - } -} - -pub struct DrmHandlerImpl { - compositor_token: CompositorToken, - window_map: Rc>, - drawer: GliumDrawer>, - logger: ::slog::Logger, -} - -impl DrmHandler for DrmHandlerImpl { - fn ready( - &mut self, - _device: &mut DrmDevice, - _crtc: crtc::Handle, - _frame: u32, - _duration: Duration, - ) { - self.drawer - .draw_windows(&*self.window_map.borrow(), self.compositor_token, &self.logger); - } - - fn error(&mut self, _device: &mut DrmDevice, error: DrmError) { - panic!("{:?}", error); - } -} From db495ce4dc698b773d6a0b89947c44339cc2c3fa Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 10:10:01 +0100 Subject: [PATCH 19/56] Add backend_session to default, as it is not implied by backend_udev anymore --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b65e227..cbc43bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ lazy_static = "1.0.0" gl_generator = { version = "0.9", optional = true } [features] -default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "renderer_glium", "xwayland"] +default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session", "renderer_glium", "xwayland"] backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl"] backend_drm = ["drm"] backend_drm_legacy = ["backend_drm"] From 9428853ad60e1659ccb5a8061a9f367808589b7e Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 10:10:30 +0100 Subject: [PATCH 20/56] anvil: fix for drm backend changes --- anvil/Cargo.toml | 5 +- anvil/src/glium_drawer.rs | 28 ++---- anvil/src/udev.rs | 186 ++++++++++++++++++++++---------------- anvil/src/winit.rs | 6 +- 4 files changed, 121 insertions(+), 104 deletions(-) diff --git a/anvil/Cargo.toml b/anvil/Cargo.toml index fec642d..d7deafe 100644 --- a/anvil/Cargo.toml +++ b/anvil/Cargo.toml @@ -23,8 +23,7 @@ features = [ "renderer_glium" ] gl_generator = "0.9" [features] -default = [ "winit", "tty_launch", "udev" ] +default = [ "winit", "udev" ] winit = [ "smithay/backend_winit" ] -tty_launch = [ "smithay/backend_libinput", "smithay/backend_drm" ] -udev = [ "tty_launch", "smithay/backend_udev" ] +udev = [ "smithay/backend_libinput", "smithay/backend_drm", "smithay/backend_udev", "smithay/backend_session" ] logind = [ "smithay/backend_session_logind" ] diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index 135ed5f..d384ac0 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -12,19 +12,15 @@ use glium::{ use slog::Logger; use smithay::{ - backend::graphics::{ - egl::{ - error::Result as EGLResult, - wayland::{BufferAccessError, EGLDisplay, EGLImages, EGLWaylandExtensions, Format}, - EGLGraphicsBackend, - }, - glium::GliumGraphicsBackend, + backend::{ + egl::{BufferAccessError, EGLDisplay, EGLImages, Format}, + graphics::{gl::GLGraphicsBackend, glium::GliumGraphicsBackend}, }, wayland::{ compositor::{roles::Role, SubsurfaceRole, TraversalAction}, shm::with_buffer_contents as shm_buffer_contents, }, - wayland_server::{protocol::wl_buffer, Display, Resource}, + wayland_server::{protocol::wl_buffer, Resource}, }; use shaders; @@ -38,7 +34,7 @@ struct Vertex { implement_vertex!(Vertex, position, tex_coords); -pub struct GliumDrawer { +pub struct GliumDrawer { display: GliumGraphicsBackend, vertex_buffer: glium::VertexBuffer, index_buffer: glium::IndexBuffer, @@ -47,13 +43,13 @@ pub struct GliumDrawer { log: Logger, } -impl GliumDrawer { +impl GliumDrawer { pub fn borrow(&self) -> Ref { self.display.borrow() } } -impl> + EGLGraphicsBackend + 'static> GliumDrawer { +impl> + GLGraphicsBackend + 'static> GliumDrawer { pub fn init(backend: T, egl_display: Rc>>, log: Logger) -> GliumDrawer { let display = backend.into(); @@ -97,7 +93,7 @@ impl> + EGLGraphicsBackend + 'static> GliumDrawe } } -impl GliumDrawer { +impl GliumDrawer { pub fn texture_from_buffer(&self, buffer: Resource) -> Result { // try to retrieve the egl contents of this buffer let images = if let Some(display) = &self.egl_display.borrow().as_ref() { @@ -217,12 +213,6 @@ impl GliumDrawer { } } -impl EGLWaylandExtensions for GliumDrawer { - fn bind_wl_display(&self, display: &Display) -> EGLResult { - self.display.bind_wl_display(display) - } -} - pub struct TextureMetadata { pub texture: Texture2d, pub fragment: usize, @@ -231,7 +221,7 @@ pub struct TextureMetadata { images: Option, } -impl GliumDrawer { +impl GliumDrawer { pub fn draw_windows(&self, window_map: &MyWindowMap, compositor_token: MyCompositorToken, log: &Logger) { let mut frame = self.draw(); frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None); diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index a3de2aa..ccbfbef 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -2,41 +2,42 @@ use std::{ cell::RefCell, collections::HashMap, io::Error as IoError, + os::unix::io::{AsRawFd, RawFd}, path::PathBuf, rc::Rc, sync::{ atomic::{AtomicBool, Ordering}, Arc, }, - time::Duration, }; -use glium::Surface; +use glium::Surface as GliumSurface; use slog::Logger; use smithay::{ backend::{ - drm::{DevPath, DrmBackend, DrmDevice, DrmHandler}, - graphics::{ - egl::wayland::{EGLDisplay, EGLWaylandExtensions}, - GraphicsBackend, + drm::{ + dev_t, + egl::{EglDevice, EglSurface}, + gbm::{egl::Gbm as EglGbmBackend, GbmDevice}, + legacy::LegacyDrmDevice, + DevPath, Device, DeviceHandler, Surface, }, + egl::{EGLDisplay, EGLGraphicsBackend}, + graphics::CursorBackend, input::InputBackend, libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}, session::{ auto::{auto_session_bind, AutoSession}, - Session, SessionNotifier, + OFlag, Session, SessionNotifier, }, - udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler}, + udev::{primary_gpu, udev_backend_bind, UdevBackend, UdevHandler}, }, - drm::{ - control::{ - connector::{Info as ConnectorInfo, State as ConnectorState}, - crtc, - encoder::Info as EncoderInfo, - Device as ControlDevice, ResourceInfo, - }, - result::Error as DrmError, + drm::control::{ + connector::{Info as ConnectorInfo, State as ConnectorState}, + crtc, + encoder::Info as EncoderInfo, + ResourceInfo, }, image::{ImageBuffer, Rgba}, input::Libinput, @@ -54,6 +55,18 @@ use glium_drawer::GliumDrawer; use input_handler::AnvilInputHandler; use shell::{init_shell, MyWindowMap, Roles, SurfaceData}; +pub struct SessionFd(RawFd); +impl AsRawFd for SessionFd { + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +type RenderDevice = + EglDevice>, GbmDevice>>; +type RenderSurface = + EglSurface>, GbmDevice>>; + pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger) -> Result<(), ()> { let name = display.add_socket_auto().unwrap().into_string().unwrap(); info!(log, "Listening on wayland socket"; "name" => name.clone()); @@ -88,13 +101,12 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger let primary_gpu = primary_gpu(&context, &seat).unwrap_or_default(); let bytes = include_bytes!("../resources/cursor2.rgba"); - let mut udev_backend = UdevBackend::new( - event_loop.handle(), + let udev_backend = UdevBackend::new( &context, - session.clone(), UdevHandlerImpl { compositor_token, active_egl_context, + session: session.clone(), backends: HashMap::new(), display: display.clone(), primary_gpu, @@ -103,11 +115,10 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(), logger: log.clone(), }, + seat.clone(), log.clone(), ).map_err(|_| ())?; - let udev_session_id = notifier.register(&mut udev_backend); - init_data_device( &mut display.borrow_mut(), |_| {}, @@ -171,13 +182,14 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger session, )); let libinput_event_source = libinput_bind(libinput_backend, event_loop.handle()) - .map_err(|(e, _)| e) + .map_err(|e| -> IoError { e.into() }) .unwrap(); - let session_event_source = auto_session_bind(notifier, &event_loop.handle()) .map_err(|(e, _)| e) .unwrap(); - let udev_event_source = udev_backend_bind(udev_backend).unwrap(); + let udev_event_source = udev_backend_bind(udev_backend, &event_loop.handle()) + .map_err(|e| -> IoError { e.into() }) + .unwrap(); while running.load(Ordering::SeqCst) { if event_loop @@ -192,7 +204,6 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger } let mut notifier = session_event_source.unbind(); - notifier.unregister(udev_session_id); notifier.unregister(libinput_session_id); libinput_event_source.remove(); @@ -204,7 +215,14 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger struct UdevHandlerImpl { compositor_token: CompositorToken, active_egl_context: Rc>>, - backends: HashMap>>>>>, + session: AutoSession, + backends: HashMap< + dev_t, + ( + RenderDevice, + Rc>>>, + ), + >, display: Rc>, primary_gpu: Option, window_map: Rc>, @@ -215,10 +233,11 @@ struct UdevHandlerImpl { impl UdevHandlerImpl { pub fn scan_connectors( - &self, - device: &mut DrmDevice, + device: &mut RenderDevice, egl_display: Rc>>, - ) -> HashMap>> { + pointer_image: &ImageBuffer, Vec>, + logger: &::slog::Logger, + ) -> HashMap> { // Get a set of all modesetting resource handles (excluding planes): let res_handles = device.resource_handles().unwrap(); @@ -226,9 +245,9 @@ impl UdevHandlerImpl { let connector_infos: Vec = res_handles .connectors() .iter() - .map(|conn| ConnectorInfo::load_from_device(device, *conn).unwrap()) + .map(|conn| device.resource_info::(*conn).unwrap()) .filter(|conn| conn.connection_state() == ConnectorState::Connected) - .inspect(|conn| info!(self.logger, "Connected: {:?}", conn.connector_type())) + .inspect(|conn| info!(logger, "Connected: {:?}", conn.connector_type())) .collect(); let mut backends = HashMap::new(); @@ -238,7 +257,7 @@ impl UdevHandlerImpl { let encoder_infos = connector_info .encoders() .iter() - .flat_map(|encoder_handle| EncoderInfo::load_from_device(device, *encoder_handle)) + .flat_map(|encoder_handle| device.resource_info::(*encoder_handle)) .collect::>(); for encoder_info in encoder_infos { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { @@ -247,16 +266,16 @@ impl UdevHandlerImpl { // create a backend let renderer = GliumDrawer::init( device - .create_backend(crtc, mode, vec![connector_info.handle()]) + .create_surface(crtc, mode, vec![connector_info.handle()].into_iter()) .unwrap(), egl_display.clone(), - self.logger.clone(), + logger.clone(), ); // create cursor renderer .borrow() - .set_cursor_representation(&self.pointer_image, (2, 2)) + .set_cursor_representation(pointer_image, (2, 2)) .unwrap(); // render first frame @@ -277,64 +296,77 @@ impl UdevHandlerImpl { } } -impl UdevHandler for UdevHandlerImpl { - fn device_added(&mut self, device: &mut DrmDevice) -> Option { - // init hardware acceleration on the primary gpu. - if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { - *self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok(); +impl UdevHandler for UdevHandlerImpl { + fn device_added(&mut self, _device: dev_t, path: PathBuf) { + if let Some(mut device) = self + .session + .open( + &path, + OFlag::O_RDWR | OFlag::O_CLOEXEC | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, + ).ok() + .and_then(|fd| LegacyDrmDevice::new(SessionFd(fd), self.logger.clone()).ok()) + .and_then(|drm| GbmDevice::new(drm, self.logger.clone()).ok()) + .and_then(|gbm| EglDevice::new(gbm, self.logger.clone()).ok()) + { + // init hardware acceleration on the primary gpu. + if path.canonicalize().ok() == self.primary_gpu { + *self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok(); + } + + let backends = Rc::new(RefCell::new(UdevHandlerImpl::scan_connectors( + &mut device, + self.active_egl_context.clone(), + &self.pointer_image, + &self.logger, + ))); + + device.set_handler(DrmHandlerImpl { + compositor_token: self.compositor_token, + backends: backends.clone(), + window_map: self.window_map.clone(), + pointer_location: self.pointer_location.clone(), + logger: self.logger.clone(), + }); + + self.backends.insert(device.device_id(), (device, backends)); } - - let backends = Rc::new(RefCell::new( - self.scan_connectors(device, self.active_egl_context.clone()), - )); - self.backends.insert(device.device_id(), backends.clone()); - - Some(DrmHandlerImpl { - compositor_token: self.compositor_token, - backends, - window_map: self.window_map.clone(), - pointer_location: self.pointer_location.clone(), - logger: self.logger.clone(), - }) } - fn device_changed(&mut self, device: &mut DrmDevice) { - //quick and dirt, just re-init all backends - let backends = &self.backends[&device.device_id()]; - *backends.borrow_mut() = self.scan_connectors(device, self.active_egl_context.clone()); + fn device_changed(&mut self, device: dev_t) { + //quick and dirty, just re-init all backends + if let Some((ref mut device, ref backends)) = self.backends.get_mut(&device) { + *backends.borrow_mut() = UdevHandlerImpl::scan_connectors( + device, + self.active_egl_context.clone(), + &self.pointer_image, + &self.logger, + ); + } } - fn device_removed(&mut self, device: &mut DrmDevice) { + fn device_removed(&mut self, device: dev_t) { // drop the backends on this side - self.backends.remove(&device.device_id()); - - // don't use hardware acceleration anymore, if this was the primary gpu - if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { - *self.active_egl_context.borrow_mut() = None; + if let Some((dev, _)) = self.backends.remove(&device) { + // don't use hardware acceleration anymore, if this was the primary gpu + if dev.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { + *self.active_egl_context.borrow_mut() = None; + } } } - - fn error(&mut self, error: IoError) { - error!(self.logger, "{:?}", error); - } } pub struct DrmHandlerImpl { compositor_token: CompositorToken, - backends: Rc>>>>, + backends: Rc>>>, window_map: Rc>, pointer_location: Rc>, logger: ::slog::Logger, } -impl DrmHandler for DrmHandlerImpl { - fn ready( - &mut self, - _device: &mut DrmDevice, - crtc: crtc::Handle, - _frame: u32, - _duration: Duration, - ) { +impl DeviceHandler for DrmHandlerImpl { + type Device = RenderDevice; + + fn vblank(&mut self, crtc: crtc::Handle) { if let Some(drawer) = self.backends.borrow().get(&crtc) { { let (x, y) = *self.pointer_location.borrow(); @@ -347,7 +379,7 @@ impl DrmHandler for DrmHandlerImpl { } } - fn error(&mut self, _device: &mut DrmDevice, error: DrmError) { + fn error(&mut self, error: ::Error) { error!(self.logger, "{:?}", error); } } diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 4d191bd..2c3c2b0 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -5,11 +5,7 @@ use std::{ }; use smithay::{ - backend::{ - graphics::egl::{wayland::EGLWaylandExtensions, EGLGraphicsBackend}, - input::InputBackend, - winit, - }, + backend::{egl::EGLGraphicsBackend, graphics::gl::GLGraphicsBackend, input::InputBackend, winit}, wayland::{ data_device::{default_action_chooser, init_data_device, set_data_device_focus}, output::{Mode, Output, PhysicalProperties}, From 10e74e29485e9dea6482cba0e29fa0372db6fbc8 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 10:14:23 +0100 Subject: [PATCH 21/56] build: fix build without gl-features --- build.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.rs b/build.rs index b119e11..9ae8ecb 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,11 @@ +#[cfg(any(feature = "backend_egl", feature = "backend_gl"))] extern crate gl_generator; +#[cfg(any(feature = "backend_egl", feature = "backend_gl"))] use gl_generator::{Api, Fallbacks, Profile, Registry}; use std::{env, fs::File, path::PathBuf}; +#[cfg(any(feature = "backend_egl", feature = "backend_gl"))] fn main() { let dest = PathBuf::from(&env::var("OUT_DIR").unwrap()); @@ -46,3 +49,6 @@ fn main() { .unwrap(); } } + +#[cfg(not(any(feature = "backend_egl", feature = "backend_gl")))] +fn main() {} \ No newline at end of file From cea123cd0b3e0109fd93021292554c56a495670c Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 11:39:56 +0100 Subject: [PATCH 22/56] backend_winit: depends on renderer_gl --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cbc43bd..c352770 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ gl_generator = { version = "0.9", optional = true } [features] default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session", "renderer_glium", "xwayland"] -backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl"] +backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl", "renderer_gl"] backend_drm = ["drm"] backend_drm_legacy = ["backend_drm"] backend_drm_gbm = ["backend_drm", "gbm"] From 59e0ad87f944b93f68fd6d9c5a7ecc19172a9ae2 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 11:40:35 +0100 Subject: [PATCH 23/56] gbm: do not expose egl support, if backend_egl is not enabled --- src/backend/drm/gbm/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 34d0fe0..208c317 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -17,6 +17,7 @@ mod surface; pub use self::surface::GbmSurface; use self::surface::GbmSurfaceInternal; +#[cfg(feature = "backend_egl")] pub mod egl; #[cfg(feature = "backend_session")] From d07c66985f1f8620d6864ad801d4265eb0d6940e Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 11:40:56 +0100 Subject: [PATCH 24/56] gbm: CursorBackend depends on backend_drm_legacy --- src/backend/drm/gbm/surface.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index bff5f2c..97f4e5c 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -9,6 +9,7 @@ use std::cell::{Cell, RefCell}; use std::os::unix::io::AsRawFd; use std::rc::Rc; +#[cfg(feature = "backend_drm_legacy")] use backend::drm::legacy::LegacyDrmDevice; use backend::graphics::CursorBackend; use backend::graphics::SwapBuffersError; @@ -225,6 +226,7 @@ where */ // But for now got to do this: +#[cfg(feature = "backend_drm_legacy")] impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal> { type CursorFormat = &'a ImageBuffer, Vec>; type Error = Error; @@ -353,6 +355,7 @@ impl Surface for GbmSurface { } } +#[cfg(feature = "backend_drm_legacy")] impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurface> { type CursorFormat = &'a ImageBuffer, Vec>; type Error = Error; From 7e3217f96d0461c1cd110e7bc2216df8394bcc52 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 11:41:15 +0100 Subject: [PATCH 25/56] lib: fix feature names for crate imports --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 24e5b49..422b947 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,13 +21,13 @@ extern crate xkbcommon; pub extern crate dbus; #[cfg(feature = "backend_drm")] pub extern crate drm; -#[cfg(feature = "backend_drm")] +#[cfg(feature = "backend_drm_gbm")] pub extern crate gbm; #[cfg(feature = "backend_libinput")] pub extern crate input; #[cfg(feature = "backend_session_logind")] pub extern crate systemd; -#[cfg(feature = "udev")] +#[cfg(feature = "backend_udev")] pub extern crate udev; #[cfg(feature = "backend_winit")] extern crate wayland_client; From 079ad953a460bd3f4b592b2f63e977c7ea094f0a Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 12:13:11 +0100 Subject: [PATCH 26/56] build: fix wrongly named feature --- build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.rs b/build.rs index 9ae8ecb..c19c4f7 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,7 @@ -#[cfg(any(feature = "backend_egl", feature = "backend_gl"))] +#[cfg(any(feature = "backend_egl", feature = "renderer_gl"))] extern crate gl_generator; -#[cfg(any(feature = "backend_egl", feature = "backend_gl"))] +#[cfg(any(feature = "backend_egl", feature = "renderer_gl"))] use gl_generator::{Api, Fallbacks, Profile, Registry}; use std::{env, fs::File, path::PathBuf}; @@ -50,5 +50,5 @@ fn main() { } } -#[cfg(not(any(feature = "backend_egl", feature = "backend_gl")))] +#[cfg(not(any(feature = "backend_egl", feature = "renderer_gl")))] fn main() {} \ No newline at end of file From 9a82de6fae870da8fd83087329995478956796e0 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 12:20:31 +0100 Subject: [PATCH 27/56] graphics: Move PixelFormat out of gl module --- src/backend/drm/egl/surface.rs | 6 +++++- src/backend/egl/context.rs | 2 +- src/backend/egl/mod.rs | 1 + src/backend/graphics/format.rs | 22 ++++++++++++++++++++++ src/backend/graphics/gl.rs | 25 +------------------------ src/backend/graphics/mod.rs | 3 +++ src/backend/winit.rs | 4 ++-- 7 files changed, 35 insertions(+), 28 deletions(-) create mode 100644 src/backend/graphics/format.rs diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 634310b..682338c 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -7,7 +7,10 @@ use super::error::*; use backend::drm::{Device, Surface}; use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use backend::egl::{EGLContext, EGLSurface}; -use backend::graphics::gl::{GLGraphicsBackend, PixelFormat}; +#[cfg(feature = "renderer_gl")] +use backend::graphics::gl::GLGraphicsBackend; +#[cfg(feature = "renderer_gl")] +use backend::graphics::PixelFormat; use backend::graphics::{CursorBackend, SwapBuffersError}; pub struct EglSurface< @@ -91,6 +94,7 @@ where } } +#[cfg(feature = "renderer_gl")] impl::Surface> + 'static, D: Device + NativeDisplay + 'static> GLGraphicsBackend for EglSurface where diff --git a/src/backend/egl/context.rs b/src/backend/egl/context.rs index 070c07a..28f8c70 100644 --- a/src/backend/egl/context.rs +++ b/src/backend/egl/context.rs @@ -1,7 +1,7 @@ //! EGL context related structs use super::{error::*, ffi, native, EGLSurface}; -use backend::graphics::gl::PixelFormat; +use backend::graphics::PixelFormat; use nix::libc::{c_int, c_void}; use slog; use std::{ diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index 3516c15..dfafee9 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -337,6 +337,7 @@ impl EGLDisplay { context: &EGLContext, display: *mut wl_display, ) -> EGLDisplay { + #[cfg(feature = "renderer_gl")] let gl = gl_ffi::Gles2::load_with(|s| unsafe { context.get_proc_address(s) as *const _ }); EGLDisplay { diff --git a/src/backend/graphics/format.rs b/src/backend/graphics/format.rs new file mode 100644 index 0000000..7b3176d --- /dev/null +++ b/src/backend/graphics/format.rs @@ -0,0 +1,22 @@ +/// Describes the pixel format of a framebuffer +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PixelFormat { + /// is the format hardware accelerated + pub hardware_accelerated: bool, + /// number of bits used for colors + pub color_bits: u8, + /// number of bits used for alpha channel + pub alpha_bits: u8, + /// number of bits used for depth channel + pub depth_bits: u8, + /// number of bits used for stencil buffer + pub stencil_bits: u8, + /// is stereoscopy enabled + pub stereoscopy: bool, + /// is double buffering enabled + pub double_buffer: bool, + /// number of samples used for multisampling if enabled + pub multisampling: Option, + /// is srgb enabled + pub srgb: bool, +} \ No newline at end of file diff --git a/src/backend/graphics/gl.rs b/src/backend/graphics/gl.rs index 78c3c9f..a39ce14 100644 --- a/src/backend/graphics/gl.rs +++ b/src/backend/graphics/gl.rs @@ -1,6 +1,6 @@ use nix::libc::c_void; -use super::SwapBuffersError; +use super::{SwapBuffersError, PixelFormat}; #[cfg_attr(feature = "cargo-clippy", allow(clippy))] #[allow(missing_docs)] @@ -10,29 +10,6 @@ pub(crate) mod ffi { pub use self::ffi::Gles2; -/// Describes the pixel format of the main framebuffer -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct PixelFormat { - /// is the format hardware accelerated - pub hardware_accelerated: bool, - /// number of bits used for colors - pub color_bits: u8, - /// number of bits used for alpha channel - pub alpha_bits: u8, - /// number of bits used for depth channel - pub depth_bits: u8, - /// number of bits used for stencil buffer - pub stencil_bits: u8, - /// is stereoscopy enabled - pub stereoscopy: bool, - /// is double buffering enabled - pub double_buffer: bool, - /// number of samples used for multisampling if enabled - pub multisampling: Option, - /// is srgb enabled - pub srgb: bool, -} - /// Trait that describes objects that have an OpenGL context /// and can be used to render upon pub trait GLGraphicsBackend { diff --git a/src/backend/graphics/mod.rs b/src/backend/graphics/mod.rs index abac583..188e1c0 100644 --- a/src/backend/graphics/mod.rs +++ b/src/backend/graphics/mod.rs @@ -8,6 +8,9 @@ pub use self::errors::*; mod cursor; pub use self::cursor::*; +mod format; +pub use self::format::*; + #[cfg(feature = "renderer_gl")] pub mod gl; #[cfg(feature = "renderer_glium")] diff --git a/src/backend/winit.rs b/src/backend/winit.rs index fef1f74..af2dd3f 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -6,8 +6,8 @@ use backend::{ EGLDisplay, EGLGraphicsBackend, EGLSurface, }, graphics::{ - gl::{GLGraphicsBackend, PixelFormat}, - CursorBackend, SwapBuffersError, + gl::GLGraphicsBackend, + CursorBackend, SwapBuffersError, PixelFormat, }, input::{ Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, From 8824e49b82d6f25fb469e8864572afc56683b76d Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 18:21:44 +0100 Subject: [PATCH 28/56] build: finally fix all features naming --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index c19c4f7..e843e05 100644 --- a/build.rs +++ b/build.rs @@ -5,7 +5,7 @@ extern crate gl_generator; use gl_generator::{Api, Fallbacks, Profile, Registry}; use std::{env, fs::File, path::PathBuf}; -#[cfg(any(feature = "backend_egl", feature = "backend_gl"))] +#[cfg(any(feature = "backend_egl", feature = "renderer_gl"))] fn main() { let dest = PathBuf::from(&env::var("OUT_DIR").unwrap()); From e7575d08b87eeef39fcc111e25803380aadc575b Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 18:22:39 +0100 Subject: [PATCH 29/56] gbm: fix calling lock_front_buffer without eglSwapBuffers --- src/backend/drm/gbm/egl.rs | 7 ++++++- src/backend/drm/gbm/mod.rs | 25 +++++++------------------ src/backend/drm/gbm/session.rs | 11 ++++++----- src/backend/drm/gbm/surface.rs | 31 ++++++++++++++++++------------- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 742f66b..372be36 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -91,7 +91,12 @@ unsafe impl NativeSurface for GbmSurface { where F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, { - if self.0.crtc.commit_pending() { + if self.0.crtc.commit_pending() || { + let fb = self.0.front_buffer.take(); + let res = fb.is_none(); + self.0.front_buffer.set(fb); + res + } { self.recreate(flip).map_err(|_| SwapBuffersError::ContextLost) } else { self.page_flip(flip) diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 208c317..a09043f 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -1,6 +1,6 @@ use super::{Device, DeviceHandler, RawDevice, ResourceHandles, ResourceInfo, Surface}; -use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; +use drm::control::{connector, crtc, Device as ControlDevice, Mode}; use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use nix::libc::dev_t; @@ -127,6 +127,9 @@ impl Device for GbmDevice { ) -> Result> { info!(self.logger, "Initializing GbmSurface"); + let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) + .chain_err(|| ErrorKind::UnderlyingBackendError)?; + let (w, h) = mode.size(); let surface = self .dev @@ -138,19 +141,6 @@ impl Device for GbmDevice { BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; - // init the first screen - // (must be done before calling page_flip for the first time) - let mut front_bo = surface - .lock_front_buffer() - .chain_err(|| ErrorKind::FrontBufferLockFailed)?; - - debug!(self.logger, "FrontBuffer color format: {:?}", front_bo.format()); - - // we need a framebuffer for the front buffer - let fb = framebuffer::create(&*self.dev.borrow(), &*front_bo) - .chain_err(|| ErrorKind::UnderlyingBackendError)?; - front_bo.set_userdata(fb).unwrap(); - let cursor = Cell::new(( self.dev .borrow() @@ -166,11 +156,10 @@ impl Device for GbmDevice { let backend = Rc::new(GbmSurfaceInternal { dev: self.dev.clone(), surface: RefCell::new(surface), - crtc: Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) - .chain_err(|| ErrorKind::UnderlyingBackendError)?, + crtc: drm_surface, cursor, - current_frame_buffer: Cell::new(fb), - front_buffer: Cell::new(front_bo), + current_frame_buffer: Cell::new(None), + front_buffer: Cell::new(None), next_buffer: Cell::new(None), logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))), }); diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs index ffb1948..f66245d 100644 --- a/src/backend/drm/gbm/session.rs +++ b/src/backend/drm/gbm/session.rs @@ -44,11 +44,12 @@ impl { pub(super) surface: RefCell>, pub(super) crtc: ::Surface, pub(super) cursor: Cell<(BufferObject<()>, (u32, u32))>, - pub(super) current_frame_buffer: Cell, - pub(super) front_buffer: Cell>, + pub(super) current_frame_buffer: Cell>, + pub(super) front_buffer: Cell>>, pub(super) next_buffer: Cell>>, pub(super) logger: ::slog::Logger, } @@ -31,7 +31,7 @@ impl GbmSurfaceInternal { // this is called from the PageFlipHandler if let Some(next_buffer) = self.next_buffer.replace(None) { trace!(self.logger, "Releasing old front buffer"); - self.front_buffer.set(next_buffer); + self.front_buffer.set(Some(next_buffer)); // drop and release the old buffer } } @@ -83,7 +83,7 @@ impl GbmSurfaceInternal { trace!(self.logger, "Queueing Page flip"); self.crtc.page_flip(fb.handle())?; - self.current_frame_buffer.set(fb); + self.current_frame_buffer.set(Some(fb)); Ok(()) } @@ -96,7 +96,7 @@ impl GbmSurfaceInternal { // Recreate the surface and the related resources to match the new // resolution. - debug!(self.logger, "Reinitializing surface for new mode: {}:{}", w, h); + debug!(self.logger, "(Re-)Initializing surface for mode: {}:{}", w, h); let surface = self .dev .borrow_mut() @@ -107,8 +107,6 @@ impl GbmSurfaceInternal { BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; - flip()?; - // Clean up next_buffer { if let Some(mut old_bo) = self.next_buffer.take() { @@ -123,9 +121,11 @@ impl GbmSurfaceInternal { } } + flip()?; + // Cleanup front_buffer and init the first screen on the new front_buffer // (must be done before calling page_flip for the first time) - let mut old_front_bo = self.front_buffer.replace({ + let old_front_bo = self.front_buffer.replace({ let mut front_bo = surface .lock_front_buffer() .chain_err(|| ErrorKind::FrontBufferLockFailed)?; @@ -140,10 +140,11 @@ impl GbmSurfaceInternal { .commit(fb.handle()) .chain_err(|| ErrorKind::UnderlyingBackendError)?; + self.current_frame_buffer.set(Some(fb)); front_bo.set_userdata(fb).unwrap(); - front_bo + Some(front_bo) }); - if let Ok(Some(fb)) = old_front_bo.take_userdata() { + if let Some(Ok(Some(fb))) = old_front_bo.map(|mut bo| bo.take_userdata()) { if let Err(err) = framebuffer::destroy(&self.crtc, fb.handle()) { warn!( self.logger, @@ -283,8 +284,6 @@ impl Drop for GbmSurfaceInternal { if let Ok(Some(fb)) = { if let Some(mut next) = self.next_buffer.take() { next.take_userdata() - } else if let Ok(mut next) = self.surface.borrow().lock_front_buffer() { - next.take_userdata() } else { Ok(None) } @@ -293,7 +292,13 @@ impl Drop for GbmSurfaceInternal { let _ = framebuffer::destroy(&self.crtc, fb.handle()); } - if let Ok(Some(fb)) = self.front_buffer.get_mut().take_userdata() { + if let Ok(Some(fb)) = { + if let Some(mut next) = self.front_buffer.take() { + next.take_userdata() + } else { + Ok(None) + } + } { // ignore failure at this point let _ = framebuffer::destroy(&self.crtc, fb.handle()); } From d6e7fb591ee38ae6970e223198ec62d8ef6085a7 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 18:22:57 +0100 Subject: [PATCH 30/56] direct: fix udev feature name --- src/backend/session/direct.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index f795b44..d7bc3a9 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -67,7 +67,7 @@ use std::{ Arc, }, }; -#[cfg(feature = "backend_session_udev")] +#[cfg(feature = "backend_udev")] use udev::Context; use wayland_server::calloop::{signals::Signals, LoopHandle, Source}; @@ -120,12 +120,12 @@ const TTY_MAJOR: u64 = 4; #[cfg(not(any(target_os = "linux", target_os = "android")))] const TTY_MAJOR: u64 = 0; -#[cfg(not(feature = "backend_session_udev"))] +#[cfg(not(feature = "backend_udev"))] fn is_tty_device(dev: dev_t, _path: Option<&Path>) -> bool { major(dev) == TTY_MAJOR } -#[cfg(feature = "backend_session_udev")] +#[cfg(feature = "backend_udev")] fn is_tty_device(dev: dev_t, path: Option<&Path>) -> bool { match path { Some(path) => { From 5741ccdd468d7378541283ef852408eb22a1f6fe Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Thu, 22 Nov 2018 22:26:32 +0100 Subject: [PATCH 31/56] gbm: fix EGLSurface recreation --- src/backend/drm/gbm/egl.rs | 25 +++++----- src/backend/drm/gbm/mod.rs | 3 +- src/backend/drm/gbm/session.rs | 10 ++-- src/backend/drm/gbm/surface.rs | 90 +++++++++++----------------------- src/backend/egl/native.rs | 29 ++++++++--- src/backend/egl/surface.rs | 55 +++++++++++++++------ 6 files changed, 111 insertions(+), 101 deletions(-) diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 372be36..45b36bb 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -87,19 +87,20 @@ unsafe impl NativeSurface for GbmSurface { self.0.surface.borrow().as_raw() as *const _ } - fn swap_buffers(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> - where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, - { - if self.0.crtc.commit_pending() || { - let fb = self.0.front_buffer.take(); - let res = fb.is_none(); - self.0.front_buffer.set(fb); - res - } { - self.recreate(flip).map_err(|_| SwapBuffersError::ContextLost) + fn needs_recreation(&self) -> bool { + self.0.crtc.commit_pending() + } + + fn recreate(&self) -> bool { + if let Err(err) = GbmSurface::recreate(self) { + error!(self.0.logger, "Failure recreating internal resources: {:?}", err); + false } else { - self.page_flip(flip) + true } } + + fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { + self.page_flip() + } } diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index a09043f..cbf4c63 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -128,7 +128,7 @@ impl Device for GbmDevice { info!(self.logger, "Initializing GbmSurface"); let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) - .chain_err(|| ErrorKind::UnderlyingBackendError)?; + .chain_err(|| ErrorKind::UnderlyingBackendError)?; let (w, h) = mode.size(); let surface = self @@ -161,6 +161,7 @@ impl Device for GbmDevice { current_frame_buffer: Cell::new(None), front_buffer: Cell::new(None), next_buffer: Cell::new(None), + recreated: Cell::new(true), logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))), }); self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs index f66245d..1894a5f 100644 --- a/src/backend/drm/gbm/session.rs +++ b/src/backend/drm/gbm/session.rs @@ -45,11 +45,11 @@ impl { pub(super) current_frame_buffer: Cell>, pub(super) front_buffer: Cell>>, pub(super) next_buffer: Cell>>, + pub(super) recreated: Cell, pub(super) logger: ::slog::Logger, } @@ -29,17 +30,12 @@ impl GbmSurfaceInternal { pub(super) fn unlock_buffer(&self) { // after the page swap is finished we need to release the rendered buffer. // this is called from the PageFlipHandler - if let Some(next_buffer) = self.next_buffer.replace(None) { - trace!(self.logger, "Releasing old front buffer"); - self.front_buffer.set(Some(next_buffer)); - // drop and release the old buffer - } + trace!(self.logger, "Releasing old front buffer"); + self.front_buffer.set(self.next_buffer.replace(None)); + // drop and release the old buffer } - pub fn page_flip(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> - where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, - { + pub fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { let res = { let nb = self.next_buffer.take(); let res = nb.is_some(); @@ -52,9 +48,6 @@ impl GbmSurfaceInternal { return Err(SwapBuffersError::AlreadySwapped); } - // flip normally - flip()?; - // supporting only one buffer would cause a lot of inconvinience and // would most likely result in a lot of flickering. // neither weston, wlc or wlroots bother with that as well. @@ -81,17 +74,21 @@ impl GbmSurfaceInternal { self.next_buffer.set(Some(next_bo)); trace!(self.logger, "Queueing Page flip"); - self.crtc.page_flip(fb.handle())?; + if self.recreated.get() { + self.crtc + .commit(fb.handle()) + .map_err(|_| SwapBuffersError::ContextLost)?; + self.recreated.set(false); + } else { + self.crtc.page_flip(fb.handle())?; + } self.current_frame_buffer.set(Some(fb)); Ok(()) } - pub fn recreate(&self, flip: F) -> Result<()> - where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, - { + pub fn recreate(&self) -> Result<()> { let (w, h) = self.pending_mode().size(); // Recreate the surface and the related resources to match the new @@ -107,44 +104,17 @@ impl GbmSurfaceInternal { BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; - // Clean up next_buffer - { - if let Some(mut old_bo) = self.next_buffer.take() { - if let Ok(Some(fb)) = old_bo.take_userdata() { - if let Err(err) = framebuffer::destroy(&self.crtc, fb.handle()) { - warn!( - self.logger, - "Error releasing old back_buffer framebuffer: {:?}", err - ); - } - } + // Clean up buffers + if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) { + if let Err(err) = framebuffer::destroy(&self.crtc, fb.handle()) { + warn!( + self.logger, + "Error releasing old back_buffer framebuffer: {:?}", err + ); } } - flip()?; - - // Cleanup front_buffer and init the first screen on the new front_buffer - // (must be done before calling page_flip for the first time) - let old_front_bo = self.front_buffer.replace({ - let mut front_bo = surface - .lock_front_buffer() - .chain_err(|| ErrorKind::FrontBufferLockFailed)?; - - debug!(self.logger, "FrontBuffer color format: {:?}", front_bo.format()); - - // we also need a new framebuffer for the front buffer - let fb = framebuffer::create(&self.crtc, &*front_bo) - .chain_err(|| ErrorKind::UnderlyingBackendError)?; - - self.crtc - .commit(fb.handle()) - .chain_err(|| ErrorKind::UnderlyingBackendError)?; - - self.current_frame_buffer.set(Some(fb)); - front_bo.set_userdata(fb).unwrap(); - Some(front_bo) - }); - if let Some(Ok(Some(fb))) = old_front_bo.map(|mut bo| bo.take_userdata()) { + if let Some(Ok(Some(fb))) = self.front_buffer.take().map(|mut bo| bo.take_userdata()) { if let Err(err) = framebuffer::destroy(&self.crtc, fb.handle()) { warn!( self.logger, @@ -156,6 +126,8 @@ impl GbmSurfaceInternal { // Drop the old surface after cleanup *self.surface.borrow_mut() = surface; + self.recreated.set(true); + Ok(()) } } @@ -308,18 +280,12 @@ impl Drop for GbmSurfaceInternal { pub struct GbmSurface(pub(super) Rc>); impl GbmSurface { - pub fn page_flip(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> - where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, - { - self.0.page_flip(flip) + pub fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { + self.0.page_flip() } - pub fn recreate(&self, flip: F) -> Result<()> - where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, - { - self.0.recreate(flip) + pub fn recreate(&self) -> Result<()> { + self.0.recreate() } } diff --git a/src/backend/egl/native.rs b/src/backend/egl/native.rs index 2cfb9f7..1edc445 100644 --- a/src/backend/egl/native.rs +++ b/src/backend/egl/native.rs @@ -167,14 +167,31 @@ unsafe impl NativeDisplay for WinitWindow { pub unsafe trait NativeSurface { /// Return a raw pointer egl will accept for surface creation. fn ptr(&self) -> ffi::NativeWindowType; + + /// Will be called to check if any internal resources will need + /// to be recreated. Old resources must be used until `recreate` + /// was called. + /// + /// Only needs to be recreated, if this shall sometimes return true. + /// The default implementation always returns false. + fn needs_recreation(&self) -> bool { + false + } + + /// Instructs the surface to recreate internal resources + /// + /// Must only be implemented if `needs_recreation` can return `true`. + /// Returns true on success. + /// If this call was successful `ptr()` *should* return something different. + fn recreate(&self) -> bool { + true + } + /// Adds additional semantics when calling EGLSurface::swap_buffers /// - /// Only implement if required by the backend, flip must be called during this call. - fn swap_buffers(&self, flip: F) -> ::std::result::Result<(), SwapBuffersError> - where - F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, - { - flip() + /// Only implement if required by the backend. + fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { + Ok(()) } } diff --git a/src/backend/egl/surface.rs b/src/backend/egl/surface.rs index 3e11ce5..3d6b15b 100644 --- a/src/backend/egl/surface.rs +++ b/src/backend/egl/surface.rs @@ -2,7 +2,9 @@ use super::{error::*, ffi, native, EGLContext}; use backend::graphics::SwapBuffersError; +use nix::libc::c_int; use std::{ + cell::Cell, ops::{Deref, DerefMut}, rc::{Rc, Weak}, }; @@ -12,7 +14,9 @@ pub struct EGLSurface { context: Weak, display: Weak, native: N, - surface: ffi::egl::types::EGLSurface, + surface: Cell, + config_id: ffi::egl::types::EGLConfig, + surface_attributes: Vec, } impl Deref for EGLSurface { @@ -50,28 +54,49 @@ impl EGLSurface { context: Rc::downgrade(&context.context), display: Rc::downgrade(&context.display), native, - surface, + surface: Cell::new(surface), + config_id: context.config_id, + surface_attributes: context.surface_attributes.clone(), }) } /// Swaps buffers at the end of a frame. pub fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { - self.native.swap_buffers(|| { + let surface = self.surface.get(); + + if !surface.is_null() { if let Some(display) = self.display.upgrade() { - let ret = unsafe { ffi::egl::SwapBuffers((*display) as *const _, self.surface as *const _) }; + let ret = unsafe { ffi::egl::SwapBuffers((*display) as *const _, surface as *const _) }; if ret == 0 { match unsafe { ffi::egl::GetError() } as u32 { - ffi::egl::CONTEXT_LOST => Err(SwapBuffersError::ContextLost), - err => Err(SwapBuffersError::Unknown(err)), - } + ffi::egl::CONTEXT_LOST => return Err(SwapBuffersError::ContextLost), + err => return Err(SwapBuffersError::Unknown(err)), + }; } else { - Ok(()) + return Ok(()); } } else { - Err(SwapBuffersError::ContextLost) + return Err(SwapBuffersError::ContextLost); } - }) + self.native.swap_buffers()?; + }; + + if self.native.needs_recreation() || surface.is_null() { + if let Some(display) = self.display.upgrade() { + self.native.recreate(); + self.surface.set(unsafe { + ffi::egl::CreateWindowSurface( + *display, + self.config_id, + self.native.ptr(), + self.surface_attributes.as_ptr(), + ) + }); + } + } + + Ok(()) } /// Makes the OpenGL context the current context in the current thread. @@ -84,8 +109,8 @@ impl EGLSurface { if let (Some(display), Some(context)) = (self.display.upgrade(), self.context.upgrade()) { let ret = ffi::egl::MakeCurrent( (*display) as *const _, - self.surface as *const _, - self.surface as *const _, + self.surface.get() as *const _, + self.surface.get() as *const _, (*context) as *const _, ); @@ -106,8 +131,8 @@ impl EGLSurface { pub fn is_current(&self) -> bool { if self.context.upgrade().is_some() { unsafe { - ffi::egl::GetCurrentSurface(ffi::egl::DRAW as _) == self.surface as *const _ - && ffi::egl::GetCurrentSurface(ffi::egl::READ as _) == self.surface as *const _ + ffi::egl::GetCurrentSurface(ffi::egl::DRAW as _) == self.surface.get() as *const _ + && ffi::egl::GetCurrentSurface(ffi::egl::READ as _) == self.surface.get() as *const _ } } else { false @@ -119,7 +144,7 @@ impl Drop for EGLSurface { fn drop(&mut self) { if let Some(display) = self.display.upgrade() { unsafe { - ffi::egl::DestroySurface((*display) as *const _, self.surface as *const _); + ffi::egl::DestroySurface((*display) as *const _, self.surface.get() as *const _); } } } From 0ed69bf2dad234496fb6b0e404a30555b9809d93 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Fri, 23 Nov 2018 15:10:51 +0100 Subject: [PATCH 32/56] session: Add multiplexer --- anvil/src/udev.rs | 105 ++++++++++++++++++++--------- src/backend/drm/legacy/session.rs | 6 +- src/backend/session/auto.rs | 22 +----- src/backend/session/dbus/logind.rs | 18 +---- src/backend/session/direct.rs | 18 ++--- src/backend/session/mod.rs | 10 +-- src/backend/session/multi.rs | 64 ++++++++++++++++++ 7 files changed, 152 insertions(+), 91 deletions(-) create mode 100644 src/backend/session/multi.rs diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index ccbfbef..e85b9c6 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -17,7 +17,7 @@ use slog::Logger; use smithay::{ backend::{ drm::{ - dev_t, + dev_t, device_bind, egl::{EglDevice, EglSurface}, gbm::{egl::Gbm as EglGbmBackend, GbmDevice}, legacy::LegacyDrmDevice, @@ -29,7 +29,7 @@ use smithay::{ libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}, session::{ auto::{auto_session_bind, AutoSession}, - OFlag, Session, SessionNotifier, + notify_multiplexer, AsSessionObserver, OFlag, Session, SessionNotifier, }, udev::{primary_gpu, udev_backend_bind, UdevBackend, UdevHandler}, }, @@ -48,7 +48,14 @@ use smithay::{ seat::{Seat, XkbConfig}, shm::init_shm_global, }, - wayland_server::{calloop::EventLoop, protocol::wl_output, Display}, + wayland_server::{ + calloop::{ + generic::{EventedFd, Generic}, + EventLoop, LoopHandle, Source, + }, + protocol::wl_output, + Display, + }, }; use glium_drawer::GliumDrawer; @@ -87,6 +94,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger * Initialize session */ let (session, mut notifier) = AutoSession::new(log.clone()).ok_or(())?; + let (udev_observer, udev_notifier) = notify_multiplexer(); + let udev_session_id = notifier.register(udev_observer); let running = Arc::new(AtomicBool::new(true)); @@ -113,6 +122,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger window_map: window_map.clone(), pointer_location: pointer_location.clone(), pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(), + loop_handle: event_loop.handle(), + notifier: udev_notifier, logger: log.clone(), }, seat.clone(), @@ -168,7 +179,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger */ let mut libinput_context = Libinput::new_from_udev::>(session.clone().into(), &context); - let libinput_session_id = notifier.register(&mut libinput_context); + let libinput_session_id = notifier.register(libinput_context.observer()); libinput_context.udev_assign_seat(&seat).unwrap(); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); libinput_backend.set_handler(AnvilInputHandler::new_with_session( @@ -205,6 +216,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger let mut notifier = session_event_source.unbind(); notifier.unregister(libinput_session_id); + notifier.unregister(udev_session_id); libinput_event_source.remove(); udev_event_source.remove(); @@ -212,14 +224,15 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger Ok(()) } -struct UdevHandlerImpl { +struct UdevHandlerImpl { compositor_token: CompositorToken, active_egl_context: Rc>>, session: AutoSession, backends: HashMap< dev_t, ( - RenderDevice, + S::Id, + Source>>, Rc>>>, ), >, @@ -228,14 +241,15 @@ struct UdevHandlerImpl { window_map: Rc>, pointer_location: Rc>, pointer_image: ImageBuffer, Vec>, + loop_handle: LoopHandle, + notifier: S, logger: ::slog::Logger, } -impl UdevHandlerImpl { +impl UdevHandlerImpl { pub fn scan_connectors( device: &mut RenderDevice, egl_display: Rc>>, - pointer_image: &ImageBuffer, Vec>, logger: &::slog::Logger, ) -> HashMap> { // Get a set of all modesetting resource handles (excluding planes): @@ -272,19 +286,6 @@ impl UdevHandlerImpl { logger.clone(), ); - // create cursor - renderer - .borrow() - .set_cursor_representation(pointer_image, (2, 2)) - .unwrap(); - - // render first frame - { - let mut frame = renderer.draw(); - frame.clear_color(0.8, 0.8, 0.9, 1.0); - frame.finish().unwrap(); - } - backends.insert(crtc, renderer); break; } @@ -296,7 +297,7 @@ impl UdevHandlerImpl { } } -impl UdevHandler for UdevHandlerImpl { +impl UdevHandler for UdevHandlerImpl { fn device_added(&mut self, _device: dev_t, path: PathBuf) { if let Some(mut device) = self .session @@ -313,10 +314,9 @@ impl UdevHandler for UdevHandlerImpl { *self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok(); } - let backends = Rc::new(RefCell::new(UdevHandlerImpl::scan_connectors( + let backends = Rc::new(RefCell::new(UdevHandlerImpl::::scan_connectors( &mut device, self.active_egl_context.clone(), - &self.pointer_image, &self.logger, ))); @@ -328,29 +328,72 @@ impl UdevHandler for UdevHandlerImpl { logger: self.logger.clone(), }); - self.backends.insert(device.device_id(), (device, backends)); + let device_session_id = self.notifier.register(device.observer()); + let dev_id = device.device_id(); + let event_source = device_bind(&self.loop_handle, device) + .map_err(|e| -> IoError { e.into() }) + .unwrap(); + + for renderer in backends.borrow_mut().values() { + // create cursor + renderer + .borrow() + .set_cursor_representation(&self.pointer_image, (2, 2)) + .unwrap(); + + // render first frame + { + let mut frame = renderer.draw(); + frame.clear_color(0.8, 0.8, 0.9, 1.0); + frame.finish().unwrap(); + } + } + + self.backends + .insert(dev_id, (device_session_id, event_source, backends)); } } fn device_changed(&mut self, device: dev_t) { //quick and dirty, just re-init all backends - if let Some((ref mut device, ref backends)) = self.backends.get_mut(&device) { - *backends.borrow_mut() = UdevHandlerImpl::scan_connectors( - device, + if let Some((_, ref mut evt_source, ref backends)) = self.backends.get_mut(&device) { + let source = evt_source.clone_inner(); + let mut evented = source.borrow_mut(); + let mut backends = backends.borrow_mut(); + *backends = UdevHandlerImpl::::scan_connectors( + &mut (*evented).0, self.active_egl_context.clone(), - &self.pointer_image, &self.logger, ); + + for renderer in backends.values() { + // create cursor + renderer + .borrow() + .set_cursor_representation(&self.pointer_image, (2, 2)) + .unwrap(); + + // render first frame + { + let mut frame = renderer.draw(); + frame.clear_color(0.8, 0.8, 0.9, 1.0); + frame.finish().unwrap(); + } + } } } fn device_removed(&mut self, device: dev_t) { // drop the backends on this side - if let Some((dev, _)) = self.backends.remove(&device) { + if let Some((id, evt_source, _)) = self.backends.remove(&device) { // don't use hardware acceleration anymore, if this was the primary gpu - if dev.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { + let source = evt_source.clone_inner(); + let evented = source.borrow(); + if (*evented).0.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { *self.active_egl_context.borrow_mut() = None; } + + self.notifier.unregister(id); } } } diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs index 5d00f0a..b188985 100644 --- a/src/backend/drm/legacy/session.rs +++ b/src/backend/drm/legacy/session.rs @@ -1,4 +1,4 @@ -use drm::control::{connector, crtc, Device as ControlDevice}; +use drm::control::{connector, crtc}; use drm::Device as BasicDevice; use nix::libc::dev_t; use nix::sys::stat; @@ -23,7 +23,7 @@ pub struct LegacyDrmDeviceObserver { logger: ::slog::Logger, } -impl AsSessionObserver> for LegacyDrmDevice { +impl AsSessionObserver> for LegacyDrmDevice { fn observer(&mut self) -> LegacyDrmDeviceObserver { LegacyDrmDeviceObserver { dev: Rc::downgrade(&self.dev), @@ -37,7 +37,7 @@ impl AsSessionObserver> f } } -impl SessionObserver for LegacyDrmDeviceObserver { +impl SessionObserver for LegacyDrmDeviceObserver { fn pause(&mut self, devnum: Option<(u32, u32)>) { if let Some((major, minor)) = devnum { if major as u64 != stat::major(self.dev_id) || minor as u64 != stat::minor(self.dev_id) { diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index d5612c8..e1dd62f 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -31,7 +31,7 @@ use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier}; use super::{ direct::{self, direct_session_bind, BoundDirectSession, DirectSession, DirectSessionNotifier}, - AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver, + AsErrno, Session, SessionNotifier, SessionObserver, }; use nix::fcntl::OFlag; use std::{cell::RefCell, io::Error as IoError, os::unix::io::RawFd, path::Path, rc::Rc}; @@ -202,10 +202,7 @@ impl Session for AutoSession { impl SessionNotifier for AutoSessionNotifier { type Id = AutoId; - fn register>( - &mut self, - signal: &mut A, - ) -> Self::Id { + fn register(&mut self, signal: S) -> Self::Id { match *self { #[cfg(feature = "backend_session_logind")] AutoSessionNotifier::Logind(ref mut logind) => { @@ -231,21 +228,6 @@ impl SessionNotifier for AutoSessionNotifier { _ => unreachable!(), } } - - fn is_active(&self) -> bool { - match *self { - #[cfg(feature = "backend_session_logind")] - AutoSessionNotifier::Logind(ref logind) => logind.is_active(), - AutoSessionNotifier::Direct(ref direct) => direct.is_active(), - } - } - fn seat(&self) -> &str { - match *self { - #[cfg(feature = "backend_session_logind")] - AutoSessionNotifier::Logind(ref logind) => logind.seat(), - AutoSessionNotifier::Direct(ref direct) => direct.seat(), - } - } } impl BoundAutoSession { diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 147abd0..e144422 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -404,27 +404,13 @@ pub struct Id(usize); impl SessionNotifier for LogindSessionNotifier { type Id = Id; - fn register>( - &mut self, - signal: &mut A, - ) -> Self::Id { - self.internal - .signals - .borrow_mut() - .push(Some(Box::new(signal.observer()))); + fn register(&mut self, signal: S) -> Self::Id { + self.internal.signals.borrow_mut().push(Some(Box::new(signal))); Id(self.internal.signals.borrow().len() - 1) } fn unregister(&mut self, signal: Id) { self.internal.signals.borrow_mut()[signal.0] = None; } - - fn is_active(&self) -> bool { - self.internal.active.load(Ordering::SeqCst) - } - - fn seat(&self) -> &str { - &self.internal.seat - } } /// Bound logind session that is driven by the `wayland_server::EventLoop`. diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index d7bc3a9..d879731 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -45,7 +45,7 @@ //! for notifications are the `Libinput` context, the `UdevBackend` or a `DrmDevice` (handled //! automatically by the `UdevBackend`, if not done manually). -use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; +use super::{AsErrno, Session, SessionNotifier, SessionObserver}; use nix::{ fcntl::{self, open, OFlag}, libc::c_int, @@ -350,28 +350,18 @@ pub struct Id(usize); impl SessionNotifier for DirectSessionNotifier { type Id = Id; - fn register>( - &mut self, - signal: &mut A, - ) -> Self::Id { - self.signals.push(Some(Box::new(signal.observer()))); + fn register(&mut self, signal: S) -> Self::Id { + self.signals.push(Some(Box::new(signal))); Id(self.signals.len() - 1) } fn unregister(&mut self, signal: Id) { self.signals[signal.0] = None; } - - fn is_active(&self) -> bool { - self.active.load(Ordering::SeqCst) - } - fn seat(&self) -> &str { - "seat0" - } } impl DirectSessionNotifier { fn signal_received(&mut self) { - if self.is_active() { + if self.active.load(Ordering::SeqCst) { info!(self.logger, "Session shall become inactive."); for signal in &mut self.signals { if let Some(ref mut signal) = *signal { diff --git a/src/backend/session/mod.rs b/src/backend/session/mod.rs index 2eeeee8..8967233 100644 --- a/src/backend/session/mod.rs +++ b/src/backend/session/mod.rs @@ -54,15 +54,9 @@ pub trait SessionNotifier { /// Registers a given `SessionObserver`. /// /// Returns an id of the inserted observer, can be used to remove it again. - fn register>(&mut self, signal: &mut A) - -> Self::Id; + fn register(&mut self, signal: S) -> Self::Id; /// Removes an observer by its given id from `SessionNotifier::register`. fn unregister(&mut self, signal: Self::Id); - - /// Check if this session is currently active - fn is_active(&self) -> bool; - /// Which seat this session is on - fn seat(&self) -> &str; } /// Trait describing the ability to return a `SessionObserver` related to Self. @@ -186,3 +180,5 @@ pub mod auto; mod dbus; pub mod direct; pub use self::dbus::*; +mod multi; +pub use self::multi::*; diff --git a/src/backend/session/multi.rs b/src/backend/session/multi.rs new file mode 100644 index 0000000..8fa57b3 --- /dev/null +++ b/src/backend/session/multi.rs @@ -0,0 +1,64 @@ +use std::{ + collections::HashMap, + os::unix::io::RawFd, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, + }, +}; + +use super::{SessionNotifier, SessionObserver}; + +static ID_COUNTER: AtomicUsize = AtomicUsize::new(0); + +/// Ids of registered `SessionObserver`s of the `DirectSessionNotifier` +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub struct Id(usize); + +struct MultiObserver { + observer: Arc>>>, +} + +impl SessionObserver for MultiObserver { + fn pause(&mut self, device: Option<(u32, u32)>) { + let mut lock = self.observer.lock().unwrap(); + for mut observer in lock.values_mut() { + observer.pause(device) + } + } + fn activate(&mut self, device: Option<(u32, u32, Option)>) { + let mut lock = self.observer.lock().unwrap(); + for mut observer in lock.values_mut() { + observer.activate(device) + } + } +} + +struct MultiNotifier { + observer: Arc>>>, +} + +impl SessionNotifier for MultiNotifier { + type Id = Id; + + fn register(&mut self, signal: S) -> Self::Id { + let id = Id(ID_COUNTER.fetch_add(1, Ordering::SeqCst)); + self.observer.lock().unwrap().insert(id, Box::new(signal)); + id + } + + fn unregister(&mut self, signal: Self::Id) { + self.observer.lock().unwrap().remove(&signal); + } +} + +pub fn notify_multiplexer() -> (impl SessionObserver, impl SessionNotifier) { + let observer = Arc::new(Mutex::new(HashMap::new())); + + ( + MultiObserver { + observer: observer.clone(), + }, + MultiNotifier { observer }, + ) +} From 8abcc145d7d7d61a7474c396d99779aa5a276f72 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Fri, 23 Nov 2018 15:11:27 +0100 Subject: [PATCH 33/56] egl: EGLContext borrow native to circumvent RefCell runtime error --- build.rs | 2 +- src/backend/drm/egl/mod.rs | 10 ++++---- src/backend/drm/egl/session.rs | 2 +- src/backend/drm/egl/surface.rs | 9 ++++--- src/backend/drm/gbm/surface.rs | 7 +++--- src/backend/egl/context.rs | 44 +++++++++++++++++++--------------- src/backend/egl/surface.rs | 3 +-- src/backend/graphics/format.rs | 2 +- src/backend/graphics/gl.rs | 2 +- src/backend/winit.rs | 20 +++++++++------- 10 files changed, 53 insertions(+), 48 deletions(-) diff --git a/build.rs b/build.rs index e843e05..28ac1cf 100644 --- a/build.rs +++ b/build.rs @@ -51,4 +51,4 @@ fn main() { } #[cfg(not(any(feature = "backend_egl", feature = "renderer_gl")))] -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 802cf30..6f4509b 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -1,6 +1,5 @@ use drm::control::{connector, crtc, Mode, ResourceHandles, ResourceInfo}; use nix::libc::dev_t; -use std::cell::RefCell; use std::iter::FromIterator; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; @@ -28,7 +27,7 @@ pub struct EglDevice< > where ::Surface: NativeSurface, { - dev: Rc>>, + dev: Rc>, logger: ::slog::Logger, } @@ -82,9 +81,9 @@ where debug!(log, "Creating egl context from device"); Ok(EglDevice { // Open the gbm device from the drm device and create a context based on that - dev: Rc::new(RefCell::new( + dev: Rc::new( EGLContext::new(dev, attributes, Default::default(), log.clone()).map_err(Error::from)?, - )), + ), logger: log, }) } @@ -148,7 +147,6 @@ where let surface = self .dev - .borrow_mut() .create_surface((crtc, mode, Vec::from_iter(connectors)).into())?; Ok(EglSurface { @@ -182,6 +180,6 @@ where ::Surface: NativeSurface, { fn bind_wl_display(&self, display: &Display) -> EGLResult { - self.dev.borrow().bind_wl_display(display) + self.dev.bind_wl_display(display) } } diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index 338865d..fc18bca 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -20,7 +20,7 @@ where { fn observer(&mut self) -> EglDeviceObserver { EglDeviceObserver { - observer: (**self.dev.borrow_mut()).observer(), + observer: self.dev.borrow_mut().observer(), } } } diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 682338c..5573abb 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -1,6 +1,5 @@ use drm::control::{connector, crtc, Mode}; use nix::libc::c_void; -use std::cell::RefCell; use std::rc::Rc; use super::error::*; @@ -19,7 +18,7 @@ pub struct EglSurface< > where ::Surface: NativeSurface, { - pub(super) dev: Rc>>, + pub(super) dev: Rc>, pub(super) surface: EGLSurface, } @@ -105,7 +104,7 @@ where } unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { - self.dev.borrow().get_proc_address(symbol) + self.dev.get_proc_address(symbol) } fn get_framebuffer_dimensions(&self) -> (u32, u32) { @@ -114,7 +113,7 @@ where } fn is_current(&self) -> bool { - self.dev.borrow().is_current() && self.surface.is_current() + self.dev.is_current() && self.surface.is_current() } unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> { @@ -122,6 +121,6 @@ where } fn get_pixel_format(&self) -> PixelFormat { - self.dev.borrow().get_pixel_format() + self.dev.get_pixel_format() } } diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index 2eb29b0..70167e7 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -73,16 +73,17 @@ impl GbmSurfaceInternal { }; self.next_buffer.set(Some(next_bo)); - trace!(self.logger, "Queueing Page flip"); if self.recreated.get() { + debug!(self.logger, "Commiting new state"); self.crtc .commit(fb.handle()) .map_err(|_| SwapBuffersError::ContextLost)?; self.recreated.set(false); - } else { - self.crtc.page_flip(fb.handle())?; } + trace!(self.logger, "Queueing Page flip"); + self.crtc.page_flip(fb.handle())?; + self.current_frame_buffer.set(Some(fb)); Ok(()) diff --git a/src/backend/egl/context.rs b/src/backend/egl/context.rs index 28f8c70..f0767db 100644 --- a/src/backend/egl/context.rs +++ b/src/backend/egl/context.rs @@ -5,17 +5,16 @@ use backend::graphics::PixelFormat; use nix::libc::{c_int, c_void}; use slog; use std::{ + cell::{Ref, RefCell, RefMut}, ffi::{CStr, CString}, marker::PhantomData, - mem, - ops::{Deref, DerefMut}, - ptr, + mem, ptr, rc::Rc, }; /// EGL context for rendering pub struct EGLContext> { - native: N, + native: RefCell, pub(crate) context: Rc, pub(crate) display: Rc, pub(crate) config_id: ffi::egl::types::EGLConfig, @@ -26,19 +25,6 @@ pub struct EGLContext> { _backend: PhantomData, } -impl> Deref for EGLContext { - type Target = N; - fn deref(&self) -> &N { - &self.native - } -} - -impl> DerefMut for EGLContext { - fn deref_mut(&mut self) -> &mut N { - &mut self.native - } -} - impl> EGLContext { /// Create a new `EGLContext` from a given `NativeDisplay` pub fn new( @@ -56,7 +42,7 @@ impl> EGLContext { unsafe { EGLContext::::new_internal(ptr, attributes, reqs, log.clone()) }?; Ok(EGLContext { - native, + native: RefCell::new(native), context, display, config_id, @@ -429,10 +415,11 @@ impl> EGLContext { } /// Creates a surface for rendering - pub fn create_surface(&mut self, args: N::Arguments) -> Result> { + pub fn create_surface(&self, args: N::Arguments) -> Result> { trace!(self.logger, "Creating EGL window surface."); let surface = self .native + .borrow_mut() .create_surface(args) .chain_err(|| ErrorKind::SurfaceCreationFailed)?; EGLSurface::new(self, surface).map(|x| { @@ -459,6 +446,25 @@ impl> EGLContext { pub fn get_pixel_format(&self) -> PixelFormat { self.pixel_format } + + /// Borrow the underlying native display. + /// + /// This follows the same semantics as `std::cell:RefCell`. + /// Multiple read-only borrows are possible. Borrowing the + /// backend while there is a mutable reference will panic. + pub fn borrow(&self) -> Ref { + self.native.borrow() + } + + /// Borrow the underlying native display mutably. + /// + /// This follows the same semantics as `std::cell:RefCell`. + /// Holding any other borrow while trying to borrow the backend + /// mutably will panic. Note that EGL will borrow the display + /// mutably during surface creation. + pub fn borrow_mut(&self) -> RefMut { + self.native.borrow_mut() + } } unsafe impl + Send> Send for EGLContext {} diff --git a/src/backend/egl/surface.rs b/src/backend/egl/surface.rs index 3d6b15b..df3ac31 100644 --- a/src/backend/egl/surface.rs +++ b/src/backend/egl/surface.rs @@ -74,12 +74,11 @@ impl EGLSurface { err => return Err(SwapBuffersError::Unknown(err)), }; } else { - return Ok(()); + self.native.swap_buffers()?; } } else { return Err(SwapBuffersError::ContextLost); } - self.native.swap_buffers()?; }; if self.native.needs_recreation() || surface.is_null() { diff --git a/src/backend/graphics/format.rs b/src/backend/graphics/format.rs index 7b3176d..96bef69 100644 --- a/src/backend/graphics/format.rs +++ b/src/backend/graphics/format.rs @@ -19,4 +19,4 @@ pub struct PixelFormat { pub multisampling: Option, /// is srgb enabled pub srgb: bool, -} \ No newline at end of file +} diff --git a/src/backend/graphics/gl.rs b/src/backend/graphics/gl.rs index a39ce14..c811ff5 100644 --- a/src/backend/graphics/gl.rs +++ b/src/backend/graphics/gl.rs @@ -1,6 +1,6 @@ use nix::libc::c_void; -use super::{SwapBuffersError, PixelFormat}; +use super::{PixelFormat, SwapBuffersError}; #[cfg_attr(feature = "cargo-clippy", allow(clippy))] #[allow(missing_docs)] diff --git a/src/backend/winit.rs b/src/backend/winit.rs index af2dd3f..0b94085 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -5,10 +5,7 @@ use backend::{ context::GlAttributes, error as egl_error, error::Result as EGLResult, native, EGLContext, EGLDisplay, EGLGraphicsBackend, EGLSurface, }, - graphics::{ - gl::GLGraphicsBackend, - CursorBackend, SwapBuffersError, PixelFormat, - }, + graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError}, input::{ Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, @@ -17,7 +14,12 @@ use backend::{ }, }; use nix::libc::c_void; -use std::{cell::RefCell, cmp, error, fmt, rc::Rc, time::Instant}; +use std::{ + cell::{Ref, RefCell}, + cmp, error, fmt, + rc::Rc, + time::Instant, +}; use wayland_client::egl as wegl; use wayland_server::Display; use winit::{ @@ -56,10 +58,10 @@ enum Window { } impl Window { - fn window(&self) -> &WinitWindow { + fn window(&self) -> Ref { match *self { - Window::Wayland { ref context, .. } => &**context, - Window::X11 { ref context, .. } => &**context, + Window::Wayland { ref context, .. } => context.borrow(), + Window::X11 { ref context, .. } => context.borrow(), } } } @@ -218,7 +220,7 @@ pub trait WinitEventsHandler { impl WinitGraphicsBackend { /// Get a reference to the internally used `winit::Window` - pub fn winit_window(&self) -> &WinitWindow { + pub fn winit_window(&self) -> Ref { self.window.window() } } From a745eace153405d3a14655c9405b963ac94c9455 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sat, 24 Nov 2018 14:15:14 +0100 Subject: [PATCH 34/56] anvil: fix tty swap --- anvil/src/input_handler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 31b0563..f417235 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -11,7 +11,7 @@ use std::{ use slog::Logger; #[cfg(feature = "udev")] -use smithay::backend::session::auto::AutoSession; +use smithay::backend::session::{Session, auto::AutoSession}; use smithay::{ backend::input::{ self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent, @@ -131,7 +131,7 @@ impl InputHandler for AnvilInputHandler { info!(self.log, "Quitting."); self.running.store(false, Ordering::SeqCst); } - #[cfg(feature = "tty_lauch")] + #[cfg(feature = "udev")] KeyAction::VtSwitch(vt) => if let Some(ref mut session) = self.session { info!(log, "Trying to switch to vt {}", vt); if let Err(err) = session.change_vt(vt) { From 51f0050d68bb0025a8efd4948aacccea51708cec Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 25 Nov 2018 00:33:44 +0100 Subject: [PATCH 35/56] drm: fix dropping master when killed from another tty --- src/backend/drm/legacy/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 4459c15..6bd1619 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -264,10 +264,10 @@ impl Drop for LegacyDrmDevice { error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); } } - if self.priviledged { - if let Err(err) = self.drop_master() { - error!(self.logger, "Failed to drop drm master state. Error: {}", err); - } + } + if self.priviledged { + if let Err(err) = self.drop_master() { + error!(self.logger, "Failed to drop drm master state. Error: {}", err); } } } From 2c73651327b6ec40ed6600eec6fdc6d7d0029046 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 25 Nov 2018 00:33:58 +0100 Subject: [PATCH 36/56] logind: fix dbus spamming the event queue --- src/backend/session/dbus/logind.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index e144422..9930985 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -30,7 +30,7 @@ //! automatically by the `UdevBackend`, if not done manually). //! ``` -use backend::session::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; +use backend::session::{AsErrno, Session, SessionNotifier, SessionObserver}; use dbus::{ BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message, MessageItem, OwnedFd, Path as DbusPath, Watch, WatchEvent, @@ -441,7 +441,10 @@ pub fn logind_session_bind( .into_iter() .map(|watch| { let mut source = Generic::from_raw_fd(watch.fd()); - source.set_interest(Ready::readable() | Ready::writable()); + source.set_interest( + if watch.readable() { Ready::readable() } else { Ready::empty() } + | if watch.writable() { Ready::writable() } else { Ready::empty() } + ); handle.insert_source(source, { let mut notifier = notifier.clone(); move |evt, _| notifier.event(evt) From f2466c5c5068152dd72e7e044744f350c4b31d66 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 28 Nov 2018 09:09:34 +0100 Subject: [PATCH 37/56] drm: Fix drop order --- Cargo.toml | 2 +- anvil/src/udev.rs | 12 ++-- src/backend/drm/egl/mod.rs | 16 +++++ src/backend/drm/egl/session.rs | 2 + src/backend/drm/gbm/mod.rs | 6 ++ src/backend/drm/legacy/mod.rs | 111 ++++++++++++++++-------------- src/backend/drm/legacy/session.rs | 16 +---- 7 files changed, 95 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c352770..1cf6d0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/Smithay/smithay" members = [ "anvil" ] [dependencies] -wayland-server = "0.21.4" +wayland-server = "0.21.6" wayland-sys = "0.21.3" wayland-commons = "0.21.1" nix = "0.11" diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index e85b9c6..a7f2f7a 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -385,15 +385,19 @@ impl UdevHandler for UdevHandlerImpl fn device_removed(&mut self, device: dev_t) { // drop the backends on this side - if let Some((id, evt_source, _)) = self.backends.remove(&device) { + if let Some((id, evt_source, renderers)) = self.backends.remove(&device) { + // drop surfaces + renderers.borrow_mut().clear(); + debug!(self.logger, "Surfaces dropped"); + // don't use hardware acceleration anymore, if this was the primary gpu - let source = evt_source.clone_inner(); - let evented = source.borrow(); - if (*evented).0.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { + let device = Rc::try_unwrap(evt_source.remove().unwrap()).map_err(|_| "This should not happend").unwrap().into_inner().0; + if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { *self.active_egl_context.borrow_mut() = None; } self.notifier.unregister(id); + debug!(self.logger, "Dropping device"); } } } diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 6f4509b..7cd7803 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -25,6 +25,7 @@ pub struct EglDevice< B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static, > where + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { dev: Rc>, @@ -34,6 +35,7 @@ pub struct EglDevice< impl::Surface> + 'static, D: Device + NativeDisplay + 'static> AsRawFd for EglDevice where + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn as_raw_fd(&self) -> RawFd { @@ -44,6 +46,7 @@ where impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EglDevice where + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { /// Create a new `EglGbmDrmDevice` from an open drm node @@ -93,6 +96,7 @@ struct InternalDeviceHandler< B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static, > where + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { handler: Box> + 'static>, @@ -177,9 +181,21 @@ where impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EGLGraphicsBackend for EglDevice where + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn bind_wl_display(&self, display: &Display) -> EGLResult { self.dev.bind_wl_display(display) } } + +impl::Surface> + 'static, D: Device + NativeDisplay + 'static> + Drop for EglDevice +where + >::Arguments: From<(crtc::Handle, Mode, Vec)>, + ::Surface: NativeSurface, +{ + fn drop(&mut self) { + self.clear_handler(); + } +} \ No newline at end of file diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index fc18bca..4b7fc44 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -1,4 +1,5 @@ use std::os::unix::io::RawFd; +use drm::control::{crtc, connector, Mode}; use super::EglDevice; use backend::drm::Device; @@ -16,6 +17,7 @@ impl< D: Device + NativeDisplay + AsSessionObserver + 'static, > AsSessionObserver> for EglDevice where + >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn observer(&mut self) -> EglDeviceObserver { diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index cbf4c63..5bdba8c 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -192,3 +192,9 @@ impl AsRawFd for GbmDevice { self.dev.borrow().as_raw_fd() } } + +impl Drop for GbmDevice { + fn drop(&mut self) { + self.clear_handler(); + } +} \ No newline at end of file diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 6bd1619..2b46c7b 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -26,22 +26,51 @@ pub mod session; pub struct LegacyDrmDevice { dev: Rc>, dev_id: dev_t, - priviledged: bool, active: Arc, - old_state: HashMap)>, backends: Rc>>>>, handler: Option>>>>, logger: ::slog::Logger, } -pub(in crate::backend::drm) struct Dev(A); +pub(in crate::backend::drm) struct Dev { + fd: A, + priviledged: bool, + active: Arc, + old_state: HashMap)>, + logger: ::slog::Logger, +} impl AsRawFd for Dev { fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() + self.fd.as_raw_fd() } } impl BasicDevice for Dev {} impl ControlDevice for Dev {} +impl Drop for Dev { + fn drop(&mut self) { + info!(self.logger, "Dropping device: {:?}", self.dev_path()); + if self.active.load(Ordering::SeqCst) { + let old_state = self.old_state.clone(); + for (handle, (info, connectors)) in old_state { + if let Err(err) = crtc::set( + &*self, + handle, + info.fb(), + &connectors, + info.position(), + info.mode(), + ) { + error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); + } + } + } + if self.priviledged { + if let Err(err) = self.drop_master() { + error!(self.logger, "Failed to drop drm master state. Error: {}", err); + } + } + } +} impl LegacyDrmDevice { /// Create a new `LegacyDrmDevice` from an open drm node @@ -53,47 +82,43 @@ impl LegacyDrmDevice { L: Into>, { let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm")); + info!(log, "DrmDevice initializing"); let dev_id = fstat(dev.as_raw_fd()) .chain_err(|| ErrorKind::UnableToGetDeviceId)? .st_rdev; - let mut drm = LegacyDrmDevice { - // Open the drm device and create a context based on that - dev: Rc::new(Dev(dev)), - dev_id, + let active = Arc::new(AtomicBool::new(true)); + let mut dev = Dev { + fd: dev, priviledged: true, - active: Arc::new(AtomicBool::new(true)), old_state: HashMap::new(), - backends: Rc::new(RefCell::new(HashMap::new())), - handler: None, + active: active.clone(), logger: log.clone(), }; - info!(log, "DrmDevice initializing"); - // we want to modeset, so we better be the master, if we run via a tty session - if drm.set_master().is_err() { + if dev.set_master().is_err() { warn!(log, "Unable to become drm master, assuming unpriviledged mode"); - drm.priviledged = false; + dev.priviledged = false; }; - let res_handles = ControlDevice::resource_handles(&drm).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path())) + let res_handles = ControlDevice::resource_handles(&dev).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", dev.dev_path())) })?; for &con in res_handles.connectors() { - let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path())) + let con_info = connector::Info::load_from_device(&dev, con).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", dev.dev_path())) })?; if let Some(enc) = con_info.current_encoder() { - let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path())) + let enc_info = encoder::Info::load_from_device(&dev, enc).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", dev.dev_path())) })?; if let Some(crtc) = enc_info.current_crtc() { - let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", drm.dev_path())) + let info = crtc::Info::load_from_device(&dev, crtc).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", dev.dev_path())) })?; - drm.old_state + dev.old_state .entry(crtc) .or_insert((info, Vec::new())) .1 @@ -101,14 +126,22 @@ impl LegacyDrmDevice { } } } - - Ok(drm) + + Ok(LegacyDrmDevice { + // Open the drm device and create a context based on that + dev: Rc::new(dev), + dev_id, + active, + backends: Rc::new(RefCell::new(HashMap::new())), + handler: None, + logger: log.clone(), + }) } } impl AsRawFd for LegacyDrmDevice { fn as_raw_fd(&self) -> RawFd { - self.dev.0.as_raw_fd() + self.dev.as_raw_fd() } } @@ -247,28 +280,6 @@ impl RawDevice for LegacyDrmDevice { impl Drop for LegacyDrmDevice { fn drop(&mut self) { - self.backends.borrow_mut().clear(); - if Rc::strong_count(&self.dev) > 1 { - panic!("Pending DrmBackends. You need to free all backends before the DrmDevice gets destroyed"); - } - if self.active.load(Ordering::SeqCst) { - for (handle, (info, connectors)) in self.old_state.drain() { - if let Err(err) = crtc::set( - &*self.dev, - handle, - info.fb(), - &connectors, - info.position(), - info.mode(), - ) { - error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); - } - } - } - if self.priviledged { - if let Err(err) = self.drop_master() { - error!(self.logger, "Failed to drop drm master state. Error: {}", err); - } - } + self.clear_handler(); } } diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs index b188985..3f75a13 100644 --- a/src/backend/drm/legacy/session.rs +++ b/src/backend/drm/legacy/session.rs @@ -18,7 +18,6 @@ pub struct LegacyDrmDeviceObserver { dev_id: dev_t, priviledged: bool, active: Arc, - old_state: HashMap)>, backends: Weak>>>>, logger: ::slog::Logger, } @@ -28,9 +27,8 @@ impl AsSessionObserver> for Leg LegacyDrmDeviceObserver { dev: Rc::downgrade(&self.dev), dev_id: self.dev_id, - old_state: self.old_state.clone(), active: self.active.clone(), - priviledged: self.priviledged, + priviledged: self.dev.priviledged, backends: Rc::downgrade(&self.backends), logger: self.logger.clone(), } @@ -50,18 +48,6 @@ impl SessionObserver for LegacyDrmDeviceObserver { let _ = crtc::clear_cursor(&*device, surface.crtc); } } - for (handle, &(ref info, ref connectors)) in &self.old_state { - if let Err(err) = crtc::set( - &*device, - *handle, - info.fb(), - connectors, - info.position(), - info.mode(), - ) { - error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); - } - } } self.active.store(false, Ordering::SeqCst); if self.priviledged { From f8a5e8bfde2635b53f713fbaee115887cb66acad Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 28 Nov 2018 09:29:13 +0100 Subject: [PATCH 38/56] anvil: allow for non-egl builds --- Cargo.toml | 7 +-- anvil/Cargo.toml | 5 +- anvil/src/glium_drawer.rs | 100 +++++++++++++++++++++++++++++-------- anvil/src/input_handler.rs | 2 +- anvil/src/udev.rs | 90 ++++++++++++++++++++++++++++++--- src/backend/drm/egl/mod.rs | 5 +- src/backend/egl/mod.rs | 7 +++ src/lib.rs | 1 + 8 files changed, 182 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1cf6d0d..153f4e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,8 @@ members = [ "anvil" ] [dependencies] wayland-server = "0.21.6" -wayland-sys = "0.21.3" wayland-commons = "0.21.1" +wayland-sys = { version = "0.21.6", optional = true } nix = "0.11" xkbcommon = "0.2.1" tempfile = "2.1.5" @@ -28,7 +28,7 @@ input = { version = "0.4.0", optional = true } udev = { version = "0.2.0", optional = true } dbus = { version = "0.6.1", optional = true } systemd = { version = "^0.2.0", optional = true } -wayland-protocols = { version = "0.21.3", features = ["unstable_protocols", "native_server"] } +wayland-protocols = { version = "0.21.3", features = ["unstable_protocols", "server"] } image = "0.17.0" error-chain = "0.11.0" lazy_static = "1.0.0" @@ -38,7 +38,7 @@ gl_generator = { version = "0.9", optional = true } [features] default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session", "renderer_glium", "xwayland"] -backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl", "renderer_gl"] +backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl", "renderer_gl", "native_lib"] backend_drm = ["drm"] backend_drm_legacy = ["backend_drm"] backend_drm_gbm = ["backend_drm", "gbm"] @@ -50,4 +50,5 @@ backend_udev = ["udev"] backend_session_logind = ["dbus", "systemd", "backend_session"] renderer_gl = ["gl_generator"] renderer_glium = ["renderer_gl", "glium"] +native_lib = ["wayland-sys", "wayland-server/native_lib", "wayland-protocols/native_server"] xwayland = [] \ No newline at end of file diff --git a/anvil/Cargo.toml b/anvil/Cargo.toml index d7deafe..536a207 100644 --- a/anvil/Cargo.toml +++ b/anvil/Cargo.toml @@ -23,7 +23,8 @@ features = [ "renderer_glium" ] gl_generator = "0.9" [features] -default = [ "winit", "udev" ] +default = [ "winit", "egl", "udev" ] +egl = [ "smithay/native_lib" ] winit = [ "smithay/backend_winit" ] -udev = [ "smithay/backend_libinput", "smithay/backend_drm", "smithay/backend_udev", "smithay/backend_session" ] +udev = [ "smithay/backend_libinput", "smithay/backend_drm_legacy", "smithay/backend_drm_gbm", "smithay/backend_drm_egl", "smithay/backend_udev", "smithay/backend_session" ] logind = [ "smithay/backend_session_logind" ] diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index d384ac0..b10e7e1 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -11,9 +11,11 @@ use glium::{ }; use slog::Logger; +#[cfg(feature = "egl")] +use smithay::backend::egl::EGLDisplay; use smithay::{ backend::{ - egl::{BufferAccessError, EGLDisplay, EGLImages, Format}, + egl::{BufferAccessError, EGLImages, Format}, graphics::{gl::GLGraphicsBackend, glium::GliumGraphicsBackend}, }, wayland::{ @@ -39,6 +41,7 @@ pub struct GliumDrawer { vertex_buffer: glium::VertexBuffer, index_buffer: glium::IndexBuffer, programs: [glium::Program; shaders::FRAGMENT_COUNT], + #[cfg(feature = "egl")] egl_display: Rc>>, log: Logger, } @@ -50,6 +53,7 @@ impl GliumDrawer { } impl> + GLGraphicsBackend + 'static> GliumDrawer { + #[cfg(feature = "egl")] pub fn init(backend: T, egl_display: Rc>>, log: Logger) -> GliumDrawer { let display = backend.into(); @@ -91,9 +95,52 @@ impl> + GLGraphicsBackend + 'static> GliumDrawer log, } } + + #[cfg(not(feature = "egl"))] + pub fn init(backend: T, log: Logger) -> GliumDrawer { + let display = backend.into(); + + // building the vertex buffer, which contains all the vertices that we will draw + let vertex_buffer = glium::VertexBuffer::new( + &display, + &[ + Vertex { + position: [0.0, 0.0], + tex_coords: [0.0, 0.0], + }, + Vertex { + position: [0.0, 1.0], + tex_coords: [0.0, 1.0], + }, + Vertex { + position: [1.0, 1.0], + tex_coords: [1.0, 1.0], + }, + Vertex { + position: [1.0, 0.0], + tex_coords: [1.0, 0.0], + }, + ], + ).unwrap(); + + // building the index buffer + let index_buffer = + glium::IndexBuffer::new(&display, PrimitiveType::TriangleStrip, &[1 as u16, 2, 0, 3]).unwrap(); + + let programs = opengl_programs!(&display); + + GliumDrawer { + display, + vertex_buffer, + index_buffer, + programs, + log, + } + } } impl GliumDrawer { + #[cfg(feature = "egl")] pub fn texture_from_buffer(&self, buffer: Resource) -> Result { // try to retrieve the egl contents of this buffer let images = if let Some(display) = &self.egl_display.borrow().as_ref() { @@ -134,26 +181,7 @@ impl GliumDrawer { } Err(BufferAccessError::NotManaged(buffer)) => { // this is not an EGL buffer, try SHM - match shm_buffer_contents(&buffer, |slice, data| { - ::shm_load::load_shm_buffer(data, slice) - .map(|(image, kind)| (Texture2d::new(&self.display, image).unwrap(), kind, data)) - }) { - Ok(Ok((texture, kind, data))) => Ok(TextureMetadata { - texture, - fragment: kind, - y_inverted: false, - dimensions: (data.width as u32, data.height as u32), - images: None, - }), - Ok(Err(format)) => { - warn!(self.log, "Unsupported SHM buffer format"; "format" => format!("{:?}", format)); - Err(()) - } - Err(err) => { - warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err)); - Err(()) - } - } + self.texture_from_shm_buffer(buffer) } Err(err) => { error!(self.log, "EGL error"; "err" => format!("{:?}", err)); @@ -162,6 +190,35 @@ impl GliumDrawer { } } + #[cfg(not(feature = "egl"))] + pub fn texture_from_buffer(&self, buffer: Resource) -> Result { + self.texture_from_shm_buffer(buffer) + } + + fn texture_from_shm_buffer(&self, buffer: Resource) -> Result { + match shm_buffer_contents(&buffer, |slice, data| { + ::shm_load::load_shm_buffer(data, slice) + .map(|(image, kind)| (Texture2d::new(&self.display, image).unwrap(), kind, data)) + }) { + Ok(Ok((texture, kind, data))) => Ok(TextureMetadata { + texture, + fragment: kind, + y_inverted: false, + dimensions: (data.width as u32, data.height as u32), + #[cfg(feature = "egl")] + images: None, + }), + Ok(Err(format)) => { + warn!(self.log, "Unsupported SHM buffer format"; "format" => format!("{:?}", format)); + Err(()) + } + Err(err) => { + warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err)); + Err(()) + } + } + } + pub fn render_texture( &self, target: &mut glium::Frame, @@ -218,6 +275,7 @@ pub struct TextureMetadata { pub fragment: usize, pub y_inverted: bool, pub dimensions: (u32, u32), + #[cfg(feature = "egl")] images: Option, } diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index f417235..689f707 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -11,7 +11,7 @@ use std::{ use slog::Logger; #[cfg(feature = "udev")] -use smithay::backend::session::{Session, auto::AutoSession}; +use smithay::backend::session::{auto::AutoSession, Session}; use smithay::{ backend::input::{ self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent, diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index a7f2f7a..3c995e1 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -14,6 +14,8 @@ use std::{ use glium::Surface as GliumSurface; use slog::Logger; +#[cfg(feature = "egl")] +use smithay::backend::egl::{EGLDisplay, EGLGraphicsBackend}; use smithay::{ backend::{ drm::{ @@ -23,7 +25,6 @@ use smithay::{ legacy::LegacyDrmDevice, DevPath, Device, DeviceHandler, Surface, }, - egl::{EGLDisplay, EGLGraphicsBackend}, graphics::CursorBackend, input::InputBackend, libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}, @@ -79,6 +80,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger info!(log, "Listening on wayland socket"; "name" => name.clone()); ::std::env::set_var("WAYLAND_DISPLAY", name); + #[cfg(feature = "egl")] let active_egl_context = Rc::new(RefCell::new(None)); let display = Rc::new(RefCell::new(display)); @@ -114,6 +116,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger &context, UdevHandlerImpl { compositor_token, + #[cfg(feature = "egl")] active_egl_context, session: session.clone(), backends: HashMap::new(), @@ -226,6 +229,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger struct UdevHandlerImpl { compositor_token: CompositorToken, + #[cfg(feature = "egl")] active_egl_context: Rc>>, session: AutoSession, backends: HashMap< @@ -247,6 +251,7 @@ struct UdevHandlerImpl { } impl UdevHandlerImpl { + #[cfg(feature = "egl")] pub fn scan_connectors( device: &mut RenderDevice, egl_display: Rc>>, @@ -295,6 +300,54 @@ impl UdevHandlerImpl { backends } + + #[cfg(not(feature = "egl"))] + pub fn scan_connectors( + device: &mut RenderDevice, + 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.resource_info::(*conn).unwrap()) + .filter(|conn| conn.connection_state() == ConnectorState::Connected) + .inspect(|conn| info!(logger, "Connected: {:?}", conn.connector_type())) + .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() + .flat_map(|encoder_handle| device.resource_info::(*encoder_handle)) + .collect::>(); + for encoder_info in encoder_infos { + for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { + if !backends.contains_key(&crtc) { + let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) + // create a backend + let renderer = GliumDrawer::init( + device + .create_surface(crtc, mode, vec![connector_info.handle()].into_iter()) + .unwrap(), + logger.clone(), + ); + + backends.insert(crtc, renderer); + break; + } + } + } + } + + backends + } } impl UdevHandler for UdevHandlerImpl { @@ -310,16 +363,27 @@ impl UdevHandler for UdevHandlerImpl .and_then(|gbm| EglDevice::new(gbm, self.logger.clone()).ok()) { // init hardware acceleration on the primary gpu. - if path.canonicalize().ok() == self.primary_gpu { - *self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok(); + #[cfg(feature = "egl")] + { + if path.canonicalize().ok() == self.primary_gpu { + *self.active_egl_context.borrow_mut() = + device.bind_wl_display(&*self.display.borrow()).ok(); + } } + #[cfg(feature = "egl")] let backends = Rc::new(RefCell::new(UdevHandlerImpl::::scan_connectors( &mut device, self.active_egl_context.clone(), &self.logger, ))); + #[cfg(not(feature = "egl"))] + let backends = Rc::new(RefCell::new(UdevHandlerImpl::::scan_connectors( + &mut device, + &self.logger, + ))); + device.set_handler(DrmHandlerImpl { compositor_token: self.compositor_token, backends: backends.clone(), @@ -360,11 +424,15 @@ impl UdevHandler for UdevHandlerImpl let source = evt_source.clone_inner(); let mut evented = source.borrow_mut(); let mut backends = backends.borrow_mut(); - *backends = UdevHandlerImpl::::scan_connectors( + #[cfg(feature = "egl")] + let new_backends = UdevHandlerImpl::::scan_connectors( &mut (*evented).0, self.active_egl_context.clone(), &self.logger, ); + #[cfg(not(feature = "egl"))] + let new_backends = UdevHandlerImpl::::scan_connectors(&mut (*evented).0, &self.logger); + *backends = new_backends; for renderer in backends.values() { // create cursor @@ -391,9 +459,17 @@ impl UdevHandler for UdevHandlerImpl debug!(self.logger, "Surfaces dropped"); // don't use hardware acceleration anymore, if this was the primary gpu - let device = Rc::try_unwrap(evt_source.remove().unwrap()).map_err(|_| "This should not happend").unwrap().into_inner().0; - if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { - *self.active_egl_context.borrow_mut() = None; + let device = Rc::try_unwrap(evt_source.remove().unwrap()) + .map_err(|_| "This should not happend") + .unwrap() + .into_inner() + .0; + + #[cfg(feature = "egl")] + { + if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { + *self.active_egl_context.borrow_mut() = None; + } } self.notifier.unregister(id); diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 7cd7803..b97cfac 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -9,7 +9,9 @@ use super::{Device, DeviceHandler, Surface}; use backend::egl::context::GlAttributes; use backend::egl::error::Result as EGLResult; use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; -use backend::egl::{EGLContext, EGLDisplay, EGLGraphicsBackend}; +use backend::egl::EGLContext; +#[cfg(feature = "native_lib")] +use backend::egl::{EGLDisplay, EGLGraphicsBackend}; pub mod error; use self::error::*; @@ -178,6 +180,7 @@ where } } +#[cfg(feature = "native_lib")] impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EGLGraphicsBackend for EglDevice where diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index dfafee9..57d4f6d 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -29,6 +29,7 @@ use wayland_server::{ protocol::wl_buffer::{self, WlBuffer}, Display, Resource, }; +#[cfg(feature = "native_lib")] use wayland_sys::server::wl_display; pub mod context; @@ -303,6 +304,7 @@ impl Drop for EGLImages { /// Trait any backend type may implement that allows binding a `wayland_server::Display` /// to create an `EGLDisplay` for EGL-based `WlBuffer`s. +#[cfg(feature = "native_lib")] pub trait EGLGraphicsBackend { /// Binds this EGL context to the given Wayland display. /// @@ -323,6 +325,7 @@ pub trait EGLGraphicsBackend { /// Type to receive `EGLImages` for EGL-based `WlBuffer`s. /// /// Can be created by using `EGLGraphicsBackend::bind_wl_display`. +#[cfg(feature = "native_lib")] pub struct EGLDisplay { egl: Weak, wayland: *mut wl_display, @@ -332,6 +335,7 @@ pub struct EGLDisplay { egl_to_texture_support: bool, } +#[cfg(feature = "native_lib")] impl EGLDisplay { fn new>( context: &EGLContext, @@ -469,6 +473,7 @@ impl EGLDisplay { } } +#[cfg(feature = "native_lib")] impl Drop for EGLDisplay { fn drop(&mut self) { if let Some(display) = self.egl.upgrade() { @@ -481,12 +486,14 @@ impl Drop for EGLDisplay { } } +#[cfg(feature = "native_lib")] impl EGLGraphicsBackend for Rc { fn bind_wl_display(&self, display: &Display) -> Result { (**self).bind_wl_display(display) } } +#[cfg(feature = "native_lib")] impl> EGLGraphicsBackend for EGLContext { fn bind_wl_display(&self, display: &Display) -> Result { if !self.wl_drm_support { diff --git a/src/lib.rs b/src/lib.rs index 422b947..9e11b51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ extern crate tempfile; pub extern crate wayland_commons; pub extern crate wayland_protocols; pub extern crate wayland_server; +#[cfg(feature = "native_lib")] extern crate wayland_sys; extern crate xkbcommon; From 99f9156f64b1003995ff8a45c704a78a02e769f2 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 28 Nov 2018 16:16:32 +0100 Subject: [PATCH 39/56] anvil: clear window map on drop --- anvil/src/udev.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 3c995e1..d8ee6aa 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -217,6 +217,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger } } + window_map.borrow_mut().clear(); + let mut notifier = session_event_source.unbind(); notifier.unregister(libinput_session_id); notifier.unregister(udev_session_id); From b160a91f8ab5c9451dc3495aa936103eb7b8817c Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 2 Dec 2018 20:07:39 +0100 Subject: [PATCH 40/56] drm: remove mode & connector arguments of create_surface --- anvil/src/udev.rs | 9 +---- src/backend/drm/egl/mod.rs | 64 ++++++++++++++--------------- src/backend/drm/egl/session.rs | 5 +-- src/backend/drm/egl/surface.rs | 8 ++-- src/backend/drm/gbm/egl.rs | 26 ++---------- src/backend/drm/gbm/error.rs | 6 +++ src/backend/drm/gbm/mod.rs | 16 ++++---- src/backend/drm/gbm/surface.rs | 14 +++---- src/backend/drm/legacy/mod.rs | 67 +++++++++++-------------------- src/backend/drm/legacy/surface.rs | 44 +++++++++++--------- src/backend/drm/mod.rs | 8 ++-- 11 files changed, 113 insertions(+), 154 deletions(-) diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index d8ee6aa..19cd778 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -38,7 +38,6 @@ use smithay::{ connector::{Info as ConnectorInfo, State as ConnectorState}, crtc, encoder::Info as EncoderInfo, - ResourceInfo, }, image::{ImageBuffer, Rgba}, input::Libinput, @@ -283,11 +282,9 @@ impl UdevHandlerImpl { for encoder_info in encoder_infos { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { if !backends.contains_key(&crtc) { - let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) - // create a backend let renderer = GliumDrawer::init( device - .create_surface(crtc, mode, vec![connector_info.handle()].into_iter()) + .create_surface(crtc) .unwrap(), egl_display.clone(), logger.clone(), @@ -332,11 +329,9 @@ impl UdevHandlerImpl { for encoder_info in encoder_infos { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { if !backends.contains_key(&crtc) { - let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) - // create a backend let renderer = GliumDrawer::init( device - .create_surface(crtc, mode, vec![connector_info.handle()].into_iter()) + .create_surface(crtc) .unwrap(), logger.clone(), ); diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index b97cfac..759b65d 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -1,6 +1,5 @@ -use drm::control::{connector, crtc, Mode, ResourceHandles, ResourceInfo}; +use drm::control::{crtc, ResourceHandles, ResourceInfo}; use nix::libc::dev_t; -use std::iter::FromIterator; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; use wayland_server::Display; @@ -25,19 +24,19 @@ pub mod session; /// Representation of an open gbm device to create rendering backends pub struct EglDevice< B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, + D: Device + NativeDisplay + 'static, > where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { dev: Rc>, logger: ::slog::Logger, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> AsRawFd - for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > AsRawFd for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn as_raw_fd(&self) -> RawFd { @@ -45,10 +44,11 @@ where } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { /// Create a new `EglGbmDrmDevice` from an open drm node @@ -96,18 +96,18 @@ where struct InternalDeviceHandler< B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, + D: Device + NativeDisplay + 'static, > where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { handler: Box> + 'static>, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - DeviceHandler for InternalDeviceHandler +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > DeviceHandler for InternalDeviceHandler where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { type Device = D; @@ -121,10 +121,11 @@ where } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Device - for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > Device for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { type Surface = EglSurface; @@ -143,17 +144,10 @@ where self.dev.borrow_mut().clear_handler() } - fn create_surface( - &mut self, - crtc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, - ) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { info!(self.logger, "Initializing EglSurface"); - let surface = self - .dev - .create_surface((crtc, mode, Vec::from_iter(connectors)).into())?; + let surface = self.dev.create_surface(crtc)?; Ok(EglSurface { dev: self.dev.clone(), @@ -181,10 +175,11 @@ where } #[cfg(feature = "native_lib")] -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - EGLGraphicsBackend for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > EGLGraphicsBackend for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn bind_wl_display(&self, display: &Display) -> EGLResult { @@ -192,13 +187,14 @@ where } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - Drop for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > Drop for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn drop(&mut self) { self.clear_handler(); } -} \ No newline at end of file +} diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index 4b7fc44..7247d2d 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -1,5 +1,5 @@ +use drm::control::{connector, crtc, Mode}; use std::os::unix::io::RawFd; -use drm::control::{crtc, connector, Mode}; use super::EglDevice; use backend::drm::Device; @@ -14,10 +14,9 @@ pub struct EglDeviceObserver { impl< S: SessionObserver + 'static, B: Backend::Surface> + 'static, - D: Device + NativeDisplay + AsSessionObserver + 'static, + D: Device + NativeDisplay + AsSessionObserver + 'static, > AsSessionObserver> for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn observer(&mut self) -> EglDeviceObserver { diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 5573abb..b8be770 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -54,15 +54,15 @@ where .chain_err(|| ErrorKind::UnderlyingBackendError) } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.surface.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.surface.pending_mode() } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.surface .use_mode(mode) .chain_err(|| ErrorKind::UnderlyingBackendError) @@ -108,7 +108,7 @@ where } fn get_framebuffer_dimensions(&self) -> (u32, u32) { - let (w, h) = self.pending_mode().size(); + let (w, h) = self.pending_mode().map(|mode| mode.size()).unwrap_or((1, 1)); (w as u32, h as u32) } diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 45b36bb..696b400 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -45,28 +45,8 @@ impl Backend for Gbm { } } -/// Arguments necessary to construct a `GbmSurface` -pub struct SurfaceArguments { - /// Crtc - pub crtc: crtc::Handle, - /// Mode - pub mode: Mode, - /// Connectors - pub connectors: Vec, -} - -impl From<(crtc::Handle, Mode, Vec)> for SurfaceArguments { - fn from((crtc, mode, connectors): (crtc::Handle, Mode, Vec)) -> Self { - SurfaceArguments { - crtc, - mode, - connectors: Vec::from_iter(connectors), - } - } -} - unsafe impl NativeDisplay> for GbmDevice { - type Arguments = SurfaceArguments; + type Arguments = crtc::Handle; type Error = Error; fn is_backend(&self) -> bool { @@ -77,8 +57,8 @@ unsafe impl NativeDisplay> for Gb Ok(self.dev.borrow().as_raw() as *const _) } - fn create_surface(&mut self, args: SurfaceArguments) -> Result> { - Device::create_surface(self, args.crtc, args.mode, args.connectors) + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { + Device::create_surface(self, crtc) } } diff --git a/src/backend/drm/gbm/error.rs b/src/backend/drm/gbm/error.rs index 484e79c..e654c2d 100644 --- a/src/backend/drm/gbm/error.rs +++ b/src/backend/drm/gbm/error.rs @@ -16,6 +16,12 @@ error_chain! { display("Creation of gbm surface failed"), } + #[doc = "No mode is set, blocking the current operation"] + NoModeSet { + description("No mode is currently set"), + display("No mode is currently set"), + } + #[doc = "Creation of gbm buffer object failed"] BufferCreationFailed { description("Creation of gbm buffer object failed"), diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 5bdba8c..7b4f4bd 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -119,18 +119,16 @@ impl Device for GbmDevice { self.dev.borrow_mut().clear_handler(); } - fn create_surface( - &mut self, - crtc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, - ) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { info!(self.logger, "Initializing GbmSurface"); - let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) + let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc) .chain_err(|| ErrorKind::UnderlyingBackendError)?; - let (w, h) = mode.size(); + let (w, h) = drm_surface + .pending_mode() + .map(|mode| mode.size()) + .unwrap_or((1, 1)); let surface = self .dev .borrow() @@ -197,4 +195,4 @@ impl Drop for GbmDevice { fn drop(&mut self) { self.clear_handler(); } -} \ No newline at end of file +} diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index 70167e7..704ee64 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -90,7 +90,7 @@ impl GbmSurfaceInternal { } pub fn recreate(&self) -> Result<()> { - let (w, h) = self.pending_mode().size(); + let (w, h) = self.pending_mode().chain_err(|| ErrorKind::NoModeSet)?.size(); // Recreate the surface and the related resources to match the new // resolution. @@ -161,15 +161,15 @@ impl Surface for GbmSurfaceInternal { .chain_err(|| ErrorKind::UnderlyingBackendError) } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.crtc.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.crtc.pending_mode() } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.crtc .use_mode(mode) .chain_err(|| ErrorKind::UnderlyingBackendError) @@ -314,15 +314,15 @@ impl Surface for GbmSurface { self.0.remove_connector(connector) } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.0.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.0.pending_mode() } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.0.use_mode(mode) } } diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 2b46c7b..5a0d221 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -46,7 +46,7 @@ impl AsRawFd for Dev { } impl BasicDevice for Dev {} impl ControlDevice for Dev {} -impl Drop for Dev { +impl Drop for Dev { fn drop(&mut self) { info!(self.logger, "Dropping device: {:?}", self.dev_path()); if self.active.load(Ordering::SeqCst) { @@ -126,7 +126,7 @@ impl LegacyDrmDevice { } } } - + Ok(LegacyDrmDevice { // Open the drm device and create a context based on that dev: Rc::new(dev), @@ -163,12 +163,7 @@ impl Device for LegacyDrmDevice { let _ = self.handler.take(); } - fn create_surface( - &mut self, - crtc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, - ) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { if self.backends.borrow().contains_key(&crtc) { bail!(ErrorKind::CrtcAlreadyInUse(crtc)); } @@ -177,52 +172,38 @@ impl Device for LegacyDrmDevice { bail!(ErrorKind::DeviceInactive); } - let connectors = HashSet::from_iter(connectors); - // check if we have an encoder for every connector and the mode mode - for connector in &connectors { - let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| { + let crtc_info = crtc::Info::load_from_device(self, crtc) + .chain_err(|| ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", self.dev_path())))?; + + let mode = crtc_info.mode(); + + let mut connectors = HashSet::new(); + let res_handles = ControlDevice::resource_handles(self).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) + })?; + for &con in res_handles.connectors() { + let con_info = connector::Info::load_from_device(self, con).chain_err(|| { ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) })?; - - // check the mode - if !con_info.modes().contains(&mode) { - bail!(ErrorKind::ModeNotSuitable(mode)); - } - - // check for every connector which encoders it does support - let encoders = con_info - .encoders() - .iter() - .map(|encoder| { - encoder::Info::load_from_device(self, *encoder).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) - }) - }).collect::>>()?; - - // and if any encoder supports the selected crtc - let resource_handles = ControlDevice::resource_handles(self).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) - })?; - if !encoders - .iter() - .map(|encoder| encoder.possible_crtcs()) - .any(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&crtc)) - { - bail!(ErrorKind::NoSuitableEncoder(con_info, crtc)) + if let Some(enc) = con_info.current_encoder() { + let enc_info = encoder::Info::load_from_device(self, enc).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) + })?; + if let Some(current_crtc) = enc_info.current_crtc() { + if crtc == current_crtc { + connectors.insert(con); + } + } } } - // configuration is valid, the kernel will figure out the rest - let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc))); - let state = State { mode, connectors }; - let backend = Rc::new(LegacyDrmSurfaceInternal { dev: self.dev.clone(), crtc, state: RwLock::new(state.clone()), pending: RwLock::new(state), - logger, + logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))), }); self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index 36a58d7..e1ebbd4 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -15,7 +15,7 @@ use super::{error::*, Dev}; #[derive(Debug, PartialEq, Eq, Clone)] pub struct State { - pub mode: Mode, + pub mode: Option, pub connectors: HashSet, } @@ -77,11 +77,11 @@ impl Surface for LegacyDrmSurfaceInternal { self.pending.read().unwrap().connectors.clone() } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.state.read().unwrap().mode.clone() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.pending.read().unwrap().mode.clone() } @@ -93,7 +93,7 @@ impl Surface for LegacyDrmSurfaceInternal { let mut pending = self.pending.write().unwrap(); // check if the connector can handle the current mode - if info.modes().contains(&pending.mode) { + if info.modes().contains(pending.mode.as_ref().unwrap()) { // check if there is a valid encoder let encoders = info .encoders() @@ -119,7 +119,7 @@ impl Surface for LegacyDrmSurfaceInternal { pending.connectors.insert(connector); Ok(()) } else { - bail!(ErrorKind::ModeNotSuitable(pending.mode)); + bail!(ErrorKind::ModeNotSuitable(pending.mode.unwrap())); } } @@ -128,18 +128,20 @@ impl Surface for LegacyDrmSurfaceInternal { Ok(()) } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { let mut pending = self.pending.write().unwrap(); // check the connectors - for connector in &pending.connectors { - if !connector::Info::load_from_device(self, *connector) - .chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) - })?.modes() - .contains(&mode) - { - bail!(ErrorKind::ModeNotSuitable(mode)); + if let Some(mode) = mode { + for connector in &pending.connectors { + if !connector::Info::load_from_device(self, *connector) + .chain_err(|| { + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) + })?.modes() + .contains(&mode) + { + bail!(ErrorKind::ModeNotSuitable(mode)); + } } } @@ -179,7 +181,11 @@ impl RawSurface for LegacyDrmSurfaceInternal { } if current.mode != pending.mode { - info!(self.logger, "Setting new mode: {:?}", pending.mode.name()); + info!( + self.logger, + "Setting new mode: {:?}", + pending.mode.as_ref().unwrap().name() + ); } } @@ -194,7 +200,7 @@ impl RawSurface for LegacyDrmSurfaceInternal { .map(|x| *x) .collect::>(), (0, 0), - Some(pending.mode), + pending.mode, ).chain_err(|| { ErrorKind::DrmDev(format!( "Error setting crtc {:?} on {:?}", @@ -270,11 +276,11 @@ impl Surface for LegacyDrmSurface { self.0.pending_connectors() } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.0.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.0.pending_mode() } @@ -286,7 +292,7 @@ impl Surface for LegacyDrmSurface { self.0.remove_connector(connector) } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.0.use_mode(mode) } } diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 2b60f5d..82d3c54 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -38,8 +38,6 @@ pub trait Device: AsRawFd + DevPath { fn create_surface( &mut self, ctrc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, ) -> Result::Error>; fn process_events(&mut self); fn resource_info( @@ -62,9 +60,9 @@ pub trait Surface { fn pending_connectors(&self) -> Self::Connectors; fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; - fn current_mode(&self) -> Mode; - fn pending_mode(&self) -> Mode; - fn use_mode(&self, mode: Mode) -> Result<(), Self::Error>; + fn current_mode(&self) -> Option; + fn pending_mode(&self) -> Option; + fn use_mode(&self, mode: Option) -> Result<(), Self::Error>; } pub trait RawSurface: Surface + ControlDevice + BasicDevice { From 174c15088707be09aaf6dc7b51992bc771915ffb Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 2 Dec 2018 20:07:50 +0100 Subject: [PATCH 41/56] docs: added drm --- src/backend/drm/mod.rs | 142 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 82d3c54..b583279 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -1,3 +1,40 @@ +//! +//! +//! This module provides Traits reprensentating open devices +//! and their surfaces to render contents. +//! +//! --- +//! +//! Initialization of devices happens through an open file descriptor +//! of a drm device. +//! +//! --- +//! +//! Initialization of surfaces happens through the types provided by +//! [`drm-rs`](https://docs.rs/drm/0.3.4/drm/). +//! +//! Four entities are relevant for the initialization procedure. +//! +//! [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html)s represent scanout engines +//! of the device pointer to one framebuffer. +//! Their responsibility is to read the data of the framebuffer and export it into an "Encoder". +//! The number of crtc's represent the number of independant output devices the hardware may handle. +//! +//! An [`encoder`](https://docs.rs/drm/0.3.4/drm/control/encoder/index.html) encodes the data of +//! connected crtcs into a video signal for a fixed set of connectors. +//! E.g. you might have an analog encoder based on a DAG for VGA ports, but another one for digital ones. +//! Also not every encoder might be connected to every crtc. +//! +//! A [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html) represents a port +//! on your computer, possibly with a connected monitor, TV, capture card, etc. +//! +//! On surface creation a matching encoder for your `encoder`-`connector` is automatically selected, +//! if it exists, which means you still need to check your configuration. +//! +//! At last a [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html) needs to be selected, +//! supported by the `crtc` in question. +//! + pub use drm::{ control::{connector, crtc, framebuffer, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo}, Device as BasicDevice, @@ -23,55 +60,155 @@ pub mod gbm; #[cfg(feature = "backend_drm_legacy")] pub mod legacy; +/// Trait to receive events of a bound [`Device`](trait.Device.html) +/// +/// See [`device_bind`](fn.device_bind.html) pub trait DeviceHandler { + /// The [`Device`](trait.Device.html) type this handler can handle type Device: Device + ?Sized; + + /// A vblank blank event on the provided crtc has happend fn vblank(&mut self, crtc: crtc::Handle); + /// An error happend while processing events fn error(&mut self, error: <<::Device as Device>::Surface as Surface>::Error); } +/// An open drm device pub trait Device: AsRawFd + DevPath { + /// Associated [`Surface`](trait.Surface.html) of this `Device` type type Surface: Surface; + /// Returns the `id` of this device node. fn device_id(&self) -> dev_t; + + /// Assigns a `DeviceHandler` called during event processing. + /// + /// See [`device_bind`](fn.device_bind.html) and [`DeviceHandler`](trait.DeviceHandler.html) fn set_handler(&mut self, handler: impl DeviceHandler + 'static); + /// Clear a set [`DeviceHandler`](trait.DeviceHandler.html), if any fn clear_handler(&mut self); + + /// Creates a new rendering surface. + /// + /// Initialization of surfaces happens through the types provided by + /// [`drm-rs`](https://docs.rs/drm/0.3.4/drm/). + /// + /// [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html)s represent scanout engines + /// of the device pointer to one framebuffer. + /// Their responsibility is to read the data of the framebuffer and export it into an "Encoder". + /// The number of crtc's represent the number of independant output devices the hardware may handle. fn create_surface( &mut self, ctrc: crtc::Handle, ) -> Result::Error>; + + /// Processes any open events of the underlying file descriptor. + /// + /// You should not call this function manually, but rather use + /// [`device_bind`](fn.device_bind.html) to register the device + /// to an [`EventLoop`](https://docs.rs/calloop/0.4.2/calloop/struct.EventLoop.html) + /// to synchronize your rendering to the vblank events of the open crtc's fn process_events(&mut self); + + /// Load the resource from a `Device` given its + /// [`ResourceHandle`](https://docs.rs/drm/0.3.4/drm/control/trait.ResourceHandle.html) fn resource_info( &self, handle: T::Handle, ) -> Result::Error>; + + /// Attempts to acquire a copy of the `Device`'s + /// [`ResourceHandles`](https://docs.rs/drm/0.3.4/drm/control/struct.ResourceHandles.html) fn resource_handles(&self) -> Result::Error>; } +/// Marker trait for `Device`s able to provide [`RawSurface`](trait.RawSurface.html)s pub trait RawDevice: Device::Surface> { + /// Associated [`RawSurface`](trait.RawSurface.html) of this `RawDevice` type type Surface: RawSurface; } +/// An open crtc that can be used for rendering pub trait Surface { + /// Type repesenting a collection of + /// [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s + /// returned by [`current_connectors`](#method.current_connectors) and + /// [`pending_connectors`](#method.pending_connectors) type Connectors: IntoIterator; + /// Error type returned by methods of this trait type Error: Error + Send; + /// Returns the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html) of this surface fn crtc(&self) -> crtc::Handle; + /// Currently used [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s of this `Surface` fn current_connectors(&self) -> Self::Connectors; + /// Returns the pending [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s + /// used after the next `commit` of this `Surface` + /// + /// *Note*: Only on a [`RawSurface`](trait.RawSurface.html) you may directly trigger + /// a [`commit`](trait.RawSurface.html#method.commit). Other `Surface`s provide their + /// own methods that *may* trigger a commit, you will need to read their docs. fn pending_connectors(&self) -> Self::Connectors; + /// Tries to add a new [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html) + /// to be used after the next commit. + /// + /// Fails if the `connector` is not compatible with the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html) + /// (e.g. no suitable [`encoder`](https://docs.rs/drm/0.3.4/drm/control/encoder/index.html) may be found) + /// or is not compatible with the currently pending + /// [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html). fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; + /// Tries to mark a [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html) + /// for removal on the next commit. fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; + /// Returns the currently active [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html) + /// of the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html) + /// if any. fn current_mode(&self) -> Option; + /// Returns the currently pending [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html) + /// to be used after the next commit, if any. fn pending_mode(&self) -> Option; + /// Tries to set a new [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html) + /// to be used after the next commit. + /// + /// Fails if the mode is not compatible with the underlying + /// [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html) or any of the + /// pending [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s. + /// + /// *Note*: Only on a [`RawSurface`](trait.RawSurface.html) you may directly trigger + /// a [`commit`](trait.RawSurface.html#method.commit). Other `Surface`s provide their + /// own methods that *may* trigger a commit, you will need to read their docs. fn use_mode(&self, mode: Option) -> Result<(), Self::Error>; } +/// An open bare crtc without any rendering abstractions pub trait RawSurface: Surface + ControlDevice + BasicDevice { + /// Returns true whenever any state changes are pending to be commited + /// + /// The following functions may trigger a pending commit: + /// - [`add_connector`](trait.Surface.html#method.add_connector) + /// - [`remove_connector`](trait.Surface.html#method.remove_connector) + /// - [`use_mode`](trait.Surface.html#method.use_mode) fn commit_pending(&self) -> bool; + /// Commit the pending state rendering a given framebuffer. + /// + /// *Note*: This will trigger a full modeset on the underlying device, + /// potentially causing some flickering. Check before performing this + /// operation if a commit really is necessary using [`commit_pending`](#method.commit_pending). + /// + /// This operation is blocking until the crtc is in the desired state. fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), ::Error>; + /// Page-flip the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html) + /// to a new given [`framebuffer`]. + /// + /// This will not cause the crtc to modeset. + /// + /// This operation is not blocking and will produce a `vblank` event once swapping is done. + /// Make sure to [set a `DeviceHandler`](trait.Device.html#method.set_handler) and + /// [register the belonging `Device`](fn.device_bind.html) before to receive the event in time. fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError>; } -/// Trait for types representing open devices +/// Trait representing open devices that *may* return a `Path` pub trait DevPath { /// Returns the path of the open device if possible fn dev_path(&self) -> Option; @@ -87,7 +224,8 @@ impl DevPath for A { /// Bind a `Device` to an `EventLoop`, /// -/// This will cause it to recieve events and feed them into an `DeviceHandler` +/// This will cause it to recieve events and feed them into a previously +/// set [`DeviceHandler`](trait.DeviceHandler.html). pub fn device_bind( handle: &LoopHandle, device: D, From 3b92e351b1c4b589d2b4e281c400c74e176ded8c Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 2 Dec 2018 21:58:08 +0100 Subject: [PATCH 42/56] docs: added drm/legacy --- src/backend/drm/legacy/mod.rs | 16 +++++++++++++--- src/backend/drm/legacy/session.rs | 11 +++++++++-- src/backend/drm/legacy/surface.rs | 10 +--------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 5a0d221..0309e73 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -1,13 +1,22 @@ -use super::{DevPath, Device, DeviceHandler, RawDevice, Surface}; +//! +//! [`RawDevice`](../trait.RawDevice.html) and [`RawSurface`](../trait.RawSurface.html) +//! implementations using the legacy mode-setting infrastructure. +//! +//! Usually this implementation will be wrapped into a [`GbmDevice`](../gbm/struct.GbmDevice.html). +//! Take a look at `anvil`s source code for an example of this. +//! +//! For an example how to use this standalone, take a look at the `raw_drm` example. +//! -use drm::control::{connector, crtc, encoder, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo}; +use super::{DevPath, Device, DeviceHandler, RawDevice}; + +use drm::control::{connector, crtc, encoder, Device as ControlDevice, ResourceHandles, ResourceInfo}; use drm::Device as BasicDevice; use nix::libc::dev_t; use nix::sys::stat::fstat; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; -use std::iter::FromIterator; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -23,6 +32,7 @@ use self::error::*; #[cfg(feature = "backend_session")] pub mod session; +/// Open raw drm device utilizing legacy mode-setting pub struct LegacyDrmDevice { dev: Rc>, dev_id: dev_t, diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs index 3f75a13..0d86145 100644 --- a/src/backend/drm/legacy/session.rs +++ b/src/backend/drm/legacy/session.rs @@ -1,4 +1,9 @@ -use drm::control::{connector, crtc}; +//! +//! Support to register an open [`LegacyDrmDevice`](../struct.LegacyDrmDevice.html) +//! to an open [`Session`](../../session/trait.Session.html). +//! + +use drm::control::{crtc}; use drm::Device as BasicDevice; use nix::libc::dev_t; use nix::sys::stat; @@ -12,7 +17,9 @@ use std::sync::Arc; use super::{Dev, LegacyDrmDevice, LegacyDrmSurfaceInternal}; use backend::session::{AsSessionObserver, SessionObserver}; -/// `SessionObserver` linked to the `DrmDevice` it was created from. +/// [`SessionObserver`](../../session/trait.SessionObserver.html) +/// linked to the [`LegacyDrmDevice`](../struct.LegacyDrmDevice.html) +/// it was created from. pub struct LegacyDrmDeviceObserver { dev: Weak>, dev_id: dev_t, diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index e1ebbd4..3a20d4d 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -233,17 +233,9 @@ impl Drop for LegacyDrmSurfaceInternal { } } +/// Open raw crtc utilizing legacy mode-setting pub struct LegacyDrmSurface(pub(super) Rc>); -impl AsRawFd for LegacyDrmSurface { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl BasicDevice for LegacyDrmSurface {} -impl ControlDevice for LegacyDrmSurface {} - impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { type CursorFormat = &'a Buffer; type Error = Error; From 1f8a7e73358c4179b80a92fbb78394fb97e08372 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Mon, 3 Dec 2018 23:26:10 +0100 Subject: [PATCH 43/56] docs: add drm/gbm --- src/backend/drm/gbm/egl.rs | 17 ++++++++++++----- src/backend/drm/gbm/error.rs | 2 +- src/backend/drm/gbm/mod.rs | 15 +++++++++++++-- src/backend/drm/gbm/session.rs | 9 ++++++++- src/backend/drm/gbm/surface.rs | 19 ++++++++++++++++++- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 696b400..6fdd0ff 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -1,4 +1,10 @@ -use backend::drm::{connector, Device, RawDevice, RawSurface, Surface}; +//! +//! Egl [`NativeDisplay`](../../egl/native/trait.NativeDisplay.html) and +//! [`NativeSurface`](../../egl/native/trait.NativeSurface.html) support for +//! [`GbmDevice`](../struct.GbmDevice.html) and [`GbmSurface`](../struct.GbmSurface.html). +//! + +use backend::drm::{Device, RawDevice}; use backend::egl::error::Result as EglResult; use backend::egl::ffi; use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; @@ -7,13 +13,14 @@ use backend::graphics::SwapBuffersError; use super::error::{Error, Result}; use super::{GbmDevice, GbmSurface}; -use drm::control::{crtc, Device as ControlDevice, Mode}; +use drm::control::{crtc, Device as ControlDevice}; use gbm::AsRaw; -use std::iter::{FromIterator, IntoIterator}; use std::marker::PhantomData; use std::ptr; -/// Gbm backend type +/// Egl Gbm backend type +/// +/// See [`Backend`](../../egl/native/trait.Backend.html). pub struct Gbm { _userdata: PhantomData, } @@ -68,7 +75,7 @@ unsafe impl NativeSurface for GbmSurface { } fn needs_recreation(&self) -> bool { - self.0.crtc.commit_pending() + self.needs_recreation() } fn recreate(&self) -> bool { diff --git a/src/backend/drm/gbm/error.rs b/src/backend/drm/gbm/error.rs index e654c2d..452e657 100644 --- a/src/backend/drm/gbm/error.rs +++ b/src/backend/drm/gbm/error.rs @@ -48,6 +48,6 @@ error_chain! { } foreign_links { - FailedToSwap(::backend::graphics::SwapBuffersError); + FailedToSwap(::backend::graphics::SwapBuffersError) #[doc = "Swapping front buffers failed"]; } } diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 7b4f4bd..b45d2c1 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -1,6 +1,17 @@ +//! +//! [`Device`](../trait.Device.html) and [`Surface`](../trait.Surface.html) +//! implementations using gbm buffers for efficient rendering. +//! +//! Usually this implementation will be wrapped into a [`EglDevice`](../egl/struct.EglDevice.html). +//! Take a look at `anvil`s source code for an example of this. +//! +//! To use these types standalone, you will need to consider the special requirements +//! of [`GbmSurface::page_flip`](struct.GbmSurface.html#method.page_flip). +//! + use super::{Device, DeviceHandler, RawDevice, ResourceHandles, ResourceInfo, Surface}; -use drm::control::{connector, crtc, Device as ControlDevice, Mode}; +use drm::control::{crtc, Device as ControlDevice}; use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use nix::libc::dev_t; @@ -25,7 +36,7 @@ pub mod session; static LOAD: Once = ONCE_INIT; -/// Representation of an open gbm device to create rendering backends +/// Representation of an open gbm device to create rendering surfaces pub struct GbmDevice { pub(self) dev: Rc>>, backends: Rc>>>>, diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs index 1894a5f..4d3bd82 100644 --- a/src/backend/drm/gbm/session.rs +++ b/src/backend/drm/gbm/session.rs @@ -1,3 +1,8 @@ +//! +//! Support to register a [`GbmDevice`](../struct.GbmDevice.html) +//! to an open [`Session`](../../session/trait.Session.html). +//! + use drm::control::{crtc, Device as ControlDevice, ResourceInfo}; use gbm::BufferObject; use std::cell::RefCell; @@ -9,7 +14,9 @@ use super::{GbmDevice, GbmSurfaceInternal}; use backend::drm::{RawDevice, RawSurface}; use backend::session::{AsSessionObserver, SessionObserver}; -/// `SessionObserver` linked to the `DrmDevice` it was created from. +/// [`SessionObserver`](../../session/trait.SessionObserver.html) +/// linked to the [`GbmDevice`](../struct.GbmDevice.html) it was +/// created from. pub struct GbmDeviceObserver< S: SessionObserver + 'static, D: RawDevice + ControlDevice + AsSessionObserver + 'static, diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index 704ee64..9bcf2b9 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -1,7 +1,7 @@ use super::super::{Device, RawDevice, RawSurface, Surface}; use super::error::*; -use drm::control::{connector, crtc, framebuffer, Mode, ResourceHandles, ResourceInfo}; +use drm::control::{connector, crtc, framebuffer, Mode, ResourceInfo}; use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle}; use image::{ImageBuffer, Rgba}; @@ -278,16 +278,33 @@ impl Drop for GbmSurfaceInternal { } } +/// Gbm surface for rendering pub struct GbmSurface(pub(super) Rc>); impl GbmSurface { + /// Flips the underlying buffers. + /// + /// *Note*: This might trigger a full modeset on the underlying device, + /// potentially causing some flickering. In that case this operation is + /// blocking until the crtc is in the desired state. pub fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { self.0.page_flip() } + /// Recreate underlying gbm resources. + /// + /// This recreates the gbm surfaces resources, which might be needed after e.g. + /// calling [`Surface::use_mode`](../trait.Surface.html#method.use_mode). + /// You may check if your `GbmSurface` needs recreation through + /// [`needs_recreation`](#method.needs_recreation). pub fn recreate(&self) -> Result<()> { self.0.recreate() } + + /// Check if underlying gbm resources need to be recreated. + pub fn needs_recreation(&self) -> bool { + self.0.crtc.commit_pending() + } } impl Surface for GbmSurface { From 6609754d13fe4b67a69b576434639991f84264ad Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Mon, 3 Dec 2018 23:26:16 +0100 Subject: [PATCH 44/56] docs: add drm/egl --- src/backend/drm/egl/mod.rs | 24 +++++++++++++++++------- src/backend/drm/egl/session.rs | 11 +++++++++-- src/backend/drm/egl/surface.rs | 1 + 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 759b65d..a867582 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -1,3 +1,13 @@ +//! +//! [`Device`](../trait.Device.html) and [`Surface`](../trait.Surface.html) +//! implementations using egl contexts and surfaces for efficient rendering. +//! +//! Usually this implementation's [`EglSurface`](struct.EglSurface.html)s implementation +//! of [`GlGraphicsBackend`](../../graphics/gl/trait.GlGraphicsBackend.html) will be used +//! to let your compositor render. +//! Take a look at `anvil`s source code for an example of this. +//! + use drm::control::{crtc, ResourceHandles, ResourceInfo}; use nix::libc::dev_t; use std::os::unix::io::{AsRawFd, RawFd}; @@ -21,7 +31,7 @@ pub use self::surface::*; #[cfg(feature = "backend_session")] pub mod session; -/// Representation of an open gbm device to create rendering backends +/// Representation of an egl device to create egl rendering surfaces pub struct EglDevice< B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static, @@ -51,10 +61,10 @@ impl< where ::Surface: NativeSurface, { - /// Create a new `EglGbmDrmDevice` from an open drm node + /// Try to create a new `EglDevice` from an open device. /// - /// Returns an error if the file is no valid drm node or context creation was not - /// successful. + /// Returns an error if the file is no valid device or context + /// creation was not successful. pub fn new(dev: D, logger: L) -> Result where L: Into>, @@ -71,10 +81,10 @@ where ) } - /// Create a new `EglGbmDrmDevice` from an open `RawDevice` and given `GlAttributes` + /// Create a new `EglDevice` from an open device and given `GlAttributes` /// - /// Returns an error if the file is no valid drm node or context creation was not - /// successful. + /// Returns an error if the file is no valid device or context + /// creation was not successful. pub fn new_with_gl_attr(mut dev: D, attributes: GlAttributes, logger: L) -> Result where L: Into>, diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index 7247d2d..b07d8a9 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -1,4 +1,9 @@ -use drm::control::{connector, crtc, Mode}; +//! +//! Support to register an [`EglDevice`](../struct.EglDevice.html) +//! to an open [`Session`](../../session/trait.Session.html). +//! + +use drm::control::crtc; use std::os::unix::io::RawFd; use super::EglDevice; @@ -6,7 +11,9 @@ use backend::drm::Device; use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use backend::session::{AsSessionObserver, SessionObserver}; -/// `SessionObserver` linked to the `DrmDevice` it was created from. +/// [`SessionObserver`](../../session/trait.SessionObserver.html) +/// linked to the [`EglDevice`](../struct.EglDevice.html) it was +/// created from. pub struct EglDeviceObserver { observer: S, } diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index b8be770..0c17a9b 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -12,6 +12,7 @@ use backend::graphics::gl::GLGraphicsBackend; use backend::graphics::PixelFormat; use backend::graphics::{CursorBackend, SwapBuffersError}; +/// Egl surface for rendering pub struct EglSurface< B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static, From 36b265400a863fcf0214e10bd75dd9376fefb9e4 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Mon, 3 Dec 2018 23:26:32 +0100 Subject: [PATCH 45/56] docs: add graphics/gl --- src/backend/graphics/gl.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/graphics/gl.rs b/src/backend/graphics/gl.rs index c811ff5..c7f59fd 100644 --- a/src/backend/graphics/gl.rs +++ b/src/backend/graphics/gl.rs @@ -1,3 +1,5 @@ +//! Gl rendering types + use nix::libc::c_void; use super::{PixelFormat, SwapBuffersError}; From 2bc45d405394dcd12357942c3b99a1ec4e1bd931 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Mon, 3 Dec 2018 23:27:29 +0100 Subject: [PATCH 46/56] docs: fix backend_session_logind --- src/backend/session/auto.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index e1dd62f..b192076 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -114,6 +114,7 @@ impl AutoSession { } } + /// Tries to create a new session via the best available interface. #[cfg(not(feature = "backend_session_logind"))] pub fn new(logger: L) -> Option<(AutoSession, AutoSessionNotifier)> where From aa2090c079b58b798d26f566187774d3d3c454b4 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Mon, 3 Dec 2018 23:28:01 +0100 Subject: [PATCH 47/56] docs: add session/multi --- src/backend/session/multi.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/backend/session/multi.rs b/src/backend/session/multi.rs index 8fa57b3..4cd3fb7 100644 --- a/src/backend/session/multi.rs +++ b/src/backend/session/multi.rs @@ -52,6 +52,11 @@ impl SessionNotifier for MultiNotifier { } } +/// Create a pair of a linked [`SessionObserver`](../trait.SessionObserver.html) and a +/// [`SessionNotifier`](../trait.SessionNotifier.html). +/// +/// Observers added to the returned notifier are notified, +/// when the returned observer is notified. pub fn notify_multiplexer() -> (impl SessionObserver, impl SessionNotifier) { let observer = Arc::new(Mutex::new(HashMap::new())); From 8fbce616a633d99fbba0575e0af0aeab372060b3 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 5 Dec 2018 09:30:11 +0100 Subject: [PATCH 48/56] libinput: update to 0.4.1 --- Cargo.toml | 2 +- src/backend/libinput.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 153f4e5..2eb11b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ winit = { version = "0.18.0", optional = true } drm = { version = "^0.3.4", optional = true } gbm = { version = "^0.4.0", optional = true, default-features = false, features = ["drm-support"] } glium = { version = "0.19.0", optional = true, default-features = false } -input = { version = "0.4.0", optional = true } +input = { version = "0.4.1", optional = true } udev = { version = "0.2.0", optional = true } dbus = { version = "0.6.1", optional = true } systemd = { version = "^0.2.0", optional = true } diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index 199575e..95de7d3 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -594,7 +594,7 @@ impl libinput::LibinputInterface for LibinputSessionInterface { impl AsRawFd for LibinputInputBackend { fn as_raw_fd(&self) -> RawFd { - unsafe { self.context.fd() } + self.context.as_raw_fd() } } From a3734da9daa6dee434d0147a13656cfb9d69a419 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 5 Dec 2018 09:31:51 +0100 Subject: [PATCH 49/56] gbm: update to gbm 0.5 --- Cargo.toml | 2 +- src/backend/drm/gbm/egl.rs | 2 +- src/backend/drm/gbm/surface.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2eb11b9..da4bdb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ libloading = "0.4.0" wayland-client = { version = "0.21.1", features = ["egl"], optional = true } winit = { version = "0.18.0", optional = true } drm = { version = "^0.3.4", optional = true } -gbm = { version = "^0.4.0", optional = true, default-features = false, features = ["drm-support"] } +gbm = { version = "^0.5.0", optional = true, default-features = false, features = ["drm-support"] } glium = { version = "0.19.0", optional = true, default-features = false } input = { version = "0.4.1", optional = true } udev = { version = "0.2.0", optional = true } diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 6fdd0ff..cf9268b 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -88,6 +88,6 @@ unsafe impl NativeSurface for GbmSurface { } fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { - self.page_flip() + unsafe { self.page_flip() } } } diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index 9bcf2b9..c6b578c 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -35,7 +35,7 @@ impl GbmSurfaceInternal { // drop and release the old buffer } - pub fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { + pub unsafe fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { let res = { let nb = self.next_buffer.take(); let res = nb.is_some(); @@ -287,7 +287,7 @@ impl GbmSurface { /// *Note*: This might trigger a full modeset on the underlying device, /// potentially causing some flickering. In that case this operation is /// blocking until the crtc is in the desired state. - pub fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { + pub unsafe fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { self.0.page_flip() } From bbe767002d07677483f2848f87659fe3175aa796 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 5 Dec 2018 16:00:01 +0100 Subject: [PATCH 50/56] comments: add more explainations to new code --- src/backend/drm/egl/mod.rs | 2 +- src/backend/drm/gbm/egl.rs | 2 ++ src/backend/drm/gbm/mod.rs | 2 ++ src/backend/drm/gbm/surface.rs | 5 +++++ src/backend/drm/legacy/mod.rs | 7 ++++++- src/backend/drm/legacy/session.rs | 4 +++- src/backend/drm/legacy/surface.rs | 11 ++++++++++- src/backend/drm/mod.rs | 3 ++- src/backend/graphics/gl.rs | 2 +- 9 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index a867582..c834875 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -63,7 +63,7 @@ where { /// Try to create a new `EglDevice` from an open device. /// - /// Returns an error if the file is no valid device or context + /// Returns an error if the file is no valid device or context /// creation was not successful. pub fn new(dev: D, logger: L) -> Result where diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index cf9268b..8dff15b 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -88,6 +88,8 @@ unsafe impl NativeSurface for GbmSurface { } fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { + // this is save since `eglSwapBuffers` will have been called exactly once + // if this is used by our egl module, which is why this trait is unsafe. unsafe { self.page_flip() } } } diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index b45d2c1..ed3eeb1 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -136,6 +136,7 @@ impl Device for GbmDevice { let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc) .chain_err(|| ErrorKind::UnderlyingBackendError)?; + // initialize the surface let (w, h) = drm_surface .pending_mode() .map(|mode| mode.size()) @@ -150,6 +151,7 @@ impl Device for GbmDevice { BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; + // initialize a buffer for the cursor image let cursor = Cell::new(( self.dev .borrow() diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index c6b578c..b60b8a9 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -284,6 +284,11 @@ pub struct GbmSurface(pub(super) Rc GbmSurface { /// Flips the underlying buffers. /// + /// The surface will reported being already flipped until the matching events + /// was processed either by calling `GbmDevice::process_events` manually after the flip + /// (bad idea performance-wise) or by binding the device to an event-loop by using + /// `device_bind`. + /// /// *Note*: This might trigger a full modeset on the underlying device, /// potentially causing some flickering. In that case this operation is /// blocking until the crtc is in the desired state. diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 0309e73..51d5e4a 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -60,6 +60,9 @@ impl Drop for Dev { fn drop(&mut self) { info!(self.logger, "Dropping device: {:?}", self.dev_path()); if self.active.load(Ordering::SeqCst) { + // Here we restore the tty to it's previous state. + // In case e.g. getty was running on the tty sets the correct framebuffer again, + // so that getty will be visible. let old_state = self.old_state.clone(); for (handle, (info, connectors)) in old_state { if let Err(err) = crtc::set( @@ -113,6 +116,7 @@ impl LegacyDrmDevice { dev.priviledged = false; }; + // enumerate (and save) the current device state let res_handles = ControlDevice::resource_handles(&dev).chain_err(|| { ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", dev.dev_path())) })?; @@ -138,7 +142,6 @@ impl LegacyDrmDevice { } Ok(LegacyDrmDevice { - // Open the drm device and create a context based on that dev: Rc::new(dev), dev_id, active, @@ -182,6 +185,8 @@ impl Device for LegacyDrmDevice { bail!(ErrorKind::DeviceInactive); } + // Try to enumarate the current state to set the initial state variable correctly + let crtc_info = crtc::Info::load_from_device(self, crtc) .chain_err(|| ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", self.dev_path())))?; diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs index 0d86145..fcb7b55 100644 --- a/src/backend/drm/legacy/session.rs +++ b/src/backend/drm/legacy/session.rs @@ -3,7 +3,7 @@ //! to an open [`Session`](../../session/trait.Session.html). //! -use drm::control::{crtc}; +use drm::control::crtc; use drm::Device as BasicDevice; use nix::libc::dev_t; use nix::sys::stat; @@ -52,6 +52,8 @@ impl SessionObserver for LegacyDrmDeviceObserver { if let Some(device) = self.dev.upgrade() { if let Some(backends) = self.backends.upgrade() { for surface in backends.borrow().values().filter_map(Weak::upgrade) { + // other ttys that use no cursor, might not clear it themselves. + // This makes sure our cursor won't stay visible. let _ = crtc::clear_cursor(&*device, surface.crtc); } } diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index 3a20d4d..f05b618 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -131,7 +131,7 @@ impl Surface for LegacyDrmSurfaceInternal { fn use_mode(&self, mode: Option) -> Result<()> { let mut pending = self.pending.write().unwrap(); - // check the connectors + // check the connectors to see if this mode is supported if let Some(mode) = mode { for connector in &pending.connectors { if !connector::Info::load_from_device(self, *connector) @@ -236,6 +236,15 @@ impl Drop for LegacyDrmSurfaceInternal { /// Open raw crtc utilizing legacy mode-setting pub struct LegacyDrmSurface(pub(super) Rc>); +impl AsRawFd for LegacyDrmSurface { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl BasicDevice for LegacyDrmSurface {} +impl ControlDevice for LegacyDrmSurface {} + impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for LegacyDrmSurface { type CursorFormat = &'a Buffer; type Error = Error; diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index b583279..d75932a 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -36,8 +36,9 @@ //! pub use drm::{ - control::{connector, crtc, framebuffer, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo}, Device as BasicDevice, + buffer::Buffer, + control::{connector, crtc, framebuffer, Mode, ResourceHandles, ResourceInfo, Device as ControlDevice}, }; pub use nix::libc::dev_t; diff --git a/src/backend/graphics/gl.rs b/src/backend/graphics/gl.rs index c7f59fd..aa8984d 100644 --- a/src/backend/graphics/gl.rs +++ b/src/backend/graphics/gl.rs @@ -49,7 +49,7 @@ pub trait GLGraphicsBackend { /// /// This remains valid as long as the underlying `GLGraphicsBackend` is alive /// and may only be used in combination with the backend. Using this with any -/// other gl context may cause undefined behavior. +/// other gl context *may* cause undefined behavior. pub fn load_raw_gl(backend: &B) -> Gles2 { Gles2::load_with(|s| unsafe { backend.get_proc_address(s) as *const _ }) } From 14d2e6e37330395f65dc0131888dcc300542cf3d Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 5 Dec 2018 16:00:17 +0100 Subject: [PATCH 51/56] anvil: explain the implementation a bit more --- anvil/src/udev.rs | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 19cd778..49122e8 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -132,6 +132,9 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger log.clone(), ).map_err(|_| ())?; + /* + * Initialize wayland clipboard + */ init_data_device( &mut display.borrow_mut(), |_| {}, @@ -139,6 +142,9 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger log.clone(), ); + /* + * Initialize wayland input object + */ let (mut w_seat, _) = Seat::new(&mut display.borrow_mut(), session.seat(), log.clone()); let pointer = w_seat.add_pointer(); @@ -147,6 +153,9 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger set_data_device_focus(seat, focus.and_then(|s| s.client())) }).expect("Failed to initialize the keyboard"); + /* + * Initialize a fake output (we render one screen to every device in this example) + */ let (output, _output_global) = Output::new( &mut display.borrow_mut(), "Drm".into(), @@ -194,6 +203,10 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger pointer_location, session, )); + + /* + * Bind all our objects that get driven by the event loop + */ let libinput_event_source = libinput_bind(libinput_backend, event_loop.handle()) .map_err(|e| -> IoError { e.into() }) .unwrap(); @@ -204,6 +217,9 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger .map_err(|e| -> IoError { e.into() }) .unwrap(); + /* + * And run our loop + */ while running.load(Ordering::SeqCst) { if event_loop .dispatch(Some(::std::time::Duration::from_millis(16)), &mut ()) @@ -216,6 +232,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger } } + // Cleanup stuff window_map.borrow_mut().clear(); let mut notifier = session_event_source.unbind(); @@ -283,9 +300,7 @@ impl UdevHandlerImpl { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { if !backends.contains_key(&crtc) { let renderer = GliumDrawer::init( - device - .create_surface(crtc) - .unwrap(), + device.create_surface(crtc).unwrap(), egl_display.clone(), logger.clone(), ); @@ -329,12 +344,8 @@ impl UdevHandlerImpl { for encoder_info in encoder_infos { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { if !backends.contains_key(&crtc) { - let renderer = GliumDrawer::init( - device - .create_surface(crtc) - .unwrap(), - logger.clone(), - ); + let renderer = + GliumDrawer::init(device.create_surface(crtc).unwrap(), logger.clone()); backends.insert(crtc, renderer); break; @@ -349,6 +360,7 @@ impl UdevHandlerImpl { impl UdevHandler for UdevHandlerImpl { fn device_added(&mut self, _device: dev_t, path: PathBuf) { + // Try to open the device if let Some(mut device) = self .session .open( @@ -381,6 +393,9 @@ impl UdevHandler for UdevHandlerImpl &self.logger, ))); + // 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 device.set_handler(DrmHandlerImpl { compositor_token: self.compositor_token, backends: backends.clone(), @@ -455,13 +470,13 @@ impl UdevHandler for UdevHandlerImpl renderers.borrow_mut().clear(); debug!(self.logger, "Surfaces dropped"); - // don't use hardware acceleration anymore, if this was the primary gpu let device = Rc::try_unwrap(evt_source.remove().unwrap()) .map_err(|_| "This should not happend") .unwrap() .into_inner() .0; + // 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.primary_gpu { @@ -495,6 +510,7 @@ impl DeviceHandler for DrmHandlerImpl { .set_cursor_position(x.trunc().abs() as u32, y.trunc().abs() as u32); } + // and draw in sync with our monitor drawer.draw_windows(&*self.window_map.borrow(), self.compositor_token, &self.logger); } } From a8343edbd7f1a9bc063d4d06a87b9d80ab1e544b Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 5 Dec 2018 22:44:30 +0100 Subject: [PATCH 52/56] legacy: add legacy drm example --- Cargo.toml | 3 + examples/raw_drm.rs | 150 +++++++++++++++++++++++++++++++++++++++++ src/backend/drm/mod.rs | 6 +- 3 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 examples/raw_drm.rs diff --git a/Cargo.toml b/Cargo.toml index da4bdb3..f08b880 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,9 @@ image = "0.17.0" error-chain = "0.11.0" lazy_static = "1.0.0" +[dev-dependencies] +slog-term = "2.3" + [build-dependencies] gl_generator = { version = "0.9", optional = true } diff --git a/examples/raw_drm.rs b/examples/raw_drm.rs new file mode 100644 index 0000000..ba14bff --- /dev/null +++ b/examples/raw_drm.rs @@ -0,0 +1,150 @@ +extern crate drm; +extern crate smithay; +#[macro_use] +extern crate slog; +extern crate slog_term; + +use drm::{buffer::PixelFormat, control::dumbbuffer::DumbBuffer}; +use slog::Drain; +use smithay::{ + backend::drm::{ + connector::{self, State as ConnectorState}, + crtc, device_bind, encoder, framebuffer, + legacy::{error::Error, LegacyDrmDevice, LegacyDrmSurface}, + ControlDevice, Device, DeviceHandler, RawSurface, ResourceInfo, Surface, + }, + wayland_server::calloop::EventLoop, +}; +use std::{ + fs::{File, OpenOptions}, + io::Error as IoError, + rc::Rc, + sync::Mutex, +}; + +fn main() { + let log = slog::Logger::root(Mutex::new(slog_term::term_full().fuse()).fuse(), o!()); + + /* + * Initialize the drm backend + */ + + // "Find" a suitable drm device + let mut options = OpenOptions::new(); + options.read(true); + options.write(true); + let mut device = LegacyDrmDevice::new(options.open("/dev/dri/card0").unwrap(), log.clone()).unwrap(); + + // Get a set of all modesetting resource handles (excluding planes): + let res_handles = Device::resource_handles(&device).unwrap(); + + // Use first connected connector + let connector_info = res_handles + .connectors() + .iter() + .map(|conn| Device::resource_info::(&device, *conn).unwrap()) + .find(|conn| conn.connection_state() == ConnectorState::Connected) + .unwrap(); + + // Use the first encoder + let encoder_info = Device::resource_info::(&device, connector_info.encoders()[0]).unwrap(); + + // use the connected crtc if any + let crtc = encoder_info + .current_crtc() + // or use the first one that is compatible with the encoder + .unwrap_or_else(|| { + *res_handles + .filter_crtcs(encoder_info.possible_crtcs()) + .iter() + .next() + .unwrap() + }); + + // Assuming we found a good connector and loaded the info into `connector_info` + let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) + + // Initialize the hardware backend + let surface = Rc::new(device.create_surface(crtc).unwrap()); + + surface.use_mode(Some(mode)).unwrap(); + for conn in surface.current_connectors().into_iter() { + if conn != connector_info.handle() { + surface.remove_connector(conn).unwrap(); + } + } + surface.add_connector(connector_info.handle()).unwrap(); + + /* + * Lets create buffers and framebuffers. + * We use drm-rs DumbBuffers, because they always work and require little to no setup. + * But they are very slow, this is just for demonstration purposes. + */ + let (w, h) = mode.size(); + let front_buffer = + DumbBuffer::create_from_device(&device, (w as u32, h as u32), PixelFormat::XRGB8888).unwrap(); + let front_framebuffer = device.create_framebuffer(&front_buffer).unwrap(); + let back_buffer = + DumbBuffer::create_from_device(&device, (w as u32, h as u32), PixelFormat::XRGB8888).unwrap(); + let back_framebuffer = device.create_framebuffer(&back_buffer).unwrap(); + + device.set_handler(DrmHandlerImpl { + current: front_framebuffer.handle(), + front: (front_buffer, front_framebuffer.clone()), + back: (back_buffer, back_framebuffer), + surface: surface.clone(), + }); + + /* + * Register the DrmDevice on the EventLoop + */ + let mut event_loop = EventLoop::<()>::new().unwrap(); + let _source = device_bind(&event_loop.handle(), device) + .map_err(|err| -> IoError { err.into() }) + .unwrap(); + + // Start rendering + if surface.commit_pending() { + surface.commit(front_framebuffer.handle()).unwrap(); + } + surface.page_flip(front_framebuffer.handle()).unwrap(); + + // Run + event_loop.run(None, &mut (), |_| {}).unwrap(); +} + +pub struct DrmHandlerImpl { + front: (DumbBuffer, framebuffer::Info), + back: (DumbBuffer, framebuffer::Info), + current: framebuffer::Handle, + surface: Rc>, +} + +impl DeviceHandler for DrmHandlerImpl { + type Device = LegacyDrmDevice; + + fn vblank(&mut self, _crtc: crtc::Handle) { + { + // Swap and map buffer + let mut mapping = if self.current == self.front.1.handle() { + self.current = self.back.1.handle(); + self.back.0.map(&*self.surface).unwrap() + } else { + self.current = self.front.1.handle(); + self.front.0.map(&*self.surface).unwrap() + }; + + // now we could render to the mapping via software rendering. + // this example just sets some grey color + + for mut x in mapping.as_mut() { + *x = 128; + } + } + self.surface.page_flip(self.current).unwrap(); + } + + fn error(&mut self, error: Error) { + panic!("{:?}", error); + } +} diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index d75932a..8a143b0 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -36,9 +36,11 @@ //! pub use drm::{ - Device as BasicDevice, buffer::Buffer, - control::{connector, crtc, framebuffer, Mode, ResourceHandles, ResourceInfo, Device as ControlDevice}, + control::{ + connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo, + }, + Device as BasicDevice, }; pub use nix::libc::dev_t; From 7dc3d64b6e064e87e0566f0db7930e2b274e0876 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Thu, 6 Dec 2018 14:45:40 +0100 Subject: [PATCH 53/56] docs: typo fixes Co-Authored-By: Drakulix --- src/backend/drm/gbm/egl.rs | 2 +- src/backend/drm/gbm/surface.rs | 2 +- src/backend/graphics/cursor.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 8dff15b..5977870 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -88,7 +88,7 @@ unsafe impl NativeSurface for GbmSurface { } fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { - // this is save since `eglSwapBuffers` will have been called exactly once + // this is safe since `eglSwapBuffers` will have been called exactly once // if this is used by our egl module, which is why this trait is unsafe. unsafe { self.page_flip() } } diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index b60b8a9..96a98eb 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -284,7 +284,7 @@ pub struct GbmSurface(pub(super) Rc GbmSurface { /// Flips the underlying buffers. /// - /// The surface will reported being already flipped until the matching events + /// The surface will report being already flipped until the matching event /// was processed either by calling `GbmDevice::process_events` manually after the flip /// (bad idea performance-wise) or by binding the device to an event-loop by using /// `device_bind`. diff --git a/src/backend/graphics/cursor.rs b/src/backend/graphics/cursor.rs index e08c5cc..7140bd5 100644 --- a/src/backend/graphics/cursor.rs +++ b/src/backend/graphics/cursor.rs @@ -6,7 +6,7 @@ pub trait CursorBackend<'a> { /// Error the underlying backend throws if operations fail type Error; - /// Sets the cursor position and therefor updates the drawn cursors position. + /// Sets the cursor position and therefore updates the drawn cursors position. /// Useful as well for e.g. pointer wrapping. /// /// Not guaranteed to be supported on every backend. The result usually From c24619861eb88a1cdf72c62bed7dc87c1c558038 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sat, 8 Dec 2018 13:46:55 +0100 Subject: [PATCH 54/56] egl: style: move constraints into where clause --- src/backend/drm/egl/mod.rs | 50 +++++++++++++++------------------- src/backend/drm/egl/session.rs | 9 +++--- src/backend/drm/egl/surface.rs | 19 +++++++------ 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index c834875..b918427 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -32,21 +32,20 @@ pub use self::surface::*; pub mod session; /// Representation of an egl device to create egl rendering surfaces -pub struct EglDevice< +pub struct EglDevice +where B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static, -> where ::Surface: NativeSurface, { dev: Rc>, logger: ::slog::Logger, } -impl< - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, - > AsRawFd for EglDevice +impl AsRawFd for EglDevice where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { fn as_raw_fd(&self) -> RawFd { @@ -54,11 +53,10 @@ where } } -impl< - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, - > EglDevice +impl EglDevice where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { /// Try to create a new `EglDevice` from an open device. @@ -104,20 +102,19 @@ where } } -struct InternalDeviceHandler< +struct InternalDeviceHandler +where B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static, -> where ::Surface: NativeSurface, { handler: Box> + 'static>, } -impl< - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, - > DeviceHandler for InternalDeviceHandler +impl DeviceHandler for InternalDeviceHandler where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { type Device = D; @@ -131,11 +128,10 @@ where } } -impl< - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, - > Device for EglDevice +impl Device for EglDevice where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { type Surface = EglSurface; @@ -185,11 +181,10 @@ where } #[cfg(feature = "native_lib")] -impl< - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, - > EGLGraphicsBackend for EglDevice +impl EGLGraphicsBackend for EglDevice where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { fn bind_wl_display(&self, display: &Display) -> EGLResult { @@ -197,11 +192,10 @@ where } } -impl< - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, - > Drop for EglDevice +impl Drop for EglDevice where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { fn drop(&mut self) { diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index b07d8a9..0d6fc3f 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -18,12 +18,11 @@ pub struct EglDeviceObserver { observer: S, } -impl< - S: SessionObserver + 'static, - B: Backend::Surface> + 'static, - D: Device + NativeDisplay + AsSessionObserver + 'static, - > AsSessionObserver> for EglDevice +impl AsSessionObserver> for EglDevice where + S: SessionObserver + 'static, + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + AsSessionObserver + 'static, ::Surface: NativeSurface, { fn observer(&mut self) -> EglDeviceObserver { diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 0c17a9b..064825e 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -13,19 +13,20 @@ use backend::graphics::PixelFormat; use backend::graphics::{CursorBackend, SwapBuffersError}; /// Egl surface for rendering -pub struct EglSurface< +pub struct EglSurface +where B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static, -> where ::Surface: NativeSurface, { pub(super) dev: Rc>, pub(super) surface: EGLSurface, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Surface - for EglSurface +impl Surface for EglSurface where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { type Error = Error; @@ -70,9 +71,10 @@ where } } -impl<'a, B: Backend::Surface> + 'static, D: Device + NativeDisplay + 'static> - CursorBackend<'a> for EglSurface +impl<'a, B, D> CursorBackend<'a> for EglSurface where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface + CursorBackend<'a>, { type CursorFormat = >::CursorFormat; @@ -95,9 +97,10 @@ where } #[cfg(feature = "renderer_gl")] -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - GLGraphicsBackend for EglSurface +impl GLGraphicsBackend for EglSurface where + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, ::Surface: NativeSurface, { fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { From a1b8d2bf47813df7188dacb058ae1c07a92321dd Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sat, 8 Dec 2018 13:49:30 +0100 Subject: [PATCH 55/56] docs: clarify get_framebuffer_dimensions --- src/backend/graphics/gl.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/graphics/gl.rs b/src/backend/graphics/gl.rs index aa8984d..b50e4ba 100644 --- a/src/backend/graphics/gl.rs +++ b/src/backend/graphics/gl.rs @@ -25,9 +25,9 @@ pub trait GLGraphicsBackend { /// Returns the dimensions of the window, or screen, etc in points. /// - /// That are the scaled pixels of the underlying graphics backend. - /// For nested compositors this will respect the scaling of the root compositor. - /// For drawing directly onto hardware this unit will be equal to actual pixels. + /// These are the actual pixels of the underlying graphics backend. + /// For nested compositors you will need to handle the scaling + /// of the root compositor yourself, if you want to. fn get_framebuffer_dimensions(&self) -> (u32, u32); /// Returns true if the OpenGL context is the current one in the thread. From a3acd48cc37de9a120fc3f79003f70b1d9448889 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sat, 8 Dec 2018 18:31:08 +0100 Subject: [PATCH 56/56] fmt: rust 1.31 --- anvil/src/glium_drawer.rs | 15 ++++-- anvil/src/input_handler.rs | 12 +++-- anvil/src/udev.rs | 9 ++-- anvil/src/winit.rs | 3 +- build.rs | 6 ++- src/backend/drm/gbm/mod.rs | 6 ++- src/backend/drm/gbm/session.rs | 9 ++-- src/backend/drm/gbm/surface.rs | 10 ++-- src/backend/drm/legacy/mod.rs | 55 ++++++++++++---------- src/backend/drm/legacy/surface.rs | 12 +++-- src/backend/egl/mod.rs | 7 +-- src/backend/libinput.rs | 25 +++++----- src/backend/session/dbus/logind.rs | 12 +++-- src/backend/session/direct.rs | 9 ++-- src/backend/udev.rs | 6 ++- src/wayland/data_device/dnd_grab.rs | 6 ++- src/wayland/data_device/mod.rs | 6 ++- src/wayland/data_device/server_dnd_grab.rs | 3 +- src/wayland/seat/keyboard.rs | 3 +- src/wayland/shell/legacy/wl_handlers.rs | 3 +- src/wayland/shell/xdg/mod.rs | 6 ++- src/wayland/shell/xdg/xdg_handlers.rs | 24 ++++++---- src/wayland/shell/xdg/zxdgv6_handlers.rs | 24 ++++++---- src/xwayland/xserver.rs | 3 +- 24 files changed, 164 insertions(+), 110 deletions(-) diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index b10e7e1..440ed5a 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -78,7 +78,8 @@ impl> + GLGraphicsBackend + 'static> GliumDrawer tex_coords: [1.0, 0.0], }, ], - ).unwrap(); + ) + .unwrap(); // building the index buffer let index_buffer = @@ -121,7 +122,8 @@ impl> + GLGraphicsBackend + 'static> GliumDrawer tex_coords: [1.0, 0.0], }, ], - ).unwrap(); + ) + .unwrap(); // building the index buffer let index_buffer = @@ -165,7 +167,8 @@ impl GliumDrawer { MipmapsOption::NoMipmap, images.width, images.height, - ).unwrap(); + ) + .unwrap(); unsafe { images .bind_to_texture(0, opengl_texture.get_id()) @@ -261,7 +264,8 @@ impl GliumDrawer { blend: blending, ..Default::default() }, - ).unwrap(); + ) + .unwrap(); } #[inline] @@ -338,7 +342,8 @@ impl GliumDrawer { TraversalAction::SkipChildren } }, - ).unwrap(); + ) + .unwrap(); } }); } diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 689f707..cdb397f 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -132,12 +132,14 @@ impl InputHandler for AnvilInputHandler { self.running.store(false, Ordering::SeqCst); } #[cfg(feature = "udev")] - KeyAction::VtSwitch(vt) => if let Some(ref mut session) = self.session { - info!(log, "Trying to switch to vt {}", vt); - if let Err(err) = session.change_vt(vt) { - error!(log, "Error switching to vt {}: {}", vt, err); + KeyAction::VtSwitch(vt) => { + if let Some(ref mut session) = self.session { + info!(log, "Trying to switch to vt {}", vt); + if let Err(err) = session.change_vt(vt) { + error!(log, "Error switching to vt {}: {}", vt, err); + } } - }, + } KeyAction::Run(cmd) => { info!(self.log, "Starting program"; "cmd" => cmd.clone()); if let Err(e) = Command::new(&cmd).spawn() { diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 49122e8..ffe09fa 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -130,7 +130,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger }, seat.clone(), log.clone(), - ).map_err(|_| ())?; + ) + .map_err(|_| ())?; /* * Initialize wayland clipboard @@ -151,7 +152,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger let keyboard = w_seat .add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| { set_data_device_focus(seat, focus.and_then(|s| s.client())) - }).expect("Failed to initialize the keyboard"); + }) + .expect("Failed to initialize the keyboard"); /* * Initialize a fake output (we render one screen to every device in this example) @@ -366,7 +368,8 @@ impl UdevHandler for UdevHandlerImpl .open( &path, OFlag::O_RDWR | OFlag::O_CLOEXEC | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, - ).ok() + ) + .ok() .and_then(|fd| LegacyDrmDevice::new(SessionFd(fd), self.logger.clone()).ok()) .and_then(|drm| GbmDevice::new(drm, self.logger.clone()).ok()) .and_then(|gbm| EglDevice::new(gbm, self.logger.clone()).ok()) diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 2c3c2b0..f405e4a 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -59,7 +59,8 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log let keyboard = seat .add_keyboard(XkbConfig::default(), 1000, 500, |seat, focus| { set_data_device_focus(seat, focus.and_then(|s| s.client())) - }).expect("Failed to initialize the keyboard"); + }) + .expect("Failed to initialize the keyboard"); let (output, _) = Output::new( display, diff --git a/build.rs b/build.rs index 28ac1cf..dbd1dec 100644 --- a/build.rs +++ b/build.rs @@ -33,7 +33,8 @@ fn main() { "EGL_EXT_platform_device", "EGL_KHR_image_base", ], - ).write_bindings(gl_generator::GlobalGenerator, &mut file) + ) + .write_bindings(gl_generator::GlobalGenerator, &mut file) .unwrap(); } @@ -45,7 +46,8 @@ fn main() { Profile::Compatibility, Fallbacks::None, ["GL_OES_EGL_image"], - ).write_bindings(gl_generator::StructGenerator, &mut file) + ) + .write_bindings(gl_generator::StructGenerator, &mut file) .unwrap(); } } diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index ed3eeb1..7298d7c 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -149,7 +149,8 @@ impl Device for GbmDevice { h as u32, GbmFormat::XRGB8888, BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, - ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; + ) + .chain_err(|| ErrorKind::SurfaceCreationFailed)?; // initialize a buffer for the cursor image let cursor = Cell::new(( @@ -160,7 +161,8 @@ impl Device for GbmDevice { 1, GbmFormat::ARGB8888, BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, - ).chain_err(|| ErrorKind::BufferCreationFailed)?, + ) + .chain_err(|| ErrorKind::BufferCreationFailed)?, (0, 0), )); diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs index 4d3bd82..0777cf4 100644 --- a/src/backend/drm/gbm/session.rs +++ b/src/backend/drm/gbm/session.rs @@ -61,16 +61,15 @@ impl, - (u32, u32), - ) = unsafe { &*backend.cursor.as_ptr() }; + let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) = + unsafe { &*backend.cursor.as_ptr() }; if crtc::set_cursor2( &*backend.dev.borrow(), *crtc, cursor, ((*hotspot).0 as i32, (*hotspot).1 as i32), - ).is_err() + ) + .is_err() { if let Err(err) = crtc::set_cursor(&*backend.dev.borrow(), *crtc, cursor) { error!(self.logger, "Failed to reset cursor. Error: {}", err); diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index 96a98eb..62a7ea2 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -103,7 +103,8 @@ impl GbmSurfaceInternal { h as u32, GbmFormat::XRGB8888, BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, - ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; + ) + .chain_err(|| ErrorKind::SurfaceCreationFailed)?; // Clean up buffers if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) { @@ -185,7 +186,7 @@ impl<'a, D: RawDevice + 'static> CursorBackend<'a> for GbmSurfaceInternal where ::Surface: CursorBackend<'a>, <::Surface as CursorBackend<'a>>::CursorFormat: Buffer, - <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send + <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send { */ // @@ -195,7 +196,7 @@ impl<'a, D: RawDevice + 'static> GraphicsBackend<'a> for GbmSurfaceInternal where ::Surface: CursorBackend<'a>, <::Surface as CursorBackend<'a>>::CursorFormat=&'a Buffer, - <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send + <::Surface as CursorBackend<'a>>::Error: ::std::error::Error + Send { */ // But for now got to do this: @@ -231,7 +232,8 @@ impl<'a, A: AsRawFd + 'static> CursorBackend<'a> for GbmSurfaceInternal Device for LegacyDrmDevice { fn process_events(&mut self) { match crtc::receive_events(self) { - Ok(events) => for event in events { - if let crtc::Event::PageFlip(event) = event { - if self.active.load(Ordering::SeqCst) { - if self - .backends - .borrow() - .get(&event.crtc) - .iter() - .flat_map(|x| x.upgrade()) - .next() - .is_some() - { - trace!(self.logger, "Handling event for backend {:?}", event.crtc); - if let Some(handler) = self.handler.as_ref() { - handler.borrow_mut().vblank(event.crtc); + Ok(events) => { + for event in events { + if let crtc::Event::PageFlip(event) = event { + if self.active.load(Ordering::SeqCst) { + if self + .backends + .borrow() + .get(&event.crtc) + .iter() + .flat_map(|x| x.upgrade()) + .next() + .is_some() + { + trace!(self.logger, "Handling event for backend {:?}", event.crtc); + if let Some(handler) = self.handler.as_ref() { + handler.borrow_mut().vblank(event.crtc); + } + } else { + self.backends.borrow_mut().remove(&event.crtc); } - } else { - self.backends.borrow_mut().remove(&event.crtc); } } } - }, - Err(err) => if let Some(handler) = self.handler.as_ref() { - handler.borrow_mut().error( - ResultExt::<()>::chain_err(Err(err), || { - ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path())) - }).unwrap_err(), - ); - }, + } + Err(err) => { + if let Some(handler) = self.handler.as_ref() { + handler.borrow_mut().error( + ResultExt::<()>::chain_err(Err(err), || { + ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path())) + }) + .unwrap_err(), + ); + } + } } } diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index f05b618..3ea3b5b 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -102,7 +102,8 @@ impl Surface for LegacyDrmSurfaceInternal { encoder::Info::load_from_device(self, *encoder).chain_err(|| { ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) }) - }).collect::>>()?; + }) + .collect::>>()?; // and if any encoder supports the selected crtc let resource_handles = self.resource_handles().chain_err(|| { @@ -137,7 +138,8 @@ impl Surface for LegacyDrmSurfaceInternal { if !connector::Info::load_from_device(self, *connector) .chain_err(|| { ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) - })?.modes() + })? + .modes() .contains(&mode) { bail!(ErrorKind::ModeNotSuitable(mode)); @@ -201,7 +203,8 @@ impl RawSurface for LegacyDrmSurfaceInternal { .collect::>(), (0, 0), pending.mode, - ).chain_err(|| { + ) + .chain_err(|| { ErrorKind::DrmDev(format!( "Error setting crtc {:?} on {:?}", self.crtc, @@ -222,7 +225,8 @@ impl RawSurface for LegacyDrmSurfaceInternal { self.crtc, framebuffer, &[crtc::PageFlipFlags::PageFlipEvent], - ).map_err(|_| SwapBuffersError::ContextLost) + ) + .map_err(|_| SwapBuffersError::ContextLost) } } diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index 57d4f6d..c5d29bd 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -37,12 +37,7 @@ pub use self::context::EGLContext; pub mod error; use self::error::*; -#[allow( - non_camel_case_types, - dead_code, - unused_mut, - non_upper_case_globals -)] +#[allow(non_camel_case_types, dead_code, unused_mut, non_upper_case_globals)] pub mod ffi; use self::ffi::egl::types::EGLImage; diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index 95de7d3..d700b5a 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -24,10 +24,7 @@ use wayland_server::calloop::{ // No idea if this is the same across unix platforms // Lets make this linux exclusive for now, once someone tries to build it for // any BSD-like system, they can verify if this is right and make a PR to change this. -#[cfg(all( - any(target_os = "linux", target_os = "android"), - feature = "backend_session" -))] +#[cfg(all(any(target_os = "linux", target_os = "android"), feature = "backend_session"))] const INPUT_MAJOR: u32 = 13; /// Libinput based `InputBackend`. @@ -448,16 +445,18 @@ impl backend::InputBackend for LibinputInputBackend { libinput::Event::Keyboard(keyboard_event) => { use input::event::keyboard::*; match keyboard_event { - KeyboardEvent::Key(key_event) => if let Some(ref mut handler) = self.handler { - let device_seat = key_event.device().seat(); - if let Some(ref seat) = self.seats.get(&device_seat) { - trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event); - handler.on_keyboard_key(seat, key_event); - } else { - warn!(self.logger, "Received key event of non existing Seat"); - continue; + KeyboardEvent::Key(key_event) => { + if let Some(ref mut handler) = self.handler { + let device_seat = key_event.device().seat(); + if let Some(ref seat) = self.seats.get(&device_seat) { + trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event); + handler.on_keyboard_key(seat, key_event); + } else { + warn!(self.logger, "Received key event of non existing Seat"); + continue; + } } - }, + } } } libinput::Event::Pointer(pointer_event) => { diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 9930985..9450bc6 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -101,7 +101,8 @@ impl LogindSession { "org.freedesktop.login1.Manager", "GetSession", Some(vec![session_id.clone().into()]), - )?.get1::>() + )? + .get1::>() .chain_err(|| ErrorKind::UnexpectedMethodReturn)?; // Match all signals that we want to receive and handle @@ -342,7 +343,8 @@ impl Session for LogindSession { (major(stat.st_rdev) as u32).into(), (minor(stat.st_rdev) as u32).into(), ]), - )?.get2::(); + )? + .get2::(); let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); Ok(fd) } else { @@ -363,7 +365,8 @@ impl Session for LogindSession { (major(stat.st_rdev) as u32).into(), (minor(stat.st_rdev) as u32).into(), ]), - ).map(|_| ()) + ) + .map(|_| ()) } else { bail!(ErrorKind::SessionLost) } @@ -390,7 +393,8 @@ impl Session for LogindSession { "org.freedesktop.login1.Seat", "SwitchTo", Some(vec![(vt_num as u32).into()]), - ).map(|_| ()) + ) + .map(|_| ()) } else { bail!(ErrorKind::SessionLost) } diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index d879731..cdb60d6 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -185,8 +185,10 @@ impl DirectSession { path, fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC, Mode::empty(), - ).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(path.to_string_lossy()))) - }).unwrap_or_else(|| { + ) + .chain_err(|| ErrorKind::FailedToOpenTTY(String::from(path.to_string_lossy()))) + }) + .unwrap_or_else(|| { dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(""))) })?; @@ -429,7 +431,8 @@ pub fn direct_session_bind( .insert_source(source, { let notifier = notifier.clone(); move |_, _| notifier.borrow_mut().signal_received() - }).map_err(move |e| { + }) + .map_err(move |e| { // the backend in the closure should already have been dropped let notifier = Rc::try_unwrap(fail_notifier) .unwrap_or_else(|_| unreachable!()) diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 0bdc487..cc2f901 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -73,7 +73,8 @@ impl UdevBackend { warn!(log, "Unable to get id of {:?}, Error: {:?}. Skipping", path, err); None } - }).collect(); + }) + .collect(); let mut builder = MonitorBuilder::new(context)?; builder.match_subsystem("drm")?; @@ -217,6 +218,7 @@ pub fn all_gpus>(context: &Context, seat: S) -> UdevResult(&self.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Toplevel(ref state) => Some(state.clone()), _ => None, - }).ok() + }) + .ok() .and_then(|x| x) } } @@ -782,7 +783,8 @@ where .with_role_data::(&self.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Popup(ref state) => Some(state.clone()), _ => None, - }).ok() + }) + .ok() .and_then(|x| x) } } diff --git a/src/wayland/shell/xdg/xdg_handlers.rs b/src/wayland/shell/xdg/xdg_handlers.rs index d5dc724..dd722cb 100644 --- a/src/wayland/shell/xdg/xdg_handlers.rs +++ b/src/wayland/shell/xdg/xdg_handlers.rs @@ -217,7 +217,8 @@ where "xdg_surface was destroyed before its role object".into(), ); } - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); } fn xdg_surface_implementation( @@ -244,7 +245,8 @@ fn xdg_surface_implementation( min_size: (0, 0), max_size: (0, 0), }); - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); let toplevel = id.implement_nonsend( toplevel_implementation::, Some(destroy_toplevel::), @@ -286,7 +288,8 @@ fn xdg_surface_implementation( parent: parent_surface, positioner: positioner_data.borrow().clone(), }); - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); let popup = id.implement_nonsend( xg_popup_implementation::, Some(destroy_popup::), @@ -315,7 +318,8 @@ fn xdg_surface_implementation( .compositor_token .with_role_data::(&data.wl_surface, |data| { data.window_geometry = Some(Rectangle { x, y, width, height }); - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); } xdg_surface::Request::AckConfigure { serial } => { data.shell_data @@ -336,7 +340,8 @@ fn xdg_surface_implementation( ); } role_data.configured = true; - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); } } } @@ -369,7 +374,8 @@ fn with_surface_toplevel_data( .with_role_data::(&toplevel_data.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data), _ => unreachable!(), - }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }) + .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } pub fn send_toplevel_configure( @@ -539,7 +545,8 @@ where .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }) + .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) data.shell_data @@ -627,7 +634,8 @@ where .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }).expect("xdg_popup exists but surface has not shell_surface role?!"); + }) + .expect("xdg_popup exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) data.shell_data diff --git a/src/wayland/shell/xdg/zxdgv6_handlers.rs b/src/wayland/shell/xdg/zxdgv6_handlers.rs index 1621146..eb8cc17 100644 --- a/src/wayland/shell/xdg/zxdgv6_handlers.rs +++ b/src/wayland/shell/xdg/zxdgv6_handlers.rs @@ -236,7 +236,8 @@ where "xdg_surface was destroyed before its role object".into(), ); } - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); } fn xdg_surface_implementation( @@ -263,7 +264,8 @@ fn xdg_surface_implementation( min_size: (0, 0), max_size: (0, 0), }); - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); let toplevel = id.implement_nonsend( toplevel_implementation::, Some(destroy_toplevel::), @@ -302,7 +304,8 @@ fn xdg_surface_implementation( parent: Some(parent_data.wl_surface.clone()), positioner: positioner_data.borrow().clone(), }); - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); let popup = id.implement_nonsend( popup_implementation::, Some(destroy_popup::), @@ -331,7 +334,8 @@ fn xdg_surface_implementation( .compositor_token .with_role_data::(&data.wl_surface, |data| { data.window_geometry = Some(Rectangle { x, y, width, height }); - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); } zxdg_surface_v6::Request::AckConfigure { serial } => { data.shell_data @@ -352,7 +356,8 @@ fn xdg_surface_implementation( ); } role_data.configured = true; - }).expect("xdg_surface exists but surface has not shell_surface role?!"); + }) + .expect("xdg_surface exists but surface has not shell_surface role?!"); } } } @@ -382,7 +387,8 @@ where .with_role_data::(&data.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data), _ => unreachable!(), - }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }) + .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } pub fn send_toplevel_configure( @@ -553,7 +559,8 @@ where .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }) + .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) data.shell_data @@ -644,7 +651,8 @@ where .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }).expect("xdg_popup exists but surface has not shell_surface role?!"); + }) + .expect("xdg_popup exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) data.shell_data diff --git a/src/xwayland/xserver.rs b/src/xwayland/xserver.rs index 868129c..32eb4c2 100644 --- a/src/xwayland/xserver.rs +++ b/src/xwayland/xserver.rs @@ -97,7 +97,8 @@ impl XWayland { debug_assert!(evt.signal() == Signal::SIGUSR1); xwayland_ready(&inner); }, - ).map_err(|_| ()) + ) + .map_err(|_| ()) }), wayland_display: display, instance: None,