diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index e17ead8..2a19e56 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -52,11 +52,10 @@ type BackendRef = Weak::Surface>>; /// Representation of an egl device to create egl rendering surfaces pub struct EglDevice where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { dev: EGLDisplay, logger: ::slog::Logger, @@ -67,11 +66,10 @@ where impl AsRawFd for EglDevice where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { fn as_raw_fd(&self) -> RawFd { self.dev.borrow().as_raw_fd() @@ -80,11 +78,10 @@ where impl EglDevice where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { /// Try to create a new [`EglDevice`] from an open device. /// @@ -138,22 +135,20 @@ where struct InternalDeviceHandler where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { handler: Box> + 'static>, } impl DeviceHandler for InternalDeviceHandler where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { type Device = D; @@ -167,11 +162,10 @@ where impl Device for EglDevice where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { type Surface = EglSurface<::Surface>; @@ -250,11 +244,10 @@ where #[cfg(feature = "use_system_lib")] impl EGLGraphicsBackend for EglDevice where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { fn bind_wl_display(&self, display: &Display) -> Result { self.dev.bind_wl_display(display) @@ -263,11 +256,10 @@ where impl Drop for EglDevice where - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay::Surface as Surface>::Error> + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + NativeDisplay + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { fn drop(&mut self) { self.clear_handler(); diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index 6a6f2e0..9a6c774 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -28,15 +28,13 @@ pub struct EglDeviceObserver AsSessionObserver::Surface>> for EglDevice where S: SessionObserver + 'static, - B: Backend::Surface> + 'static, - D: Device - + NativeDisplay< - B, - Arguments = (crtc::Handle, Mode, Vec), - Error = <::Surface as Surface>::Error, - > + AsSessionObserver + B: Backend::Surface, Error = <::Surface as Surface>::Error> + 'static, - ::Surface: NativeSurface, + D: Device + + NativeDisplay)> + + AsSessionObserver + + 'static, + ::Surface: NativeSurface::Surface as Surface>::Error>, { fn observer(&mut self) -> EglDeviceObserver::Surface> { EglDeviceObserver { diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 2f6d908..62d557a 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -7,7 +7,7 @@ use crate::backend::drm::{Device, RawDevice, Surface}; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::{display::EGLDisplayHandle, ffi}; -use crate::backend::egl::{wrap_egl_call, EGLError, Error as EglBackendError}; +use crate::backend::egl::{wrap_egl_call, EGLError, Error as EglBackendError, SurfaceCreationError}; use super::{Error, GbmDevice, GbmSurface}; @@ -15,7 +15,6 @@ use drm::control::{connector, crtc, Device as ControlDevice, Mode}; use gbm::AsRaw; use nix::libc::{c_int, c_void}; use std::marker::PhantomData; -use std::ptr; /// Egl Gbm backend type /// @@ -26,6 +25,7 @@ pub struct Gbm { impl Backend for Gbm { type Surface = GbmSurface; + type Error = Error<<::Surface as Surface>::Error>; unsafe fn get_display( display: ffi::NativeDisplayType, @@ -66,7 +66,6 @@ impl Backend for Gbm { unsafe impl NativeDisplay> for GbmDevice { type Arguments = (crtc::Handle, Mode, Vec); - type Error = Error<<::Surface as Surface>::Error>; fn is_backend(&self) -> bool { true @@ -76,34 +75,40 @@ unsafe impl NativeDisplay> for Gb Ok(self.dev.borrow().as_raw() as *const _) } - fn create_surface(&mut self, args: Self::Arguments) -> Result, Self::Error> { + fn create_surface( + &mut self, + args: Self::Arguments, + ) -> Result, Error<<::Surface as Surface>::Error>> { Device::create_surface(self, args.0, args.1, &args.2) } } unsafe impl NativeSurface for GbmSurface { + type Error = Error<<::Surface as Surface>::Error>; + unsafe fn create( &self, display: &EGLDisplayHandle, config_id: ffi::egl::types::EGLConfig, surface_attributes: &[c_int], - ) -> *const c_void { - ffi::egl::CreateWindowSurface( - display.handle, - config_id, - self.0.surface.borrow().as_raw() as *const _, - surface_attributes.as_ptr(), - ) + ) -> Result<*const c_void, SurfaceCreationError> { + GbmSurface::recreate(self).map_err(SurfaceCreationError::NativeSurfaceCreationFailed)?; + + wrap_egl_call(|| { + ffi::egl::CreateWindowSurface( + display.handle, + config_id, + self.0.surface.borrow().as_raw() as *const _, + surface_attributes.as_ptr(), + ) + }) + .map_err(SurfaceCreationError::EGLSurfaceCreationFailed) } fn needs_recreation(&self) -> bool { self.needs_recreation() } - fn recreate(&self) -> Result<(), Self::Error> { - GbmSurface::recreate(self) - } - fn swap_buffers(&self) -> Result<(), Self::Error> { // 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. diff --git a/src/backend/egl/display.rs b/src/backend/egl/display.rs index 9ac488d..2490796 100644 --- a/src/backend/egl/display.rs +++ b/src/backend/egl/display.rs @@ -379,7 +379,7 @@ impl> EGLDisplay { double_buffer: Option, config: ffi::egl::types::EGLConfig, args: N::Arguments, - ) -> Result, SurfaceCreationError> { + ) -> Result, SurfaceCreationError> { trace!(self.logger, "Creating EGL window surface."); let surface = self .native @@ -399,7 +399,6 @@ impl> EGLDisplay { debug!(self.logger, "EGL surface successfully created"); x }) - .map_err(SurfaceCreationError::EGLSurfaceCreationFailed) } /// Returns the runtime egl version of this display diff --git a/src/backend/egl/native.rs b/src/backend/egl/native.rs index 201f8ea..6e084fb 100644 --- a/src/backend/egl/native.rs +++ b/src/backend/egl/native.rs @@ -13,7 +13,9 @@ use winit::window::Window as WinitWindow; /// Trait for typed backend variants (X11/Wayland/GBM) pub trait Backend { /// Surface type created by this backend - type Surface: NativeSurface; + type Surface: NativeSurface; + /// Error type thrown by the surface creation in case of failure. + type Error: ::std::error::Error + Send + 'static; /// Return an [`EGLDisplay`](ffi::egl::types::EGLDisplay) based on this backend /// @@ -35,6 +37,7 @@ pub enum Wayland {} #[cfg(feature = "backend_winit")] impl Backend for Wayland { type Surface = wegl::WlEglSurface; + type Error = Error; unsafe fn get_display( display: ffi::NativeDisplayType, @@ -81,6 +84,7 @@ pub enum X11 {} #[cfg(feature = "backend_winit")] impl Backend for X11 { type Surface = XlibWindow; + type Error = Error; unsafe fn get_display( display: ffi::NativeDisplayType, @@ -121,8 +125,6 @@ impl Backend for X11 { pub unsafe trait NativeDisplay { /// Arguments used to surface creation. type Arguments; - /// Error type thrown by the surface creation in case of failure. - type Error: ::std::error::Error + Send + 'static; /// Because one type might implement multiple [`Backend`]s this function must be called to check /// if the expected [`Backend`] is used at runtime. fn is_backend(&self) -> bool; @@ -139,13 +141,12 @@ pub unsafe trait NativeDisplay { ffi::egl::WINDOW_BIT as ffi::EGLint } /// Create a surface - fn create_surface(&mut self, args: Self::Arguments) -> Result; + fn create_surface(&mut self, args: Self::Arguments) -> Result; } #[cfg(feature = "backend_winit")] unsafe impl NativeDisplay for WinitWindow { type Arguments = (); - type Error = Error; fn is_backend(&self) -> bool { self.xlib_display().is_some() @@ -167,7 +168,6 @@ unsafe impl NativeDisplay for WinitWindow { #[cfg(feature = "backend_winit")] unsafe impl NativeDisplay for WinitWindow { type Arguments = (); - type Error = Error; fn is_backend(&self) -> bool { self.wayland_display().is_some() @@ -198,10 +198,15 @@ unsafe impl NativeDisplay for WinitWindow { /// The returned [`NativeWindowType`](ffi::NativeWindowType) must be valid for EGL /// and there is no way to test that. pub unsafe trait NativeSurface { - /// Error of the underlying surface - type Error: std::error::Error; - - /// Create an EGLSurface from the internal native type + /// Error type thrown by the surface creation in case of failure. + type Error: ::std::error::Error + Send + 'static; + /// Create an EGLSurface from the internal native type. + /// + /// Must be able to deal with re-creation of existing resources, + /// if `needs_recreation` can return `true`. + /// + /// # Safety + /// This is usually an unsafe operation returning a raw pointer. unsafe fn create( &self, display: &EGLDisplayHandle, @@ -210,24 +215,15 @@ pub unsafe trait NativeSurface { ) -> Result<*const c_void, SurfaceCreationError>; /// Will be called to check if any internal resources will need - /// to be recreated. Old resources must be used until `recreate` - /// was called. + /// to be recreated. Old resources must be used until `create` + /// was called again and a new surface was optained. /// - /// Only needs to be recreated, if this shall sometimes return true. + /// Only needs to be recreated, if this may 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) -> Result<(), Self::Error> { - Ok(()) - } - /// Adds additional semantics when calling /// [EGLSurface::swap_buffers](::backend::egl::surface::EGLSurface::swap_buffers) /// @@ -237,28 +233,16 @@ pub unsafe trait NativeSurface { } } -/// Hack until ! gets stablized -#[derive(Debug)] -pub enum Never {} -impl std::fmt::Display for Never { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - unreachable!() - } -} -impl std::error::Error for Never {} - #[cfg(feature = "backend_winit")] unsafe impl NativeSurface for XlibWindow { - // this would really be a case for this: - // type Error = !; (https://github.com/rust-lang/rust/issues/35121) - type Error = Never; + type Error = Error; unsafe fn create( &self, display: &EGLDisplayHandle, config_id: ffi::egl::types::EGLConfig, surface_attributes: &[c_int], - ) -> Result<*const c_void, SurfaceCreationError> { + ) -> Result<*const c_void, SurfaceCreationError> { wrap_egl_call(|| { ffi::egl::CreateWindowSurface( display.handle, @@ -273,15 +257,14 @@ unsafe impl NativeSurface for XlibWindow { #[cfg(feature = "backend_winit")] unsafe impl NativeSurface for wegl::WlEglSurface { - // type Error = !; - type Error = Never; + type Error = Error; unsafe fn create( &self, display: &EGLDisplayHandle, config_id: ffi::egl::types::EGLConfig, surface_attributes: &[c_int], - ) -> Result<*const c_void, SurfaceCreationError> { + ) -> Result<*const c_void, SurfaceCreationError> { wrap_egl_call(|| { ffi::egl::CreateWindowSurface( display.handle, diff --git a/src/backend/egl/surface.rs b/src/backend/egl/surface.rs index 0a36f8f..02ea2de 100644 --- a/src/backend/egl/surface.rs +++ b/src/backend/egl/surface.rs @@ -1,6 +1,6 @@ //! EGL surface related structs -use super::{ffi, native, wrap_egl_call, EGLError, SwapBuffersError}; +use super::{ffi, native, wrap_egl_call, EGLError, SurfaceCreationError, SwapBuffersError}; use crate::backend::egl::display::EGLDisplayHandle; use crate::backend::graphics::PixelFormat; use nix::libc::c_int; @@ -42,7 +42,7 @@ impl EGLSurface { config: ffi::egl::types::EGLConfig, native: N, log: L, - ) -> Result, EGLError> + ) -> Result, SurfaceCreationError> where L: Into>, { @@ -72,7 +72,9 @@ impl EGLSurface { let surface = unsafe { native.create(&*display, config, &surface_attributes)? }; if surface == ffi::egl::NO_SURFACE { - return Err(EGLError::BadSurface); + return Err(SurfaceCreationError::EGLSurfaceCreationFailed( + EGLError::BadSurface, + )); } Ok(EGLSurface { @@ -106,16 +108,20 @@ impl EGLSurface { }; if self.native.needs_recreation() || surface.is_null() || is_bad_surface { - self.native.recreate().map_err(SwapBuffersError::Underlying)?; if !surface.is_null() { let _ = unsafe { ffi::egl::DestroySurface(**self.display, surface as *const _) }; } - //TODO remove recreate - self.native.recreate(); self.surface.set(unsafe { self.native .create(&*self.display, self.config_id, &self.surface_attributes) - .map_err(SwapBuffersError::EGLCreateWindowSurface)? + .map_err(|err| match err { + SurfaceCreationError::EGLSurfaceCreationFailed(err) => { + SwapBuffersError::EGLCreateWindowSurface(err) + } + SurfaceCreationError::NativeSurfaceCreationFailed(err) => { + SwapBuffersError::Underlying(err) + } + })? }); result.map_err(|err| {