Prevent display being destroyed until all resources have been dropped

This commit is contained in:
Chandler Newman 2020-04-16 13:44:32 +01:00
parent c4016af67b
commit f8c97baf1d
4 changed files with 229 additions and 258 deletions

View File

@ -1,17 +1,17 @@
//! EGL context related structs //! EGL context related structs
use super::{ffi, Error}; use super::{ffi, Error};
use crate::backend::egl::display::EGLDisplay; use crate::backend::egl::display::{EGLDisplay, EGLDisplayHandle};
use crate::backend::egl::native::NativeSurface; use crate::backend::egl::native::NativeSurface;
use crate::backend::egl::{native, EGLSurface}; use crate::backend::egl::{native, EGLSurface};
use crate::backend::graphics::{PixelFormat, SwapBuffersError}; use crate::backend::graphics::{PixelFormat, SwapBuffersError};
use std::ptr; use std::ptr;
use std::sync::{Arc, Weak}; use std::sync::Arc;
/// EGL context for rendering /// EGL context for rendering
pub struct EGLContext { pub struct EGLContext {
context: Arc<ffi::egl::types::EGLContext>, context: ffi::egl::types::EGLContext,
display: Weak<ffi::egl::types::EGLDisplay>, display: Arc<EGLDisplayHandle>,
config_id: ffi::egl::types::EGLConfig, config_id: ffi::egl::types::EGLConfig,
pixel_format: PixelFormat, pixel_format: PixelFormat,
} }
@ -94,7 +94,7 @@ impl EGLContext {
// TODO: Support shared contexts // TODO: Support shared contexts
let context = unsafe { let context = unsafe {
ffi::egl::CreateContext( ffi::egl::CreateContext(
*display.display, **display.display,
config_id, config_id,
ptr::null(), ptr::null(),
context_attributes.as_ptr(), context_attributes.as_ptr(),
@ -111,8 +111,8 @@ impl EGLContext {
info!(log, "EGL context created"); info!(log, "EGL context created");
Ok(EGLContext { Ok(EGLContext {
context: Arc::new(context as _), context,
display: Arc::downgrade(&display.display), display: display.display.clone(),
config_id, config_id,
pixel_format, pixel_format,
}) })
@ -132,26 +132,17 @@ impl EGLContext {
where where
N: NativeSurface, N: NativeSurface,
{ {
if let Some(display) = self.display.upgrade() { let surface_ptr = surface.surface.get();
let surface_ptr = surface.surface.get();
let ret = ffi::egl::MakeCurrent( let ret = ffi::egl::MakeCurrent(**self.display, surface_ptr, surface_ptr, self.context);
(*display) as *const _,
surface_ptr as *const _,
surface_ptr as *const _,
(*self.context) as *const _,
);
if ret == 0 { if ret == 0 {
match ffi::egl::GetError() as u32 { match ffi::egl::GetError() as u32 {
ffi::egl::CONTEXT_LOST => Err(SwapBuffersError::ContextLost), ffi::egl::CONTEXT_LOST => Err(SwapBuffersError::ContextLost),
err => panic!("eglMakeCurrent failed (eglGetError returned 0x{:x})", err), err => panic!("eglMakeCurrent failed (eglGetError returned 0x{:x})", err),
}
} else {
Ok(())
} }
} else { } else {
Err(SwapBuffersError::ContextLost) Ok(())
} }
} }
@ -162,32 +153,21 @@ impl EGLContext {
/// This function is marked unsafe, because the context cannot be made current /// This function is marked unsafe, because the context cannot be made current
/// on multiple threads. /// on multiple threads.
pub unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> { pub unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> {
if let Some(display) = self.display.upgrade() { let ret = ffi::egl::MakeCurrent(**self.display, ptr::null(), ptr::null(), self.context);
let surface_ptr = ptr::null();
let ret = ffi::egl::MakeCurrent( if ret == 0 {
(*display) as *const _, match ffi::egl::GetError() as u32 {
surface_ptr as *const _, ffi::egl::CONTEXT_LOST => Err(SwapBuffersError::ContextLost),
surface_ptr as *const _, err => panic!("eglMakeCurrent failed (eglGetError returned 0x{:x})", err),
(*self.context) as *const _,
);
if ret == 0 {
match ffi::egl::GetError() as u32 {
ffi::egl::CONTEXT_LOST => Err(SwapBuffersError::ContextLost),
err => panic!("eglMakeCurrent failed (eglGetError returned 0x{:x})", err),
}
} else {
Ok(())
} }
} else { } else {
Err(SwapBuffersError::ContextLost) Ok(())
} }
} }
/// Returns true if the OpenGL context is the current one in the thread. /// Returns true if the OpenGL context is the current one in the thread.
pub fn is_current(&self) -> bool { pub fn is_current(&self) -> bool {
unsafe { ffi::egl::GetCurrentContext() == (*self.context) as *const _ } unsafe { ffi::egl::GetCurrentContext() == self.context as *const _ }
} }
/// Returns the egl config for this context /// Returns the egl config for this context
@ -204,11 +184,12 @@ impl EGLContext {
impl Drop for EGLContext { impl Drop for EGLContext {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
// we don't call MakeCurrent(0, 0) because we are not sure that the context // We need to ensure the context is unbound, otherwise it egl stalls the destroy call
// is still the current one if ffi::egl::GetCurrentContext() == self.context as *const _ {
if let Some(display) = self.display.upgrade() { ffi::egl::MakeCurrent(ptr::null(), ptr::null(), ptr::null(), ptr::null());
ffi::egl::DestroyContext((*display) as *const _, (*self.context) as *const _);
} }
ffi::egl::DestroyContext(**self.display, self.context);
} }
} }
} }

View File

@ -5,7 +5,7 @@ use crate::backend::egl::EGLGraphicsBackend;
use crate::backend::egl::{ use crate::backend::egl::{
ffi, get_proc_address, native, BufferAccessError, EGLContext, EGLImages, EGLSurface, Error, Format, ffi, get_proc_address, native, BufferAccessError, EGLContext, EGLImages, EGLSurface, Error, Format,
}; };
use std::sync::{Arc, Weak}; use std::sync::Arc;
use std::ptr; use std::ptr;
@ -25,10 +25,34 @@ use std::ffi::{CStr, CString};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::ops::Deref;
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
/// once all resources bound to it have been dropped.
pub(crate) struct EGLDisplayHandle {
handle: ffi::egl::types::EGLDisplay,
}
impl Deref for EGLDisplayHandle {
type Target = ffi::egl::types::EGLDisplay;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl Drop for EGLDisplayHandle {
fn drop(&mut self) {
unsafe {
ffi::egl::Terminate(self.handle);
}
}
}
/// [`EGLDisplay`] represents an initialised EGL environment /// [`EGLDisplay`] represents an initialised EGL environment
pub struct EGLDisplay<B: native::Backend, N: native::NativeDisplay<B>> { pub struct EGLDisplay<B: native::Backend, N: native::NativeDisplay<B>> {
native: RefCell<N>, native: RefCell<N>,
pub(crate) display: Arc<ffi::egl::types::EGLDisplay>, pub(crate) display: Arc<EGLDisplayHandle>,
pub(crate) egl_version: (i32, i32), pub(crate) egl_version: (i32, i32),
pub(crate) extensions: Vec<String>, pub(crate) extensions: Vec<String>,
logger: slog::Logger, logger: slog::Logger,
@ -126,7 +150,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
Ok(EGLDisplay { Ok(EGLDisplay {
native: RefCell::new(native), native: RefCell::new(native),
display: Arc::new(display as *const _), display: Arc::new(EGLDisplayHandle { handle: display }),
egl_version, egl_version,
extensions, extensions,
logger: log, logger: log,
@ -259,7 +283,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
let mut num_configs = MaybeUninit::uninit(); let mut num_configs = MaybeUninit::uninit();
if unsafe { if unsafe {
ffi::egl::ChooseConfig( ffi::egl::ChooseConfig(
*self.display, **self.display,
descriptor.as_ptr(), descriptor.as_ptr(),
config_id.as_mut_ptr(), config_id.as_mut_ptr(),
1, 1,
@ -285,7 +309,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
($display:expr, $config:expr, $attr:expr) => {{ ($display:expr, $config:expr, $attr:expr) => {{
let mut value = MaybeUninit::uninit(); let mut value = MaybeUninit::uninit();
let res = ffi::egl::GetConfigAttrib( let res = ffi::egl::GetConfigAttrib(
*$display, **$display,
$config, $config,
$attr as ffi::egl::types::EGLint, $attr as ffi::egl::types::EGLint,
value.as_mut_ptr(), value.as_mut_ptr(),
@ -345,7 +369,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
})?; })?;
EGLSurface::new( EGLSurface::new(
&self.display, self.display.clone(),
pixel_format, pixel_format,
double_buffer, double_buffer,
config, config,
@ -388,14 +412,6 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
} }
} }
impl<B: native::Backend, N: native::NativeDisplay<B>> Drop for EGLDisplay<B, N> {
fn drop(&mut self) {
unsafe {
ffi::egl::Terminate((*self.display) as *const _);
}
}
}
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGLDisplay<B, N> { impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGLDisplay<B, N> {
/// Binds this EGL display to the given Wayland display. /// Binds this EGL display to the given Wayland display.
@ -414,12 +430,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGL
if !self.extensions.iter().any(|s| s == "EGL_WL_bind_wayland_display") { if !self.extensions.iter().any(|s| s == "EGL_WL_bind_wayland_display") {
return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"])); return Err(Error::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
} }
let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.c_ptr() as *mut _) }; let res = unsafe { ffi::egl::BindWaylandDisplayWL(**self.display, display.c_ptr() as *mut _) };
if res == 0 { if res == 0 {
return Err(Error::OtherEGLDisplayAlreadyBound); return Err(Error::OtherEGLDisplayAlreadyBound);
} }
Ok(EGLBufferReader::new( Ok(EGLBufferReader::new(
Arc::downgrade(&self.display), self.display.clone(),
display.c_ptr(), display.c_ptr(),
&self.extensions, &self.extensions,
)) ))
@ -431,7 +447,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGL
/// Can be created by using [`EGLGraphicsBackend::bind_wl_display`]. /// Can be created by using [`EGLGraphicsBackend::bind_wl_display`].
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
pub struct EGLBufferReader { pub struct EGLBufferReader {
display: Weak<ffi::egl::types::EGLDisplay>, display: Arc<EGLDisplayHandle>,
wayland: *mut wl_display, wayland: *mut wl_display,
#[cfg(feature = "renderer_gl")] #[cfg(feature = "renderer_gl")]
gl: gl_ffi::Gles2, gl: gl_ffi::Gles2,
@ -441,11 +457,7 @@ pub struct EGLBufferReader {
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
impl EGLBufferReader { impl EGLBufferReader {
fn new( fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display, extensions: &[String]) -> Self {
display: Weak<ffi::egl::types::EGLDisplay>,
wayland: *mut wl_display,
extensions: &[String],
) -> Self {
#[cfg(feature = "renderer_gl")] #[cfg(feature = "renderer_gl")]
let gl = gl_ffi::Gles2::load_with(|s| get_proc_address(s) as *const _); let gl = gl_ffi::Gles2::load_with(|s| get_proc_address(s) as *const _);
@ -470,105 +482,101 @@ impl EGLBufferReader {
&self, &self,
buffer: WlBuffer, buffer: WlBuffer,
) -> ::std::result::Result<EGLImages, BufferAccessError> { ) -> ::std::result::Result<EGLImages, BufferAccessError> {
if let Some(display) = self.display.upgrade() { let mut format: i32 = 0;
let mut format: i32 = 0; if unsafe {
if unsafe { ffi::egl::QueryWaylandBufferWL(
ffi::egl::QueryWaylandBufferWL( **self.display,
*display, buffer.as_ref().c_ptr() as _,
buffer.as_ref().c_ptr() as *mut _, ffi::egl::EGL_TEXTURE_FORMAT,
ffi::egl::EGL_TEXTURE_FORMAT, &mut format,
&mut format as *mut _, ) == 0
) == 0 } {
} { return Err(BufferAccessError::NotManaged(buffer));
return Err(BufferAccessError::NotManaged(buffer));
}
let format = match format {
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
ffi::egl::TEXTURE_Y_UV_WL => Format::Y_UV,
ffi::egl::TEXTURE_Y_U_V_WL => Format::Y_U_V,
ffi::egl::TEXTURE_Y_XUXV_WL => Format::Y_XUXV,
_ => panic!("EGL returned invalid texture type"),
};
let mut width: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
*display,
buffer.as_ref().c_ptr() as *mut _,
ffi::egl::WIDTH as i32,
&mut width as *mut _,
) == 0
} {
return Err(BufferAccessError::NotManaged(buffer));
}
let mut height: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
*display,
buffer.as_ref().c_ptr() as *mut _,
ffi::egl::HEIGHT as i32,
&mut height as *mut _,
) == 0
} {
return Err(BufferAccessError::NotManaged(buffer));
}
let mut inverted: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
*display,
buffer.as_ref().c_ptr() as *mut _,
ffi::egl::WAYLAND_Y_INVERTED_WL,
&mut inverted as *mut _,
) != 0
} {
inverted = 1;
}
let mut images = Vec::with_capacity(format.num_planes());
for i in 0..format.num_planes() {
let mut out = Vec::with_capacity(3);
out.push(ffi::egl::WAYLAND_PLANE_WL as i32);
out.push(i as i32);
out.push(ffi::egl::NONE as i32);
images.push({
let image = unsafe {
ffi::egl::CreateImageKHR(
*display,
ffi::egl::NO_CONTEXT,
ffi::egl::WAYLAND_BUFFER_WL,
buffer.as_ref().c_ptr() as *mut _,
out.as_ptr(),
)
};
if image == ffi::egl::NO_IMAGE_KHR {
return Err(BufferAccessError::EGLImageCreationFailed);
} else {
image
}
});
}
Ok(EGLImages {
display: Arc::downgrade(&display),
width: width as u32,
height: height as u32,
y_inverted: inverted != 0,
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)
} }
let format = match format {
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
ffi::egl::TEXTURE_Y_UV_WL => Format::Y_UV,
ffi::egl::TEXTURE_Y_U_V_WL => Format::Y_U_V,
ffi::egl::TEXTURE_Y_XUXV_WL => Format::Y_XUXV,
_ => panic!("EGL returned invalid texture type"),
};
let mut width: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
**self.display,
buffer.as_ref().c_ptr() as _,
ffi::egl::WIDTH as i32,
&mut width,
) == 0
} {
return Err(BufferAccessError::NotManaged(buffer));
}
let mut height: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
**self.display,
buffer.as_ref().c_ptr() as _,
ffi::egl::HEIGHT as i32,
&mut height,
) == 0
} {
return Err(BufferAccessError::NotManaged(buffer));
}
let mut inverted: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
**self.display,
buffer.as_ref().c_ptr() as _,
ffi::egl::WAYLAND_Y_INVERTED_WL,
&mut inverted,
) != 0
} {
inverted = 1;
}
let mut images = Vec::with_capacity(format.num_planes());
for i in 0..format.num_planes() {
let mut out = Vec::with_capacity(3);
out.push(ffi::egl::WAYLAND_PLANE_WL as i32);
out.push(i as i32);
out.push(ffi::egl::NONE as i32);
images.push({
let image = unsafe {
ffi::egl::CreateImageKHR(
**self.display,
ffi::egl::NO_CONTEXT,
ffi::egl::WAYLAND_BUFFER_WL,
buffer.as_ref().c_ptr() as *mut _,
out.as_ptr(),
)
};
if image == ffi::egl::NO_IMAGE_KHR {
return Err(BufferAccessError::EGLImageCreationFailed);
} else {
image
}
});
}
Ok(EGLImages {
display: self.display.clone(),
width: width as u32,
height: height as u32,
y_inverted: inverted != 0,
format,
images,
buffer,
#[cfg(feature = "renderer_gl")]
gl: self.gl.clone(),
#[cfg(feature = "renderer_gl")]
egl_to_texture_support: self.egl_to_texture_support,
})
} }
/// Try to receive the dimensions of a given [`WlBuffer`]. /// Try to receive the dimensions of a given [`WlBuffer`].
@ -576,46 +584,40 @@ impl EGLBufferReader {
/// In case the buffer is not managed by EGL (but e.g. the [`wayland::shm` module](::wayland::shm)) or the /// In case the buffer is not managed by EGL (but e.g. the [`wayland::shm` module](::wayland::shm)) or the
/// context has been lost, `None` is returned. /// context has been lost, `None` is returned.
pub fn egl_buffer_dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> { pub fn egl_buffer_dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
if let Some(display) = self.display.upgrade() { let mut width: i32 = 0;
let mut width: i32 = 0; if unsafe {
if unsafe { ffi::egl::QueryWaylandBufferWL(
ffi::egl::QueryWaylandBufferWL( **self.display,
*display, buffer.as_ref().c_ptr() as _,
buffer.as_ref().c_ptr() as *mut _, ffi::egl::WIDTH as _,
ffi::egl::WIDTH as i32, &mut width,
&mut width as *mut _, ) == 0
) == 0 } {
} { return None;
return None;
}
let mut height: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
*display,
buffer.as_ref().c_ptr() as *mut _,
ffi::egl::HEIGHT as i32,
&mut height as *mut _,
) == 0
} {
return None;
}
Some((width, height))
} else {
None
} }
let mut height: i32 = 0;
if unsafe {
ffi::egl::QueryWaylandBufferWL(
**self.display,
buffer.as_ref().c_ptr() as _,
ffi::egl::HEIGHT as _,
&mut height,
) == 0
} {
return None;
}
Some((width, height))
} }
} }
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
impl Drop for EGLBufferReader { impl Drop for EGLBufferReader {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(display) = self.display.upgrade() { if !self.wayland.is_null() {
if !self.wayland.is_null() { unsafe {
unsafe { ffi::egl::UnbindWaylandDisplayWL(**self.display, self.wayland as _);
ffi::egl::UnbindWaylandDisplayWL(*display, self.wayland as *mut _);
}
} }
} }
} }

View File

@ -42,8 +42,9 @@ pub mod surface;
pub use self::surface::EGLSurface; pub use self::surface::EGLSurface;
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use crate::backend::egl::display::EGLBufferReader; use crate::backend::egl::display::EGLBufferReader;
use crate::backend::egl::display::EGLDisplayHandle;
use std::ffi::CString; use std::ffi::CString;
use std::sync::Weak; use std::sync::Arc;
/// Error that can happen on optional EGL features /// Error that can happen on optional EGL features
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -167,7 +168,7 @@ impl Format {
/// Images of the EGL-based [`WlBuffer`]. /// Images of the EGL-based [`WlBuffer`].
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
pub struct EGLImages { pub struct EGLImages {
display: Weak<ffi::egl::types::EGLDisplay>, display: Arc<EGLDisplayHandle>,
/// Width in pixels /// Width in pixels
pub width: u32, pub width: u32,
/// Height in pixels /// Height in pixels
@ -204,41 +205,35 @@ impl EGLImages {
plane: usize, plane: usize,
tex_id: c_uint, tex_id: c_uint,
) -> ::std::result::Result<(), TextureCreationError> { ) -> ::std::result::Result<(), TextureCreationError> {
if self.display.upgrade().is_some() { if !self.egl_to_texture_support {
if !self.egl_to_texture_support { return Err(TextureCreationError::GLExtensionNotSupported("GL_OES_EGL_image"));
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);
self.gl.EGLImageTargetTexture2DOES(
gl_ffi::TEXTURE_2D,
*self
.images
.get(plane)
.ok_or(TextureCreationError::PlaneIndexOutOfBounds)?,
);
let res = match ffi::egl::GetError() as u32 {
ffi::egl::SUCCESS => Ok(()),
err => Err(TextureCreationError::TextureBindingFailed(err)),
};
self.gl.BindTexture(gl_ffi::TEXTURE_2D, old_tex_id as u32);
res
} else {
Err(TextureCreationError::ContextLost)
} }
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);
self.gl.EGLImageTargetTexture2DOES(
gl_ffi::TEXTURE_2D,
*self
.images
.get(plane)
.ok_or(TextureCreationError::PlaneIndexOutOfBounds)?,
);
let res = match ffi::egl::GetError() as u32 {
ffi::egl::SUCCESS => Ok(()),
err => Err(TextureCreationError::TextureBindingFailed(err)),
};
self.gl.BindTexture(gl_ffi::TEXTURE_2D, old_tex_id as u32);
res
} }
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
impl Drop for EGLImages { impl Drop for EGLImages {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(display) = self.display.upgrade() { for image in self.images.drain(..) {
for image in self.images.drain(..) { unsafe {
unsafe { ffi::egl::DestroyImageKHR(**self.display, image);
ffi::egl::DestroyImageKHR(*display, image);
}
} }
} }
self.buffer.release(); self.buffer.release();

View File

@ -1,9 +1,10 @@
//! EGL surface related structs //! EGL surface related structs
use super::{ffi, native, Error}; use super::{ffi, native, Error};
use crate::backend::egl::display::EGLDisplayHandle;
use crate::backend::graphics::{PixelFormat, SwapBuffersError}; use crate::backend::graphics::{PixelFormat, SwapBuffersError};
use nix::libc::c_int; use nix::libc::c_int;
use std::sync::{Arc, Weak}; use std::sync::Arc;
use std::{ use std::{
cell::Cell, cell::Cell,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
@ -11,7 +12,7 @@ use std::{
/// EGL surface of a given EGL context for rendering /// EGL surface of a given EGL context for rendering
pub struct EGLSurface<N: native::NativeSurface> { pub struct EGLSurface<N: native::NativeSurface> {
display: Weak<ffi::egl::types::EGLDisplay>, display: Arc<EGLDisplayHandle>,
native: N, native: N,
pub(crate) surface: Cell<ffi::egl::types::EGLSurface>, pub(crate) surface: Cell<ffi::egl::types::EGLSurface>,
config_id: ffi::egl::types::EGLConfig, config_id: ffi::egl::types::EGLConfig,
@ -34,7 +35,7 @@ impl<N: native::NativeSurface> DerefMut for EGLSurface<N> {
impl<N: native::NativeSurface> EGLSurface<N> { impl<N: native::NativeSurface> EGLSurface<N> {
pub(crate) fn new<L>( pub(crate) fn new<L>(
display: &Arc<ffi::egl::types::EGLDisplay>, display: Arc<EGLDisplayHandle>,
pixel_format: PixelFormat, pixel_format: PixelFormat,
double_buffered: Option<bool>, double_buffered: Option<bool>,
config: ffi::egl::types::EGLConfig, config: ffi::egl::types::EGLConfig,
@ -76,7 +77,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
} }
Ok(EGLSurface { Ok(EGLSurface {
display: Arc::downgrade(display), display,
native, native,
surface: Cell::new(surface), surface: Cell::new(surface),
config_id: config, config_id: config,
@ -90,34 +91,28 @@ impl<N: native::NativeSurface> EGLSurface<N> {
let surface = self.surface.get(); let surface = self.surface.get();
if !surface.is_null() { if !surface.is_null() {
if let Some(display) = self.display.upgrade() { let ret = unsafe { ffi::egl::SwapBuffers(**self.display, surface as *const _) };
let ret = unsafe { ffi::egl::SwapBuffers((*display) as *const _, surface as *const _) };
if ret == 0 { if ret == 0 {
match unsafe { ffi::egl::GetError() } as u32 { match unsafe { ffi::egl::GetError() } as u32 {
ffi::egl::CONTEXT_LOST => return Err(SwapBuffersError::ContextLost), ffi::egl::CONTEXT_LOST => return Err(SwapBuffersError::ContextLost),
err => return Err(SwapBuffersError::Unknown(err)), err => return Err(SwapBuffersError::Unknown(err)),
}; };
} else {
self.native.swap_buffers()?;
}
} else { } else {
return Err(SwapBuffersError::ContextLost); self.native.swap_buffers()?;
} }
}; };
if self.native.needs_recreation() || surface.is_null() { if self.native.needs_recreation() || surface.is_null() {
if let Some(display) = self.display.upgrade() { self.native.recreate();
self.native.recreate(); self.surface.set(unsafe {
self.surface.set(unsafe { ffi::egl::CreateWindowSurface(
ffi::egl::CreateWindowSurface( **self.display,
*display, self.config_id,
self.config_id, self.native.ptr(),
self.native.ptr(), self.surface_attributes.as_ptr(),
self.surface_attributes.as_ptr(), )
) });
});
}
} }
Ok(()) Ok(())
@ -144,10 +139,8 @@ impl<N: native::NativeSurface> EGLSurface<N> {
impl<N: native::NativeSurface> Drop for EGLSurface<N> { impl<N: native::NativeSurface> Drop for EGLSurface<N> {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(display) = self.display.upgrade() { unsafe {
unsafe { ffi::egl::DestroySurface(**self.display, self.surface.get() as *const _);
ffi::egl::DestroySurface((*display) as *const _, self.surface.get() as *const _);
}
} }
} }
} }