Prevent display being destroyed until all resources have been dropped
This commit is contained in:
parent
c4016af67b
commit
f8c97baf1d
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 _);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 _);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue