From d99108a8e6aa4459f52f74f13f389a590cb12175 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 7 Apr 2021 00:31:30 +0200 Subject: [PATCH] Simplify egl platform code - Remove EGLStream code, nvidia support will re-introduced, when 470 hopefully lands with GBM support this summer. - Greately simplify the native code by setting exclusively on `EGL_EXT_platform_base` and its extensions for initialization. - Remove generic parameters for the underlying objects on `EGLDisplay` and `EGLSurface` by using trait objects instead. - Allow creation of `EGLContext`s without a config for surface-less usage. --- src/backend/egl/context.rs | 154 ++++++++++++---------- src/backend/egl/display.rs | 263 ++++++++++++++++++++----------------- src/backend/egl/ffi.rs | 62 --------- src/backend/egl/mod.rs | 69 +++------- src/backend/egl/native.rs | 261 ++++++++++-------------------------- src/backend/egl/surface.rs | 84 ++++++------ 6 files changed, 347 insertions(+), 546 deletions(-) diff --git a/src/backend/egl/context.rs b/src/backend/egl/context.rs index f62e14a..116c5b8 100644 --- a/src/backend/egl/context.rs +++ b/src/backend/egl/context.rs @@ -1,96 +1,106 @@ //! EGL context related structs - -use super::{ffi, wrap_egl_call, Error, MakeCurrentError}; -use crate::backend::egl::display::{EGLDisplay, EGLDisplayHandle}; -use crate::backend::egl::native::NativeSurface; -use crate::backend::egl::{native, EGLSurface}; -use crate::backend::graphics::PixelFormat; use std::os::raw::c_int; use std::ptr; -use std::sync::{atomic::Ordering, Arc}; +use std::sync::atomic::Ordering; + +use super::{ffi, wrap_egl_call, Error, MakeCurrentError}; +use crate::backend::egl::display::{EGLDisplay, PixelFormat}; +use crate::backend::egl::native::EGLNativeSurface; +use crate::backend::egl::EGLSurface; + /// EGL context for rendering #[derive(Debug)] pub struct EGLContext { context: ffi::egl::types::EGLContext, - display: Arc, + pub(crate) display: EGLDisplay, config_id: ffi::egl::types::EGLConfig, - pixel_format: PixelFormat, + pixel_format: Option, } // EGLContexts can be moved between threads safely unsafe impl Send for EGLContext {} unsafe impl Sync for EGLContext {} impl EGLContext { + pub fn new( + display: &EGLDisplay, + log: L, + ) -> Result + where + L: Into>, + { + Self::new_internal(display, None, log) + } + /// Create a new [`EGLContext`] from a given [`NativeDisplay`](native::NativeDisplay) - pub(crate) fn new( - display: &EGLDisplay, - mut attributes: GlAttributes, + pub fn new_with_config( + display: &EGLDisplay, + attributes: GlAttributes, reqs: PixelFormatRequirements, log: L, ) -> Result where L: Into>, - B: native::Backend, - N: native::NativeDisplay, { - let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "renderer_egl")); + Self::new_internal(display, Some((attributes, reqs)), log) + } - // If no version is given, try OpenGLES 3.0, if available, - // fallback to 2.0 otherwise - let version = match attributes.version { - Some((3, x)) => (3, x), - Some((2, x)) => (2, x), + fn new_internal( + display: &EGLDisplay, + config: Option<(GlAttributes, PixelFormatRequirements)>, + log: L, + ) -> Result + where + L: Into>, + { + let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "backend_egl")); + + let (pixel_format, config_id) = match config { + Some((attributes, reqs)) => { + let (format, config_id) = display.choose_config(attributes, reqs)?; + (Some(format), config_id) + }, None => { - debug!(log, "Trying to initialize EGL with OpenGLES 3.0"); - attributes.version = Some((3, 0)); - match EGLContext::new(display, attributes, reqs, log.clone()) { - Ok(x) => return Ok(x), - Err(err) => { - warn!(log, "EGL OpenGLES 3.0 Initialization failed with {}", err); - debug!(log, "Trying to initialize EGL with OpenGLES 2.0"); - attributes.version = Some((2, 0)); - return EGLContext::new(display, attributes, reqs, log.clone()); - } + if !display.extensions.iter().any(|x| x == "EGL_KHR_no_config_context") && + !display.extensions.iter().any(|x| x == "EGL_MESA_configless_context") && + !display.extensions.iter().any(|x| x == "EGL_KHR_surfaceless_context") + { + return Err(Error::EglExtensionNotSupported(&["EGL_KHR_no_config_context", "EGL_MESA_configless_context", "EGL_KHR_surfaceless_context"])); } - } - Some((1, x)) => { - error!(log, "OpenGLES 1.* is not supported by the EGL renderer backend"); - return Err(Error::OpenGlVersionNotSupported((1, x))); - } - Some(version) => { - error!( - log, - "OpenGLES {:?} is unknown and not supported by the EGL renderer backend", version - ); - return Err(Error::OpenGlVersionNotSupported(version)); + (None, ffi::egl::NO_CONFIG_KHR) } }; - let (pixel_format, config_id) = display.choose_config(attributes, reqs)?; - let mut context_attributes = Vec::with_capacity(10); - if display.egl_version >= (1, 5) || display.extensions.iter().any(|s| s == "EGL_KHR_create_context") { - trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0); - context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32); - context_attributes.push(version.0 as i32); - trace!(log, "Setting CONTEXT_MINOR_VERSION to {}", version.1); - context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32); - context_attributes.push(version.1 as i32); + if let Some((attributes, _)) = config { + let version = attributes.version; - if attributes.debug && display.egl_version >= (1, 5) { - trace!(log, "Setting CONTEXT_OPENGL_DEBUG to TRUE"); - context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32); - context_attributes.push(ffi::egl::TRUE as i32); + if display.egl_version >= (1, 5) || display.extensions.iter().any(|s| s == "EGL_KHR_create_context") { + trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0); + context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32); + context_attributes.push(version.0 as i32); + trace!(log, "Setting CONTEXT_MINOR_VERSION to {}", version.1); + context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32); + context_attributes.push(version.1 as i32); + + if attributes.debug && display.egl_version >= (1, 5) { + trace!(log, "Setting CONTEXT_OPENGL_DEBUG to TRUE"); + context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32); + context_attributes.push(ffi::egl::TRUE as i32); + } + + context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32); + context_attributes.push(0); + } else if display.egl_version >= (1, 3) { + trace!(log, "Setting CONTEXT_CLIENT_VERSION to {}", version.0); + context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32); + context_attributes.push(version.0 as i32); } - - context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32); - context_attributes.push(0); - } else if display.egl_version >= (1, 3) { - trace!(log, "Setting CONTEXT_CLIENT_VERSION to {}", version.0); + } else { + trace!(log, "Setting CONTEXT_CLIENT_VERSION to 2"); context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32); - context_attributes.push(version.0 as i32); + context_attributes.push(2); } context_attributes.push(ffi::egl::NONE as i32); @@ -111,7 +121,7 @@ impl EGLContext { Ok(EGLContext { context, - display: display.display.clone(), + display: display.clone(), config_id, pixel_format, }) @@ -124,12 +134,10 @@ impl EGLContext { /// /// This function is marked unsafe, because the context cannot be made current /// on multiple threads. - pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> - where - N: NativeSurface, + pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> { let surface_ptr = surface.surface.load(Ordering::SeqCst); - wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display, surface_ptr, surface_ptr, self.context)) + wrap_egl_call(|| ffi::egl::MakeCurrent(**self.display.display, surface_ptr, surface_ptr, self.context)) .map(|_| ()) .map_err(Into::into) } @@ -143,7 +151,7 @@ impl EGLContext { pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> { wrap_egl_call(|| { ffi::egl::MakeCurrent( - **self.display, + **self.display.display, ffi::egl::NO_SURFACE, ffi::egl::NO_SURFACE, self.context, @@ -159,12 +167,12 @@ impl EGLContext { } /// Returns the egl config for this context - pub fn get_config_id(&self) -> ffi::egl::types::EGLConfig { + pub fn config_id(&self) -> ffi::egl::types::EGLConfig { self.config_id } /// Returns the pixel format of the main framebuffer of the context. - pub fn get_pixel_format(&self) -> PixelFormat { + pub fn pixel_format(&self) -> Option { self.pixel_format } @@ -175,7 +183,7 @@ impl EGLContext { if self.is_current() { wrap_egl_call(|| unsafe { ffi::egl::MakeCurrent( - **self.display, + **self.display.display, ffi::egl::NO_SURFACE, ffi::egl::NO_SURFACE, ffi::egl::NO_CONTEXT, @@ -192,7 +200,7 @@ impl Drop for EGLContext { // We need to ensure the context is unbound, otherwise it egl stalls the destroy call // ignore failures at this point let _ = self.unbind(); - ffi::egl::DestroyContext(**self.display, self.context); + ffi::egl::DestroyContext(**self.display.display, self.context); } } } @@ -202,9 +210,9 @@ impl Drop for EGLContext { pub struct GlAttributes { /// Describes the OpenGL API and version that are being requested when a context is created. /// - /// `Some(3, 0)` will request a OpenGL ES 3.0 context for example. - /// `None` means "don't care" (minimum will be 2.0). - pub version: Option<(u8, u8)>, + /// `(3, 0)` will request a OpenGL ES 3.0 context for example. + /// `(2, 0)` is the minimum. + pub version: (u8, u8), /// OpenGL profile to use pub profile: Option, /// Whether to enable the debug flag of the context. diff --git a/src/backend/egl/display.rs b/src/backend/egl/display.rs index fc26adf..f8482c8 100644 --- a/src/backend/egl/display.rs +++ b/src/backend/egl/display.rs @@ -1,31 +1,24 @@ //! Type safe native types for safe egl initialisation -#[cfg(feature = "use_system_lib")] -use crate::backend::egl::EGLGraphicsBackend; -use crate::backend::egl::{ - ffi, get_proc_address, native, wrap_egl_call, BufferAccessError, EGLContext, EGLError, EGLImages, - EGLSurface, Error, Format, SurfaceCreationError, -}; use std::sync::Arc; +use std::ffi::CStr; +use std::mem::MaybeUninit; +use std::ops::Deref; use nix::libc::c_int; - -#[cfg(feature = "wayland_frontend")] +#[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))] use wayland_server::{protocol::wl_buffer::WlBuffer, Display}; #[cfg(feature = "use_system_lib")] use wayland_sys::server::wl_display; -use crate::backend::egl::context::{GlAttributes, PixelFormatRequirements}; -#[cfg(feature = "renderer_gl")] -use crate::backend::graphics::gl::ffi as gl_ffi; -use crate::backend::graphics::PixelFormat; -use std::cell::{Ref, RefCell, RefMut}; -use std::ffi::CStr; -use std::marker::PhantomData; -use std::mem::MaybeUninit; - -use std::fmt; -use std::ops::Deref; +use crate::backend::allocator::{Buffer, dmabuf::Dmabuf}; +use crate::backend::egl::{ + ffi::egl::types::EGLImage, + ffi, wrap_egl_call, EGLError, Error, + context::{GlAttributes, PixelFormatRequirements}, + native::{EGLNativeDisplay}, + BufferAccessError, EGLImages, Format, +}; /// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed /// once all resources bound to it have been dropped. @@ -56,55 +49,54 @@ impl Drop for EGLDisplayHandle { } /// [`EGLDisplay`] represents an initialised EGL environment -#[derive(Debug)] -pub struct EGLDisplay> { - native: RefCell, +#[derive(Clone)] +pub struct EGLDisplay { pub(crate) display: Arc, pub(crate) egl_version: (i32, i32), pub(crate) extensions: Vec, + surface_type: ffi::EGLint, logger: slog::Logger, - _backend: PhantomData, } -impl> EGLDisplay { +impl EGLDisplay { /// Create a new [`EGLDisplay`] from a given [`NativeDisplay`](native::NativeDisplay) - pub fn new(native: N, logger: L) -> Result, Error> + pub fn new(native: &N, logger: L) -> Result where + N: EGLNativeDisplay + 'static, L: Into>, { - let log = crate::slog_or_fallback(logger.into()).new(o!("smithay_module" => "renderer_egl")); - let ptr = native.ptr()?; - let egl_attribs = native.attributes(); - + let log = crate::slog_or_fallback(logger.into()).new(o!("smithay_module" => "backend_egl")); ffi::make_sure_egl_is_loaded(); // the first step is to query the list of extensions without any display, if supported let dp_extensions = unsafe { let p = wrap_egl_call(|| ffi::egl::QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32)) - .map_err(Error::InitFailed)?; + .map_err(Error::InitFailed)?; //TODO EGL_EXT_client_extensions not supported // this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise // `eglQueryString` returns an error if p.is_null() { - vec![] + return Err(Error::EglExtensionNotSupported(&["EGL_EXT_platform_base"])); } else { let p = CStr::from_ptr(p); let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new()); list.split(' ').map(|e| e.to_string()).collect::>() } }; - debug!(log, "EGL No-Display Extensions: {:?}", dp_extensions); + debug!(log, "Supported EGL client extensions: {:?}", dp_extensions); + for ext in native.required_extensions() { + if !dp_extensions.iter().any(|x| x == ext) { + return Err(Error::EglExtensionNotSupported(native.required_extensions())); + } + } + + let (platform, native_ptr, attributes) = native.platform_display(); // we create an EGLDisplay let display = unsafe { - B::get_display( - ptr, - &egl_attribs, - |e: &str| dp_extensions.iter().any(|s| s == e), - log.clone(), - ) - .map_err(Error::DisplayCreationError)? + wrap_egl_call(|| ffi::egl::GetPlatformDisplayEXT(platform, native_ptr, attributes.as_ptr())) + .map_err(Error::DisplayCreationError)? }; if display == ffi::egl::NO_DISPLAY { return Err(Error::DisplayNotSupported); @@ -143,7 +135,7 @@ impl> EGLDisplay { } else { vec![] }; - info!(log, "EGL Extensions: {:?}", extensions); + info!(log, "Supported EGL display extensions: {:?}", extensions); // egl <= 1.2 does not support OpenGL ES (maybe we want to support OpenGL in the future?) if egl_version <= (1, 2) { @@ -153,12 +145,11 @@ impl> EGLDisplay { .map_err(|source| Error::OpenGlesNotSupported(Some(source)))?; Ok(EGLDisplay { - native: RefCell::new(native), display: Arc::new(EGLDisplayHandle { handle: display }), + surface_type: native.surface_type(), egl_version, extensions, logger: log, - _backend: PhantomData, }) } @@ -170,7 +161,6 @@ impl> EGLDisplay { ) -> Result<(PixelFormat, ffi::egl::types::EGLConfig), Error> { let descriptor = { let mut out: Vec = Vec::with_capacity(37); - let surface_type = self.native.borrow().surface_type(); if self.egl_version >= (1, 2) { trace!(self.logger, "Setting COLOR_BUFFER_TYPE to RGB_BUFFER"); @@ -178,15 +168,13 @@ impl> EGLDisplay { out.push(ffi::egl::RGB_BUFFER as c_int); } - trace!(self.logger, "Setting SURFACE_TYPE to {}", surface_type); + trace!(self.logger, "Setting SURFACE_TYPE to {}", self.surface_type); out.push(ffi::egl::SURFACE_TYPE as c_int); - // TODO: Some versions of Mesa report a BAD_ATTRIBUTE error - // if we ask for PBUFFER_BIT as well as WINDOW_BIT - out.push(surface_type); + out.push(self.surface_type); match attributes.version { - Some((3, _)) => { + (3, _) => { if self.egl_version < (1, 3) { error!( self.logger, @@ -201,7 +189,7 @@ impl> EGLDisplay { out.push(ffi::egl::CONFORMANT as c_int); out.push(ffi::egl::OPENGL_ES3_BIT as c_int); } - Some((2, _)) => { + (2, _) => { if self.egl_version < (1, 3) { error!( self.logger, @@ -216,12 +204,9 @@ impl> EGLDisplay { out.push(ffi::egl::CONFORMANT as c_int); out.push(ffi::egl::OPENGL_ES2_BIT as c_int); } - Some(ver) => { + ver => { return Err(Error::OpenGlVersionNotSupported(ver)); } - None => { - return Err(Error::OpenGlVersionNotSupported((0, 0))); - } }; reqs.create_attributes(&mut out, &self.logger) @@ -352,44 +337,6 @@ impl> EGLDisplay { Ok((desc, config_id)) } - /// Create a new [`EGLContext`](::backend::egl::EGLContext) - pub fn create_context( - &self, - attributes: GlAttributes, - reqs: PixelFormatRequirements, - ) -> Result { - EGLContext::new(&self, attributes, reqs, self.logger.clone()) - } - - /// Creates a surface for rendering - pub fn create_surface( - &self, - pixel_format: PixelFormat, - double_buffer: Option, - config: ffi::egl::types::EGLConfig, - args: N::Arguments, - ) -> Result, SurfaceCreationError> { - trace!(self.logger, "Creating EGL window surface."); - let surface = self - .native - .borrow_mut() - .create_surface(args) - .map_err(SurfaceCreationError::NativeSurfaceCreationFailed)?; - - EGLSurface::new( - self.display.clone(), - pixel_format, - double_buffer, - config, - surface, - self.logger.clone(), - ) - .map(|x| { - debug!(self.logger, "EGL surface successfully created"); - x - }) - } - /// Returns the runtime egl version of this display pub fn get_egl_version(&self) -> (i32, i32) { self.egl_version @@ -400,28 +347,90 @@ impl> EGLDisplay { self.extensions.clone() } - /// Borrow the underlying native display. - /// - /// This follows the same semantics as [`std::cell:RefCell`](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<'_, N> { - self.native.borrow() + /// Imports a dmabuf as an eglimage + pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result { + if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base") && + !self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import") + { + return Err(Error::EglExtensionNotSupported(&["EGL_KHR_image_base", "EGL_EXT_image_dma_buf_import"])); + } + + if dmabuf.has_modifier() { + if !self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") { + return Err(Error::EglExtensionNotSupported(&["EGL_EXT_image_dma_buf_import_modifiers"])); + } + }; + + let mut out: Vec = Vec::with_capacity(50); + + out.extend(&[ + ffi::egl::WIDTH as i32, dmabuf.width() as i32, + ffi::egl::HEIGHT as i32, dmabuf.height() as i32, + ffi::egl::LINUX_DRM_FOURCC_EXT as i32, dmabuf.format().code as u32 as i32, + ]); + + let names = [ + [ + ffi::egl::DMA_BUF_PLANE0_FD_EXT, + ffi::egl::DMA_BUF_PLANE0_OFFSET_EXT, + ffi::egl::DMA_BUF_PLANE0_PITCH_EXT, + ffi::egl::DMA_BUF_PLANE0_MODIFIER_LO_EXT, + ffi::egl::DMA_BUF_PLANE0_MODIFIER_HI_EXT + ], [ + ffi::egl::DMA_BUF_PLANE1_FD_EXT, + ffi::egl::DMA_BUF_PLANE1_OFFSET_EXT, + ffi::egl::DMA_BUF_PLANE1_PITCH_EXT, + ffi::egl::DMA_BUF_PLANE1_MODIFIER_LO_EXT, + ffi::egl::DMA_BUF_PLANE1_MODIFIER_HI_EXT + ], [ + ffi::egl::DMA_BUF_PLANE2_FD_EXT, + ffi::egl::DMA_BUF_PLANE2_OFFSET_EXT, + ffi::egl::DMA_BUF_PLANE2_PITCH_EXT, + ffi::egl::DMA_BUF_PLANE2_MODIFIER_LO_EXT, + ffi::egl::DMA_BUF_PLANE2_MODIFIER_HI_EXT + ], [ + ffi::egl::DMA_BUF_PLANE3_FD_EXT, + ffi::egl::DMA_BUF_PLANE3_OFFSET_EXT, + ffi::egl::DMA_BUF_PLANE3_PITCH_EXT, + ffi::egl::DMA_BUF_PLANE3_MODIFIER_LO_EXT, + ffi::egl::DMA_BUF_PLANE3_MODIFIER_HI_EXT + ] + ]; + + for (i, ((fd, offset), stride)) in dmabuf.handles().iter().zip(dmabuf.offsets()).zip(dmabuf.strides()).enumerate() { + out.extend(&[ + names[i][0] as i32, *fd, + names[i][1] as i32, *offset as i32, + names[i][2] as i32, *stride as i32, + ]); + if dmabuf.has_modifier() { + out.extend(&[ + names[i][3] as i32, (Into::::into(dmabuf.format().modifier) & 0xFFFFFFFF) as i32, + names[i][4] as i32, (Into::::into(dmabuf.format().modifier) >> 32) as i32, + ]) + } + } + + out.push(ffi::egl::NONE as i32); + + unsafe { + let image = ffi::egl::CreateImageKHR( + **self.display, + ffi::egl::NO_CONTEXT, + ffi::egl::LINUX_DMA_BUF_EXT, + std::ptr::null(), + out.as_ptr(), + ); + + if image == ffi::egl::NO_IMAGE_KHR { + Err(Error::EGLImageCreationFailed) + } else { + // TODO check for external + Ok(image) + } + } } - /// Borrow the underlying native display mutably. - /// - /// This follows the same semantics as [`std::cell:RefCell`](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<'_, N> { - self.native.borrow_mut() - } -} - -#[cfg(feature = "use_system_lib")] -impl> EGLGraphicsBackend for EGLDisplay { /// Binds this EGL display to the given Wayland display. /// /// This will allow clients to utilize EGL to create hardware-accelerated @@ -434,7 +443,8 @@ impl> EGLGraphicsBackend for EGL /// /// This might return [`OtherEGLDisplayAlreadyBound`](ErrorKind::OtherEGLDisplayAlreadyBound) /// if called for the same [`Display`] multiple times, as only one egl display may be bound at any given time. - fn bind_wl_display(&self, display: &Display) -> Result { + #[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))] + pub fn bind_wl_display(&self, display: &Display) -> Result { if !self.extensions.iter().any(|s| s == "EGL_WL_bind_wayland_display") { return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"])); } @@ -453,8 +463,6 @@ impl> EGLGraphicsBackend for EGL pub struct EGLBufferReader { display: Arc, wayland: *mut wl_display, - #[cfg(feature = "renderer_gl")] - gl: gl_ffi::Gles2, } // Gles2 does not implement debug, so we have to impl Debug manually @@ -471,14 +479,10 @@ impl fmt::Debug for EGLBufferReader { #[cfg(feature = "use_system_lib")] impl EGLBufferReader { fn new(display: Arc, wayland: *mut wl_display) -> Self { - #[cfg(feature = "renderer_gl")] - let gl = gl_ffi::Gles2::load_with(|s| get_proc_address(s) as *const _); Self { display, wayland, - #[cfg(feature = "renderer_gl")] - gl, } } @@ -576,8 +580,6 @@ impl EGLBufferReader { y_inverted: inverted != 0, format, images, - #[cfg(feature = "renderer_gl")] - gl: self.gl.clone(), }) } @@ -625,3 +627,24 @@ impl Drop for EGLBufferReader { } } } + +/// 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, + /// 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/egl/ffi.rs b/src/backend/egl/ffi.rs index 35e22e7..b6d0aa6 100644 --- a/src/backend/egl/ffi.rs +++ b/src/backend/egl/ffi.rs @@ -198,66 +198,4 @@ pub mod egl { // Accepted in the parameter of eglQueryWaylandBufferWL: pub const EGL_TEXTURE_FORMAT: i32 = 0x3080; pub const WAYLAND_Y_INVERTED_WL: i32 = 0x31DB; - - /// nVidia support needs some implemented but only proposed egl extensions... - /// Therefor gl_generator cannot generate them and we need some constants... - /// And a function... - #[cfg(feature = "backend_drm_eglstream")] - pub const CONSUMER_AUTO_ACQUIRE_EXT: i32 = 0x332B; - #[cfg(feature = "backend_drm_eglstream")] - pub const DRM_FLIP_EVENT_DATA_NV: i32 = 0x333E; - #[cfg(feature = "backend_drm_eglstream")] - pub const CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR: i32 = 0x321E; - #[cfg(feature = "backend_drm_eglstream")] - pub const RESOURCE_BUSY_EXT: u32 = 0x3353; - - #[cfg(feature = "backend_drm_eglstream")] - #[allow(non_snake_case, unused_variables, dead_code)] - #[inline] - pub unsafe fn StreamConsumerAcquireAttribNV( - dpy: types::EGLDisplay, - stream: types::EGLStreamKHR, - attrib_list: *const types::EGLAttrib, - ) -> types::EGLBoolean { - __gl_imports::mem::transmute::< - _, - extern "system" fn( - types::EGLDisplay, - types::EGLStreamKHR, - *const types::EGLAttrib, - ) -> types::EGLBoolean, - >(nvidia_storage::StreamConsumerAcquireAttribNV.f)(dpy, stream, attrib_list) - } - - #[cfg(feature = "backend_drm_eglstream")] - mod nvidia_storage { - use super::{FnPtr, __gl_imports::raw}; - pub static mut StreamConsumerAcquireAttribNV: FnPtr = FnPtr { - f: super::missing_fn_panic as *const raw::c_void, - is_loaded: false, - }; - } - - #[cfg(feature = "backend_drm_eglstream")] - #[allow(non_snake_case)] - pub mod StreamConsumerAcquireAttribNV { - use super::{FnPtr, __gl_imports::raw, metaloadfn, nvidia_storage}; - - #[inline] - #[allow(dead_code)] - pub fn is_loaded() -> bool { - unsafe { nvidia_storage::StreamConsumerAcquireAttribNV.is_loaded } - } - - #[allow(dead_code)] - pub fn load_with(mut loadfn: F) - where - F: FnMut(&str) -> *const raw::c_void, - { - unsafe { - nvidia_storage::StreamConsumerAcquireAttribNV = - FnPtr::new(metaloadfn(&mut loadfn, "eglStreamConsumerAcquireAttribNV", &[])) - } - } - } } diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index a6d1ea3..088f960 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -18,20 +18,20 @@ //! You may then use the resulting [`EGLDisplay`](::backend::egl::EGLDisplay) to receive [`EGLImages`](::backend::egl::EGLImages) //! of an EGL-based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer) for rendering. +/* #[cfg(feature = "renderer_gl")] use crate::backend::graphics::{ gl::{ffi as gl_ffi, GLGraphicsBackend}, SwapBuffersError as GraphicsSwapBuffersError, }; -use nix::libc::c_uint; +*/ use std::fmt; -#[cfg(feature = "wayland_frontend")] -use wayland_server::Display; pub mod context; pub use self::context::EGLContext; mod error; pub use self::error::*; +use crate::backend::SwapBuffersError as GraphicsSwapBuffersError; use nix::libc::c_void; @@ -43,11 +43,7 @@ pub mod display; pub mod native; pub mod surface; pub use self::surface::EGLSurface; -#[cfg(feature = "use_system_lib")] -use crate::backend::egl::display::EGLBufferReader; use crate::backend::egl::display::EGLDisplayHandle; -#[cfg(feature = "renderer_gl")] -use std::ffi::CStr; use std::ffi::CString; use std::sync::Arc; @@ -71,7 +67,7 @@ impl ::std::error::Error for EglExtensionNotSupportedError {} /// Returns the address of an OpenGL function. /// /// Result is independent of displays and does not guarantee an extension is actually supported at runtime. -pub fn get_proc_address(symbol: &str) -> *const c_void { +pub unsafe fn get_proc_address(symbol: &str) -> *const c_void { unsafe { let addr = CString::new(symbol.as_bytes()).unwrap(); let addr = addr.as_ptr(); @@ -111,45 +107,29 @@ impl fmt::Debug for BufferAccessError { } } -/// Error that can occur when creating a surface. -#[derive(Debug, thiserror::Error)] -pub enum SurfaceCreationError { - /// Native Surface creation failed - #[error("Surface creation failed. Err: {0:}")] - NativeSurfaceCreationFailed(#[source] E), - /// EGL surface creation failed - #[error("EGL surface creation failed. Err: {0:}")] - EGLSurfaceCreationFailed(#[source] EGLError), -} - /// Error that can happen when swapping buffers. #[derive(Debug, thiserror::Error)] -pub enum SwapBuffersError { - /// Error of the underlying native surface - #[error("Underlying error: {0:?}")] - Underlying(#[source] E), +pub enum SwapBuffersError { /// EGL error during `eglSwapBuffers` #[error("{0:}")] EGLSwapBuffers(#[source] EGLError), - /// EGL error during `eglCreateWindowSurface` + /// EGL error during surface creation #[error("{0:}")] - EGLCreateWindowSurface(#[source] EGLError), + EGLCreateSurface(#[source] EGLError), } -impl std::convert::TryFrom> for GraphicsSwapBuffersError { - type Error = E; - fn try_from(value: SwapBuffersError) -> Result { +impl std::convert::From for GraphicsSwapBuffersError { + fn from(value: SwapBuffersError) -> Self { match value { // bad surface is answered with a surface recreation in `swap_buffers` x @ SwapBuffersError::EGLSwapBuffers(EGLError::BadSurface) => { - Ok(GraphicsSwapBuffersError::TemporaryFailure(Box::new(x))) + GraphicsSwapBuffersError::TemporaryFailure(Box::new(x)) } // the rest is either never happening or are unrecoverable - x @ SwapBuffersError::EGLSwapBuffers(_) => Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x))), - x @ SwapBuffersError::EGLCreateWindowSurface(_) => { - Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x))) + x @ SwapBuffersError::EGLSwapBuffers(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)), + x @ SwapBuffersError::EGLCreateSurface(_) => { + GraphicsSwapBuffersError::ContextLost(Box::new(x)) } - SwapBuffersError::Underlying(e) => Err(e), } } } @@ -265,8 +245,6 @@ pub struct EGLImages { /// Format of these images pub format: Format, images: Vec, - #[cfg(feature = "renderer_gl")] - gl: gl_ffi::Gles2, } // Gles2 does not implement debug, so we have to impl Debug manually @@ -291,6 +269,7 @@ impl EGLImages { self.format.num_planes() } + /* /// Bind plane to an OpenGL texture id /// /// This does only temporarily modify the OpenGL state any changes are reverted before returning. @@ -342,6 +321,7 @@ impl EGLImages { self.gl.BindTexture(gl_ffi::TEXTURE_2D, old_tex_id as u32); res } + */ } #[cfg(feature = "wayland_frontend")] @@ -355,22 +335,3 @@ impl Drop for EGLImages { } } } - -/// Trait any backend type may implement that allows binding a [`Display`](wayland_server::Display) -/// to create an [`EGLBufferReader`](display::EGLBufferReader) for EGL-based [`WlBuffer`]s. -#[cfg(feature = "use_system_lib")] -pub trait EGLGraphicsBackend { - /// Binds this EGL context to the given Wayland display. - /// - /// This will allow clients to utilize EGL to create hardware-accelerated - /// surfaces. The server will need to be able to handle EGL-[`WlBuffer`]s. - /// - /// ## Errors - /// - /// This might return [`EglExtensionNotSupported`](ErrorKind::EglExtensionNotSupported) - /// if binding is not supported by the EGL implementation. - /// - /// This might return [`OtherEGLDisplayAlreadyBound`](ErrorKind::OtherEGLDisplayAlreadyBound) - /// if called for the same [`Display`] multiple times, as only one context may be bound at any given time. - fn bind_wl_display(&self, display: &Display) -> Result; -} diff --git a/src/backend/egl/native.rs b/src/backend/egl/native.rs index 1864f78..2d829b0 100644 --- a/src/backend/egl/native.rs +++ b/src/backend/egl/native.rs @@ -1,10 +1,12 @@ //! Type safe native types for safe context/surface creation use super::{ - display::EGLDisplayHandle, ffi, wrap_egl_call, EGLError, Error, SurfaceCreationError, SwapBuffersError, + display::EGLDisplayHandle, ffi, wrap_egl_call, SwapBuffersError, }; use nix::libc::{c_int, c_void}; use std::sync::Arc; +#[cfg(feature = "backend_gbm")] +use std::os::unix::io::AsRawFd; #[cfg(feature = "backend_winit")] use wayland_egl as wegl; @@ -13,186 +15,47 @@ use winit::platform::unix::WindowExtUnix; #[cfg(feature = "backend_winit")] 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; - /// Error type thrown by the surface creation in case of failure. - type Error: ::std::error::Error + Send + 'static; +#[cfg(feature = "backend_gbm")] +use gbm::{AsRaw, Device as GbmDevice}; - /// Return an [`EGLDisplay`](ffi::egl::types::EGLDisplay) based on this backend - /// - /// # Safety - /// - /// The returned [`EGLDisplay`](ffi::egl::types::EGLDisplay) needs to be a valid pointer for EGL, - /// but there is no way to test that. - unsafe fn get_display bool>( - display: ffi::NativeDisplayType, - attribs: &[ffi::EGLint], - has_dp_extension: F, - log: ::slog::Logger, - ) -> Result; -} - -#[cfg(feature = "backend_winit")] -#[derive(Debug)] -/// Wayland backend type -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, - attribs: &[ffi::EGLint], - has_dp_extension: F, - log: ::slog::Logger, - ) -> Result - where - F: Fn(&str) -> bool, - { - if has_dp_extension("EGL_KHR_platform_wayland") && ffi::egl::GetPlatformDisplay::is_loaded() { - trace!(log, "EGL Display Initialization via EGL_KHR_platform_wayland"); - let attribs = attribs.iter().map(|x| *x as isize).collect::>(); - wrap_egl_call(|| { - ffi::egl::GetPlatformDisplay( - ffi::egl::PLATFORM_WAYLAND_KHR, - display as *mut _, - attribs.as_ptr(), - ) - }) - } else if has_dp_extension("EGL_EXT_platform_wayland") && ffi::egl::GetPlatformDisplayEXT::is_loaded() - { - trace!(log, "EGL Display Initialization via EGL_EXT_platform_wayland"); - wrap_egl_call(|| { - ffi::egl::GetPlatformDisplayEXT( - ffi::egl::PLATFORM_WAYLAND_EXT, - display as *mut _, - attribs.as_ptr(), - ) - }) - } else { - trace!(log, "Default EGL Display Initialization via GetDisplay"); - wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _)) - } - } -} - -#[cfg(feature = "backend_winit")] -#[derive(Debug)] -/// Typed Xlib window for the `X11` backend -pub struct XlibWindow(u64); -#[cfg(feature = "backend_winit")] -/// X11 backend type -#[derive(Debug)] -pub enum X11 {} -#[cfg(feature = "backend_winit")] -impl Backend for X11 { - type Surface = XlibWindow; - type Error = Error; - - unsafe fn get_display( - display: ffi::NativeDisplayType, - attribs: &[ffi::EGLint], - has_dp_extension: F, - log: ::slog::Logger, - ) -> Result - where - F: Fn(&str) -> bool, - { - if has_dp_extension("EGL_KHR_platform_x11") && ffi::egl::GetPlatformDisplay::is_loaded() { - trace!(log, "EGL Display Initialization via EGL_KHR_platform_x11"); - let attribs = attribs.iter().map(|x| *x as isize).collect::>(); - wrap_egl_call(|| { - ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_X11_KHR, display as *mut _, attribs.as_ptr()) - }) - } else if has_dp_extension("EGL_EXT_platform_x11") && ffi::egl::GetPlatformDisplayEXT::is_loaded() { - trace!(log, "EGL Display Initialization via EGL_EXT_platform_x11"); - wrap_egl_call(|| { - ffi::egl::GetPlatformDisplayEXT( - ffi::egl::PLATFORM_X11_EXT, - display as *mut _, - attribs.as_ptr(), - ) - }) - } else { - trace!(log, "Default EGL Display Initialization via GetDisplay"); - wrap_egl_call(|| ffi::egl::GetDisplay(display as *mut _)) - } - } -} - -/// Trait for types returning Surfaces which can be used to initialize [`EGLSurface`](super::EGLSurface)s -/// -/// ## Unsafety -/// -/// The returned [`NativeDisplayType`](super::ffi::NativeDisplayType) must be valid for EGL and there is no way to test that. -pub unsafe trait NativeDisplay { - /// Arguments used to surface creation. - type Arguments; - /// 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; - /// Return a raw pointer EGL will accept for context creation. - fn ptr(&self) -> Result; - /// Return attributes that might be used by `B::get_display` - /// - /// Default implementation returns an empty list - fn attributes(&self) -> Vec { - vec![ffi::egl::NONE as ffi::EGLint] - } +pub trait EGLNativeDisplay: Send { + fn required_extensions(&self) -> &'static [&'static str]; + fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec); /// Type of surfaces created fn surface_type(&self) -> ffi::EGLint { ffi::egl::WINDOW_BIT as ffi::EGLint } - /// Create a surface - fn create_surface(&mut self, args: Self::Arguments) -> Result; } -#[cfg(feature = "backend_winit")] -unsafe impl NativeDisplay for WinitWindow { - type Arguments = (); - - fn is_backend(&self) -> bool { - self.xlib_display().is_some() +#[cfg(feature = "backend_gbm")] +impl EGLNativeDisplay for GbmDevice { + fn required_extensions(&self) -> &'static [&'static str] { + &["EGL_MESA_platform_gbm"] } - - fn ptr(&self) -> Result { - self.xlib_display() - .map(|ptr| ptr as *const _) - .ok_or(Error::NonMatchingBackend("X11")) - } - - fn create_surface(&mut self, _args: ()) -> Result { - self.xlib_window() - .map(XlibWindow) - .ok_or(Error::NonMatchingBackend("X11")) + fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec) { + (ffi::egl::PLATFORM_GBM_MESA, self.as_raw() as *mut _, vec![ffi::egl::NONE as ffi::EGLint]) } } #[cfg(feature = "backend_winit")] -unsafe impl NativeDisplay for WinitWindow { - type Arguments = (); - - fn is_backend(&self) -> bool { - self.wayland_display().is_some() - } - - fn ptr(&self) -> Result { - self.wayland_display() - .map(|ptr| ptr as *const _) - .ok_or(Error::NonMatchingBackend("Wayland")) - } - - fn create_surface(&mut self, _args: ()) -> Result { - if let Some(surface) = self.wayland_surface() { - let size = self.inner_size(); - Ok(unsafe { - wegl::WlEglSurface::new_from_raw(surface as *mut _, size.width as i32, size.height as i32) - }) +impl EGLNativeDisplay for WinitWindow { + fn required_extensions(&self) -> &'static [&'static str] { + if self.wayland_display().is_some() { + &["EGL_EXT_platform_wayland"] + } else if self.xlib_display().is_some() { + &["EGL_EXT_platform_x11"] } else { - Err(Error::NonMatchingBackend("Wayland")) + unreachable!("No backends for winit other then Wayland and X11 are supported") + } + } + + fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec) { + if let Some(display) = self.wayland_display() { + (ffi::egl::PLATFORM_WAYLAND_EXT, display as *mut _, vec![ffi::egl::NONE as ffi::EGLint]) + } else if let Some(display) = self.xlib_display() { + (ffi::egl::PLATFORM_X11_EXT, display as *mut _, vec![ffi::egl::NONE as ffi::EGLint]) + } else { + unreachable!("No backends for winit other then Wayland and X11 are supported") } } } @@ -203,22 +66,19 @@ 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 { +pub unsafe trait EGLNativeSurface: Send + Sync { /// 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( + fn create( &self, display: &Arc, config_id: ffi::egl::types::EGLConfig, surface_attributes: &[c_int], - ) -> Result<*const c_void, SurfaceCreationError>; + ) -> Result<*const c_void, super::EGLError>; /// Will be called to check if any internal resources will need /// to be recreated. Old resources must be used until `create` @@ -230,6 +90,19 @@ pub unsafe trait NativeSurface { false } + /// If the surface supports resizing you may implement and use this function. + /// + /// The two first arguments (width, height) are the new size of the surface, + /// the two others (dx, dy) represent the displacement of the top-left corner of the surface. + /// It allows you to control the direction of the resizing if necessary. + /// + /// Implementations may ignore the dx and dy arguments. + /// + /// Returns true if the resize was successful. + fn resize(&self, _width: i32, _height: i32, _dx: i32, _dy: i32) -> bool { + false + } + /// Adds additional semantics when calling /// [EGLSurface::swap_buffers](::backend::egl::surface::EGLSurface::swap_buffers) /// @@ -238,7 +111,7 @@ pub unsafe trait NativeSurface { &self, display: &Arc, surface: ffi::egl::types::EGLSurface, - ) -> Result<(), SwapBuffersError> { + ) -> Result<(), SwapBuffersError> { wrap_egl_call(|| unsafe { ffi::egl::SwapBuffers(***display, surface as *const _); }) @@ -247,45 +120,49 @@ pub unsafe trait NativeSurface { } #[cfg(feature = "backend_winit")] -unsafe impl NativeSurface for XlibWindow { - type Error = Error; +/// Typed Xlib window for the `X11` backend +pub struct XlibWindow(pub u64); - unsafe fn create( +#[cfg(feature = "backend_winit")] +unsafe impl EGLNativeSurface for XlibWindow { + fn create( &self, display: &Arc, config_id: ffi::egl::types::EGLConfig, surface_attributes: &[c_int], - ) -> Result<*const c_void, SurfaceCreationError> { - wrap_egl_call(|| { - ffi::egl::CreateWindowSurface( + ) -> Result<*const c_void, super::EGLError> { + wrap_egl_call(|| unsafe { + let mut id = self.0; + ffi::egl::CreatePlatformWindowSurfaceEXT( display.handle, config_id, - self.0 as *const _, + (&mut id) as *mut u64 as *mut _, surface_attributes.as_ptr(), ) }) - .map_err(SurfaceCreationError::EGLSurfaceCreationFailed) } } #[cfg(feature = "backend_winit")] -unsafe impl NativeSurface for wegl::WlEglSurface { - type Error = Error; - - unsafe fn create( +unsafe impl EGLNativeSurface for wegl::WlEglSurface { + fn create( &self, display: &Arc, config_id: ffi::egl::types::EGLConfig, surface_attributes: &[c_int], - ) -> Result<*const c_void, SurfaceCreationError> { - wrap_egl_call(|| { - ffi::egl::CreateWindowSurface( + ) -> Result<*const c_void, super::EGLError> { + wrap_egl_call(|| unsafe { + ffi::egl::CreatePlatformWindowSurfaceEXT( display.handle, config_id, - self.ptr() as *const _, + self.ptr() as *mut _, surface_attributes.as_ptr(), ) }) - .map_err(SurfaceCreationError::EGLSurfaceCreationFailed) + } + + fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool { + wegl::WlEglSurface::resize(self, width, height, dx, dy); + true } } diff --git a/src/backend/egl/surface.rs b/src/backend/egl/surface.rs index 3f4f1f0..8153830 100644 --- a/src/backend/egl/surface.rs +++ b/src/backend/egl/surface.rs @@ -1,20 +1,23 @@ //! EGL surface related structs -use super::{ffi, native, EGLError, SurfaceCreationError, SwapBuffersError}; -use crate::backend::egl::display::EGLDisplayHandle; -use crate::backend::graphics::PixelFormat; -use nix::libc::c_int; -use std::ops::{Deref, DerefMut}; use std::sync::{ atomic::{AtomicPtr, Ordering}, Arc, }; +use nix::libc::c_int; + +use crate::backend::egl::{ + display::{EGLDisplay, EGLDisplayHandle, PixelFormat}, + native::EGLNativeSurface, + ffi, EGLError, SwapBuffersError +}; + + /// EGL surface of a given EGL context for rendering -#[derive(Debug)] -pub struct EGLSurface { +pub struct EGLSurface { pub(crate) display: Arc, - native: N, + native: Box, pub(crate) surface: AtomicPtr, config_id: ffi::egl::types::EGLConfig, pixel_format: PixelFormat, @@ -23,32 +26,19 @@ pub struct EGLSurface { } // safe because EGLConfig can be moved between threads // and the other types are thread-safe -unsafe impl Send for EGLSurface {} -unsafe impl Sync for EGLSurface {} +unsafe impl Send for EGLSurface {} -impl Deref for EGLSurface { - type Target = N; - fn deref(&self) -> &N { - &self.native - } -} - -impl DerefMut for EGLSurface { - fn deref_mut(&mut self) -> &mut N { - &mut self.native - } -} - -impl EGLSurface { - pub(crate) fn new( - display: Arc, +impl EGLSurface { + pub fn new( + display: &EGLDisplay, pixel_format: PixelFormat, double_buffered: Option, config: ffi::egl::types::EGLConfig, native: N, log: L, - ) -> Result, SurfaceCreationError> + ) -> Result where + N: EGLNativeSurface + Send + 'static, L: Into>, { let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "renderer_egl")); @@ -74,17 +64,15 @@ impl EGLSurface { out }; - let surface = unsafe { native.create(&display, config, &surface_attributes)? }; + let surface = native.create(&display.display, config, &surface_attributes)?; if surface == ffi::egl::NO_SURFACE { - return Err(SurfaceCreationError::EGLSurfaceCreationFailed( - EGLError::BadSurface, - )); + return Err(EGLError::BadSurface); } Ok(EGLSurface { - display, - native, + display: display.display.clone(), + native: Box::new(native), surface: AtomicPtr::new(surface as *mut _), config_id: config, pixel_format, @@ -94,7 +82,7 @@ impl EGLSurface { } /// Swaps buffers at the end of a frame. - pub fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { + pub fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { let surface = self.surface.load(Ordering::SeqCst); let result = if !surface.is_null() { @@ -115,14 +103,7 @@ impl EGLSurface { unsafe { self.native .create(&self.display, self.config_id, &self.surface_attributes) - .map_err(|err| match err { - SurfaceCreationError::EGLSurfaceCreationFailed(err) => { - SwapBuffersError::EGLCreateWindowSurface(err) - } - SurfaceCreationError::NativeSurfaceCreationFailed(err) => { - SwapBuffersError::Underlying(err) - } - })? as *mut _ + .map_err(SwapBuffersError::EGLCreateSurface)? as *mut _ }, Ordering::SeqCst, ); @@ -151,17 +132,30 @@ impl EGLSurface { } /// Returns the egl config for this context - pub fn get_config_id(&self) -> ffi::egl::types::EGLConfig { + pub fn config_id(&self) -> ffi::egl::types::EGLConfig { self.config_id } /// Returns the pixel format of the main framebuffer of the context. - pub fn get_pixel_format(&self) -> PixelFormat { + pub fn pixel_format(&self) -> PixelFormat { self.pixel_format } + + /// Tries to resize the underlying native surface. + /// + /// The two first arguments (width, height) are the new size of the surface, + /// the two others (dx, dy) represent the displacement of the top-left corner of the surface. + /// It allows you to control the direction of the resizing if necessary. + /// + /// Implementations may ignore the dx and dy arguments. + /// + /// Returns true if the resize was successful. + pub fn resize(&self, width: i32, height: i32, dx: i32, dy: i32) -> bool { + self.native.resize(width, height, dx, dy) + } } -impl Drop for EGLSurface { +impl Drop for EGLSurface { fn drop(&mut self) { unsafe { ffi::egl::DestroySurface(**self.display, *self.surface.get_mut() as *const _);