From c9e67cdfef63fdfe451dfdf21dc5b8327367a60b Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 21 Nov 2018 09:19:40 +0100 Subject: [PATCH] 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; -}