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.
This commit is contained in:
parent
d606165088
commit
d99108a8e6
|
@ -1,76 +1,81 @@
|
||||||
//! EGL context related structs
|
//! 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::os::raw::c_int;
|
||||||
use std::ptr;
|
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
|
/// EGL context for rendering
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EGLContext {
|
pub struct EGLContext {
|
||||||
context: ffi::egl::types::EGLContext,
|
context: ffi::egl::types::EGLContext,
|
||||||
display: Arc<EGLDisplayHandle>,
|
pub(crate) display: EGLDisplay,
|
||||||
config_id: ffi::egl::types::EGLConfig,
|
config_id: ffi::egl::types::EGLConfig,
|
||||||
pixel_format: PixelFormat,
|
pixel_format: Option<PixelFormat>,
|
||||||
}
|
}
|
||||||
// EGLContexts can be moved between threads safely
|
// EGLContexts can be moved between threads safely
|
||||||
unsafe impl Send for EGLContext {}
|
unsafe impl Send for EGLContext {}
|
||||||
unsafe impl Sync for EGLContext {}
|
unsafe impl Sync for EGLContext {}
|
||||||
|
|
||||||
impl EGLContext {
|
impl EGLContext {
|
||||||
|
pub fn new<L>(
|
||||||
|
display: &EGLDisplay,
|
||||||
|
log: L,
|
||||||
|
) -> Result<EGLContext, Error>
|
||||||
|
where
|
||||||
|
L: Into<Option<::slog::Logger>>,
|
||||||
|
{
|
||||||
|
Self::new_internal(display, None, log)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new [`EGLContext`] from a given [`NativeDisplay`](native::NativeDisplay)
|
/// Create a new [`EGLContext`] from a given [`NativeDisplay`](native::NativeDisplay)
|
||||||
pub(crate) fn new<B, N, L>(
|
pub fn new_with_config<L>(
|
||||||
display: &EGLDisplay<B, N>,
|
display: &EGLDisplay,
|
||||||
mut attributes: GlAttributes,
|
attributes: GlAttributes,
|
||||||
reqs: PixelFormatRequirements,
|
reqs: PixelFormatRequirements,
|
||||||
log: L,
|
log: L,
|
||||||
) -> Result<EGLContext, Error>
|
) -> Result<EGLContext, Error>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
B: native::Backend,
|
|
||||||
N: native::NativeDisplay<B>,
|
|
||||||
{
|
{
|
||||||
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,
|
fn new_internal<L>(
|
||||||
// fallback to 2.0 otherwise
|
display: &EGLDisplay,
|
||||||
let version = match attributes.version {
|
config: Option<(GlAttributes, PixelFormatRequirements)>,
|
||||||
Some((3, x)) => (3, x),
|
log: L,
|
||||||
Some((2, x)) => (2, x),
|
) -> Result<EGLContext, Error>
|
||||||
|
where
|
||||||
|
L: Into<Option<::slog::Logger>>,
|
||||||
|
{
|
||||||
|
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 => {
|
None => {
|
||||||
debug!(log, "Trying to initialize EGL with OpenGLES 3.0");
|
if !display.extensions.iter().any(|x| x == "EGL_KHR_no_config_context") &&
|
||||||
attributes.version = Some((3, 0));
|
!display.extensions.iter().any(|x| x == "EGL_MESA_configless_context") &&
|
||||||
match EGLContext::new(display, attributes, reqs, log.clone()) {
|
!display.extensions.iter().any(|x| x == "EGL_KHR_surfaceless_context")
|
||||||
Ok(x) => return Ok(x),
|
{
|
||||||
Err(err) => {
|
return Err(Error::EglExtensionNotSupported(&["EGL_KHR_no_config_context", "EGL_MESA_configless_context", "EGL_KHR_surfaceless_context"]));
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
(None, ffi::egl::NO_CONFIG_KHR)
|
||||||
}
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (pixel_format, config_id) = display.choose_config(attributes, reqs)?;
|
|
||||||
|
|
||||||
let mut context_attributes = Vec::with_capacity(10);
|
let mut context_attributes = Vec::with_capacity(10);
|
||||||
|
|
||||||
|
if let Some((attributes, _)) = config {
|
||||||
|
let version = attributes.version;
|
||||||
|
|
||||||
if display.egl_version >= (1, 5) || display.extensions.iter().any(|s| s == "EGL_KHR_create_context") {
|
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);
|
trace!(log, "Setting CONTEXT_MAJOR_VERSION to {}", version.0);
|
||||||
context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
|
context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
|
||||||
|
@ -92,6 +97,11 @@ impl EGLContext {
|
||||||
context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
|
context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
|
||||||
context_attributes.push(version.0 as i32);
|
context_attributes.push(version.0 as i32);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
trace!(log, "Setting CONTEXT_CLIENT_VERSION to 2");
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
|
||||||
|
context_attributes.push(2);
|
||||||
|
}
|
||||||
|
|
||||||
context_attributes.push(ffi::egl::NONE as i32);
|
context_attributes.push(ffi::egl::NONE as i32);
|
||||||
|
|
||||||
|
@ -111,7 +121,7 @@ impl EGLContext {
|
||||||
|
|
||||||
Ok(EGLContext {
|
Ok(EGLContext {
|
||||||
context,
|
context,
|
||||||
display: display.display.clone(),
|
display: display.clone(),
|
||||||
config_id,
|
config_id,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
})
|
})
|
||||||
|
@ -124,12 +134,10 @@ 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_with_surface<N>(&self, surface: &EGLSurface<N>) -> Result<(), MakeCurrentError>
|
pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError>
|
||||||
where
|
|
||||||
N: NativeSurface,
|
|
||||||
{
|
{
|
||||||
let surface_ptr = surface.surface.load(Ordering::SeqCst);
|
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(|_| ())
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
@ -143,7 +151,7 @@ impl EGLContext {
|
||||||
pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> {
|
pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> {
|
||||||
wrap_egl_call(|| {
|
wrap_egl_call(|| {
|
||||||
ffi::egl::MakeCurrent(
|
ffi::egl::MakeCurrent(
|
||||||
**self.display,
|
**self.display.display,
|
||||||
ffi::egl::NO_SURFACE,
|
ffi::egl::NO_SURFACE,
|
||||||
ffi::egl::NO_SURFACE,
|
ffi::egl::NO_SURFACE,
|
||||||
self.context,
|
self.context,
|
||||||
|
@ -159,12 +167,12 @@ impl EGLContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the egl config for this context
|
/// 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
|
self.config_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the pixel format of the main framebuffer of the context.
|
/// Returns the pixel format of the main framebuffer of the context.
|
||||||
pub fn get_pixel_format(&self) -> PixelFormat {
|
pub fn pixel_format(&self) -> Option<PixelFormat> {
|
||||||
self.pixel_format
|
self.pixel_format
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +183,7 @@ impl EGLContext {
|
||||||
if self.is_current() {
|
if self.is_current() {
|
||||||
wrap_egl_call(|| unsafe {
|
wrap_egl_call(|| unsafe {
|
||||||
ffi::egl::MakeCurrent(
|
ffi::egl::MakeCurrent(
|
||||||
**self.display,
|
**self.display.display,
|
||||||
ffi::egl::NO_SURFACE,
|
ffi::egl::NO_SURFACE,
|
||||||
ffi::egl::NO_SURFACE,
|
ffi::egl::NO_SURFACE,
|
||||||
ffi::egl::NO_CONTEXT,
|
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
|
// We need to ensure the context is unbound, otherwise it egl stalls the destroy call
|
||||||
// ignore failures at this point
|
// ignore failures at this point
|
||||||
let _ = self.unbind();
|
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 {
|
pub struct GlAttributes {
|
||||||
/// Describes the OpenGL API and version that are being requested when a context is created.
|
/// 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.
|
/// `(3, 0)` will request a OpenGL ES 3.0 context for example.
|
||||||
/// `None` means "don't care" (minimum will be 2.0).
|
/// `(2, 0)` is the minimum.
|
||||||
pub version: Option<(u8, u8)>,
|
pub version: (u8, u8),
|
||||||
/// OpenGL profile to use
|
/// OpenGL profile to use
|
||||||
pub profile: Option<GlProfile>,
|
pub profile: Option<GlProfile>,
|
||||||
/// Whether to enable the debug flag of the context.
|
/// Whether to enable the debug flag of the context.
|
||||||
|
|
|
@ -1,31 +1,24 @@
|
||||||
//! Type safe native types for safe egl initialisation
|
//! 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::sync::Arc;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use nix::libc::c_int;
|
use nix::libc::c_int;
|
||||||
|
#[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))]
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
use wayland_server::{protocol::wl_buffer::WlBuffer, Display};
|
use wayland_server::{protocol::wl_buffer::WlBuffer, Display};
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
use wayland_sys::server::wl_display;
|
use wayland_sys::server::wl_display;
|
||||||
|
|
||||||
use crate::backend::egl::context::{GlAttributes, PixelFormatRequirements};
|
use crate::backend::allocator::{Buffer, dmabuf::Dmabuf};
|
||||||
#[cfg(feature = "renderer_gl")]
|
use crate::backend::egl::{
|
||||||
use crate::backend::graphics::gl::ffi as gl_ffi;
|
ffi::egl::types::EGLImage,
|
||||||
use crate::backend::graphics::PixelFormat;
|
ffi, wrap_egl_call, EGLError, Error,
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
context::{GlAttributes, PixelFormatRequirements},
|
||||||
use std::ffi::CStr;
|
native::{EGLNativeDisplay},
|
||||||
use std::marker::PhantomData;
|
BufferAccessError, EGLImages, Format,
|
||||||
use std::mem::MaybeUninit;
|
};
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
|
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
|
||||||
/// once all resources bound to it have been dropped.
|
/// once all resources bound to it have been dropped.
|
||||||
|
@ -56,54 +49,53 @@ impl Drop for EGLDisplayHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`EGLDisplay`] represents an initialised EGL environment
|
/// [`EGLDisplay`] represents an initialised EGL environment
|
||||||
#[derive(Debug)]
|
#[derive(Clone)]
|
||||||
pub struct EGLDisplay<B: native::Backend, N: native::NativeDisplay<B>> {
|
pub struct EGLDisplay {
|
||||||
native: RefCell<N>,
|
|
||||||
pub(crate) display: Arc<EGLDisplayHandle>,
|
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>,
|
||||||
|
surface_type: ffi::EGLint,
|
||||||
logger: slog::Logger,
|
logger: slog::Logger,
|
||||||
_backend: PhantomData<B>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
impl EGLDisplay {
|
||||||
/// Create a new [`EGLDisplay`] from a given [`NativeDisplay`](native::NativeDisplay)
|
/// Create a new [`EGLDisplay`] from a given [`NativeDisplay`](native::NativeDisplay)
|
||||||
pub fn new<L>(native: N, logger: L) -> Result<EGLDisplay<B, N>, Error>
|
pub fn new<N, L>(native: &N, logger: L) -> Result<EGLDisplay, Error>
|
||||||
where
|
where
|
||||||
|
N: EGLNativeDisplay + 'static,
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
let log = crate::slog_or_fallback(logger.into()).new(o!("smithay_module" => "renderer_egl"));
|
let log = crate::slog_or_fallback(logger.into()).new(o!("smithay_module" => "backend_egl"));
|
||||||
let ptr = native.ptr()?;
|
|
||||||
let egl_attribs = native.attributes();
|
|
||||||
|
|
||||||
ffi::make_sure_egl_is_loaded();
|
ffi::make_sure_egl_is_loaded();
|
||||||
|
|
||||||
// the first step is to query the list of extensions without any display, if supported
|
// the first step is to query the list of extensions without any display, if supported
|
||||||
let dp_extensions = unsafe {
|
let dp_extensions = unsafe {
|
||||||
let p =
|
let p =
|
||||||
wrap_egl_call(|| ffi::egl::QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32))
|
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
|
// this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise
|
||||||
// `eglQueryString` returns an error
|
// `eglQueryString` returns an error
|
||||||
if p.is_null() {
|
if p.is_null() {
|
||||||
vec![]
|
return Err(Error::EglExtensionNotSupported(&["EGL_EXT_platform_base"]));
|
||||||
} else {
|
} else {
|
||||||
let p = CStr::from_ptr(p);
|
let p = CStr::from_ptr(p);
|
||||||
let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new());
|
let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new());
|
||||||
list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
|
list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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
|
// we create an EGLDisplay
|
||||||
let display = unsafe {
|
let display = unsafe {
|
||||||
B::get_display(
|
wrap_egl_call(|| ffi::egl::GetPlatformDisplayEXT(platform, native_ptr, attributes.as_ptr()))
|
||||||
ptr,
|
|
||||||
&egl_attribs,
|
|
||||||
|e: &str| dp_extensions.iter().any(|s| s == e),
|
|
||||||
log.clone(),
|
|
||||||
)
|
|
||||||
.map_err(Error::DisplayCreationError)?
|
.map_err(Error::DisplayCreationError)?
|
||||||
};
|
};
|
||||||
if display == ffi::egl::NO_DISPLAY {
|
if display == ffi::egl::NO_DISPLAY {
|
||||||
|
@ -143,7 +135,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
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?)
|
// egl <= 1.2 does not support OpenGL ES (maybe we want to support OpenGL in the future?)
|
||||||
if egl_version <= (1, 2) {
|
if egl_version <= (1, 2) {
|
||||||
|
@ -153,12 +145,11 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
.map_err(|source| Error::OpenGlesNotSupported(Some(source)))?;
|
.map_err(|source| Error::OpenGlesNotSupported(Some(source)))?;
|
||||||
|
|
||||||
Ok(EGLDisplay {
|
Ok(EGLDisplay {
|
||||||
native: RefCell::new(native),
|
|
||||||
display: Arc::new(EGLDisplayHandle { handle: display }),
|
display: Arc::new(EGLDisplayHandle { handle: display }),
|
||||||
|
surface_type: native.surface_type(),
|
||||||
egl_version,
|
egl_version,
|
||||||
extensions,
|
extensions,
|
||||||
logger: log,
|
logger: log,
|
||||||
_backend: PhantomData,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +161,6 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
) -> Result<(PixelFormat, ffi::egl::types::EGLConfig), Error> {
|
) -> Result<(PixelFormat, ffi::egl::types::EGLConfig), Error> {
|
||||||
let descriptor = {
|
let descriptor = {
|
||||||
let mut out: Vec<c_int> = Vec::with_capacity(37);
|
let mut out: Vec<c_int> = Vec::with_capacity(37);
|
||||||
let surface_type = self.native.borrow().surface_type();
|
|
||||||
|
|
||||||
if self.egl_version >= (1, 2) {
|
if self.egl_version >= (1, 2) {
|
||||||
trace!(self.logger, "Setting COLOR_BUFFER_TYPE to RGB_BUFFER");
|
trace!(self.logger, "Setting COLOR_BUFFER_TYPE to RGB_BUFFER");
|
||||||
|
@ -178,15 +168,13 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
out.push(ffi::egl::RGB_BUFFER as c_int);
|
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);
|
out.push(ffi::egl::SURFACE_TYPE as c_int);
|
||||||
// TODO: Some versions of Mesa report a BAD_ATTRIBUTE error
|
out.push(self.surface_type);
|
||||||
// if we ask for PBUFFER_BIT as well as WINDOW_BIT
|
|
||||||
out.push(surface_type);
|
|
||||||
|
|
||||||
match attributes.version {
|
match attributes.version {
|
||||||
Some((3, _)) => {
|
(3, _) => {
|
||||||
if self.egl_version < (1, 3) {
|
if self.egl_version < (1, 3) {
|
||||||
error!(
|
error!(
|
||||||
self.logger,
|
self.logger,
|
||||||
|
@ -201,7 +189,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
out.push(ffi::egl::CONFORMANT as c_int);
|
out.push(ffi::egl::CONFORMANT as c_int);
|
||||||
out.push(ffi::egl::OPENGL_ES3_BIT as c_int);
|
out.push(ffi::egl::OPENGL_ES3_BIT as c_int);
|
||||||
}
|
}
|
||||||
Some((2, _)) => {
|
(2, _) => {
|
||||||
if self.egl_version < (1, 3) {
|
if self.egl_version < (1, 3) {
|
||||||
error!(
|
error!(
|
||||||
self.logger,
|
self.logger,
|
||||||
|
@ -216,12 +204,9 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
out.push(ffi::egl::CONFORMANT as c_int);
|
out.push(ffi::egl::CONFORMANT as c_int);
|
||||||
out.push(ffi::egl::OPENGL_ES2_BIT as c_int);
|
out.push(ffi::egl::OPENGL_ES2_BIT as c_int);
|
||||||
}
|
}
|
||||||
Some(ver) => {
|
ver => {
|
||||||
return Err(Error::OpenGlVersionNotSupported(ver));
|
return Err(Error::OpenGlVersionNotSupported(ver));
|
||||||
}
|
}
|
||||||
None => {
|
|
||||||
return Err(Error::OpenGlVersionNotSupported((0, 0)));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
reqs.create_attributes(&mut out, &self.logger)
|
reqs.create_attributes(&mut out, &self.logger)
|
||||||
|
@ -352,44 +337,6 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
Ok((desc, config_id))
|
Ok((desc, config_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`EGLContext`](::backend::egl::EGLContext)
|
|
||||||
pub fn create_context(
|
|
||||||
&self,
|
|
||||||
attributes: GlAttributes,
|
|
||||||
reqs: PixelFormatRequirements,
|
|
||||||
) -> Result<EGLContext, Error> {
|
|
||||||
EGLContext::new(&self, attributes, reqs, self.logger.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a surface for rendering
|
|
||||||
pub fn create_surface(
|
|
||||||
&self,
|
|
||||||
pixel_format: PixelFormat,
|
|
||||||
double_buffer: Option<bool>,
|
|
||||||
config: ffi::egl::types::EGLConfig,
|
|
||||||
args: N::Arguments,
|
|
||||||
) -> Result<EGLSurface<B::Surface>, SurfaceCreationError<B::Error>> {
|
|
||||||
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
|
/// Returns the runtime egl version of this display
|
||||||
pub fn get_egl_version(&self) -> (i32, i32) {
|
pub fn get_egl_version(&self) -> (i32, i32) {
|
||||||
self.egl_version
|
self.egl_version
|
||||||
|
@ -400,28 +347,90 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLDisplay<B, N> {
|
||||||
self.extensions.clone()
|
self.extensions.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow the underlying native display.
|
/// Imports a dmabuf as an eglimage
|
||||||
///
|
pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result<EGLImage, Error> {
|
||||||
/// This follows the same semantics as [`std::cell:RefCell`](std::cell::RefCell).
|
if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base") &&
|
||||||
/// Multiple read-only borrows are possible. Borrowing the
|
!self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import")
|
||||||
/// backend while there is a mutable reference will panic.
|
{
|
||||||
pub fn borrow(&self) -> Ref<'_, N> {
|
return Err(Error::EglExtensionNotSupported(&["EGL_KHR_image_base", "EGL_EXT_image_dma_buf_import"]));
|
||||||
self.native.borrow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow the underlying native display mutably.
|
if dmabuf.has_modifier() {
|
||||||
///
|
if !self.extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") {
|
||||||
/// This follows the same semantics as [`std::cell:RefCell`](std::cell::RefCell).
|
return Err(Error::EglExtensionNotSupported(&["EGL_EXT_image_dma_buf_import_modifiers"]));
|
||||||
/// 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> {
|
let mut out: Vec<c_int> = Vec::with_capacity(50);
|
||||||
self.native.borrow_mut()
|
|
||||||
|
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::<u64>::into(dmabuf.format().modifier) & 0xFFFFFFFF) as i32,
|
||||||
|
names[i][4] as i32, (Into::<u64>::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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "use_system_lib")]
|
|
||||||
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.
|
||||||
///
|
///
|
||||||
/// This will allow clients to utilize EGL to create hardware-accelerated
|
/// This will allow clients to utilize EGL to create hardware-accelerated
|
||||||
|
@ -434,7 +443,8 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGL
|
||||||
///
|
///
|
||||||
/// This might return [`OtherEGLDisplayAlreadyBound`](ErrorKind::OtherEGLDisplayAlreadyBound)
|
/// 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.
|
/// 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<EGLBufferReader, Error> {
|
#[cfg(all(feature = "use_system_lib", feature = "wayland_frontend"))]
|
||||||
|
pub fn bind_wl_display(&self, display: &Display) -> Result<EGLBufferReader, Error> {
|
||||||
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"]));
|
||||||
}
|
}
|
||||||
|
@ -453,8 +463,6 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGL
|
||||||
pub struct EGLBufferReader {
|
pub struct EGLBufferReader {
|
||||||
display: Arc<EGLDisplayHandle>,
|
display: Arc<EGLDisplayHandle>,
|
||||||
wayland: *mut wl_display,
|
wayland: *mut wl_display,
|
||||||
#[cfg(feature = "renderer_gl")]
|
|
||||||
gl: gl_ffi::Gles2,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gles2 does not implement debug, so we have to impl Debug manually
|
// 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")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
impl EGLBufferReader {
|
impl EGLBufferReader {
|
||||||
fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display) -> Self {
|
fn new(display: Arc<EGLDisplayHandle>, wayland: *mut wl_display) -> Self {
|
||||||
#[cfg(feature = "renderer_gl")]
|
|
||||||
let gl = gl_ffi::Gles2::load_with(|s| get_proc_address(s) as *const _);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
display,
|
display,
|
||||||
wayland,
|
wayland,
|
||||||
#[cfg(feature = "renderer_gl")]
|
|
||||||
gl,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,8 +580,6 @@ impl EGLBufferReader {
|
||||||
y_inverted: inverted != 0,
|
y_inverted: inverted != 0,
|
||||||
format,
|
format,
|
||||||
images,
|
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<u16>,
|
||||||
|
/// is srgb enabled
|
||||||
|
pub srgb: bool,
|
||||||
|
}
|
|
@ -198,66 +198,4 @@ pub mod egl {
|
||||||
// Accepted in the <attribute> parameter of eglQueryWaylandBufferWL:
|
// Accepted in the <attribute> parameter of eglQueryWaylandBufferWL:
|
||||||
pub const EGL_TEXTURE_FORMAT: i32 = 0x3080;
|
pub const EGL_TEXTURE_FORMAT: i32 = 0x3080;
|
||||||
pub const WAYLAND_Y_INVERTED_WL: i32 = 0x31DB;
|
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<F>(mut loadfn: F)
|
|
||||||
where
|
|
||||||
F: FnMut(&str) -> *const raw::c_void,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
nvidia_storage::StreamConsumerAcquireAttribNV =
|
|
||||||
FnPtr::new(metaloadfn(&mut loadfn, "eglStreamConsumerAcquireAttribNV", &[]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,20 +18,20 @@
|
||||||
//! You may then use the resulting [`EGLDisplay`](::backend::egl::EGLDisplay) to receive [`EGLImages`](::backend::egl::EGLImages)
|
//! 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.
|
//! of an EGL-based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer) for rendering.
|
||||||
|
|
||||||
|
/*
|
||||||
#[cfg(feature = "renderer_gl")]
|
#[cfg(feature = "renderer_gl")]
|
||||||
use crate::backend::graphics::{
|
use crate::backend::graphics::{
|
||||||
gl::{ffi as gl_ffi, GLGraphicsBackend},
|
gl::{ffi as gl_ffi, GLGraphicsBackend},
|
||||||
SwapBuffersError as GraphicsSwapBuffersError,
|
SwapBuffersError as GraphicsSwapBuffersError,
|
||||||
};
|
};
|
||||||
use nix::libc::c_uint;
|
*/
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
use wayland_server::Display;
|
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub use self::context::EGLContext;
|
pub use self::context::EGLContext;
|
||||||
mod error;
|
mod error;
|
||||||
pub use self::error::*;
|
pub use self::error::*;
|
||||||
|
use crate::backend::SwapBuffersError as GraphicsSwapBuffersError;
|
||||||
|
|
||||||
use nix::libc::c_void;
|
use nix::libc::c_void;
|
||||||
|
|
||||||
|
@ -43,11 +43,7 @@ pub mod display;
|
||||||
pub mod native;
|
pub mod native;
|
||||||
pub mod surface;
|
pub mod surface;
|
||||||
pub use self::surface::EGLSurface;
|
pub use self::surface::EGLSurface;
|
||||||
#[cfg(feature = "use_system_lib")]
|
|
||||||
use crate::backend::egl::display::EGLBufferReader;
|
|
||||||
use crate::backend::egl::display::EGLDisplayHandle;
|
use crate::backend::egl::display::EGLDisplayHandle;
|
||||||
#[cfg(feature = "renderer_gl")]
|
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -71,7 +67,7 @@ impl ::std::error::Error for EglExtensionNotSupportedError {}
|
||||||
/// Returns the address of an OpenGL function.
|
/// Returns the address of an OpenGL function.
|
||||||
///
|
///
|
||||||
/// Result is independent of displays and does not guarantee an extension is actually supported at runtime.
|
/// 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 {
|
unsafe {
|
||||||
let addr = CString::new(symbol.as_bytes()).unwrap();
|
let addr = CString::new(symbol.as_bytes()).unwrap();
|
||||||
let addr = addr.as_ptr();
|
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<E: std::error::Error + 'static> {
|
|
||||||
/// 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.
|
/// Error that can happen when swapping buffers.
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum SwapBuffersError<E: std::error::Error + 'static> {
|
pub enum SwapBuffersError {
|
||||||
/// Error of the underlying native surface
|
|
||||||
#[error("Underlying error: {0:?}")]
|
|
||||||
Underlying(#[source] E),
|
|
||||||
/// EGL error during `eglSwapBuffers`
|
/// EGL error during `eglSwapBuffers`
|
||||||
#[error("{0:}")]
|
#[error("{0:}")]
|
||||||
EGLSwapBuffers(#[source] EGLError),
|
EGLSwapBuffers(#[source] EGLError),
|
||||||
/// EGL error during `eglCreateWindowSurface`
|
/// EGL error during surface creation
|
||||||
#[error("{0:}")]
|
#[error("{0:}")]
|
||||||
EGLCreateWindowSurface(#[source] EGLError),
|
EGLCreateSurface(#[source] EGLError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: std::error::Error> std::convert::TryFrom<SwapBuffersError<E>> for GraphicsSwapBuffersError {
|
impl std::convert::From<SwapBuffersError> for GraphicsSwapBuffersError {
|
||||||
type Error = E;
|
fn from(value: SwapBuffersError) -> Self {
|
||||||
fn try_from(value: SwapBuffersError<E>) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
match value {
|
||||||
// bad surface is answered with a surface recreation in `swap_buffers`
|
// bad surface is answered with a surface recreation in `swap_buffers`
|
||||||
x @ SwapBuffersError::EGLSwapBuffers(EGLError::BadSurface) => {
|
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
|
// the rest is either never happening or are unrecoverable
|
||||||
x @ SwapBuffersError::EGLSwapBuffers(_) => Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x))),
|
x @ SwapBuffersError::EGLSwapBuffers(_) => GraphicsSwapBuffersError::ContextLost(Box::new(x)),
|
||||||
x @ SwapBuffersError::EGLCreateWindowSurface(_) => {
|
x @ SwapBuffersError::EGLCreateSurface(_) => {
|
||||||
Ok(GraphicsSwapBuffersError::ContextLost(Box::new(x)))
|
GraphicsSwapBuffersError::ContextLost(Box::new(x))
|
||||||
}
|
}
|
||||||
SwapBuffersError::Underlying(e) => Err(e),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,8 +245,6 @@ pub struct EGLImages {
|
||||||
/// Format of these images
|
/// Format of these images
|
||||||
pub format: Format,
|
pub format: Format,
|
||||||
images: Vec<EGLImage>,
|
images: Vec<EGLImage>,
|
||||||
#[cfg(feature = "renderer_gl")]
|
|
||||||
gl: gl_ffi::Gles2,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gles2 does not implement debug, so we have to impl Debug manually
|
// Gles2 does not implement debug, so we have to impl Debug manually
|
||||||
|
@ -291,6 +269,7 @@ impl EGLImages {
|
||||||
self.format.num_planes()
|
self.format.num_planes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Bind plane to an OpenGL texture id
|
/// Bind plane to an OpenGL texture id
|
||||||
///
|
///
|
||||||
/// This does only temporarily modify the OpenGL state any changes are reverted before returning.
|
/// 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);
|
self.gl.BindTexture(gl_ffi::TEXTURE_2D, old_tex_id as u32);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[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<EGLBufferReader, Error>;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
//! Type safe native types for safe context/surface creation
|
//! Type safe native types for safe context/surface creation
|
||||||
|
|
||||||
use super::{
|
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 nix::libc::{c_int, c_void};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
#[cfg(feature = "backend_gbm")]
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
use wayland_egl as wegl;
|
use wayland_egl as wegl;
|
||||||
|
@ -13,186 +15,47 @@ use winit::platform::unix::WindowExtUnix;
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
use winit::window::Window as WinitWindow;
|
use winit::window::Window as WinitWindow;
|
||||||
|
|
||||||
/// Trait for typed backend variants (X11/Wayland/GBM)
|
#[cfg(feature = "backend_gbm")]
|
||||||
pub trait Backend {
|
use gbm::{AsRaw, Device as GbmDevice};
|
||||||
/// Surface type created by this backend
|
|
||||||
type Surface: NativeSurface<Error = Self::Error>;
|
|
||||||
/// Error type thrown by the surface creation in case of failure.
|
|
||||||
type Error: ::std::error::Error + Send + 'static;
|
|
||||||
|
|
||||||
/// Return an [`EGLDisplay`](ffi::egl::types::EGLDisplay) based on this backend
|
pub trait EGLNativeDisplay: Send {
|
||||||
///
|
fn required_extensions(&self) -> &'static [&'static str];
|
||||||
/// # Safety
|
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>);
|
||||||
///
|
|
||||||
/// 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<F: Fn(&str) -> bool>(
|
|
||||||
display: ffi::NativeDisplayType,
|
|
||||||
attribs: &[ffi::EGLint],
|
|
||||||
has_dp_extension: F,
|
|
||||||
log: ::slog::Logger,
|
|
||||||
) -> Result<ffi::egl::types::EGLDisplay, EGLError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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<F>(
|
|
||||||
display: ffi::NativeDisplayType,
|
|
||||||
attribs: &[ffi::EGLint],
|
|
||||||
has_dp_extension: F,
|
|
||||||
log: ::slog::Logger,
|
|
||||||
) -> Result<ffi::egl::types::EGLDisplay, EGLError>
|
|
||||||
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::<Vec<_>>();
|
|
||||||
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<F>(
|
|
||||||
display: ffi::NativeDisplayType,
|
|
||||||
attribs: &[ffi::EGLint],
|
|
||||||
has_dp_extension: F,
|
|
||||||
log: ::slog::Logger,
|
|
||||||
) -> Result<ffi::egl::types::EGLDisplay, EGLError>
|
|
||||||
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::<Vec<_>>();
|
|
||||||
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<B: Backend> {
|
|
||||||
/// 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<ffi::NativeDisplayType, Error>;
|
|
||||||
/// Return attributes that might be used by `B::get_display`
|
|
||||||
///
|
|
||||||
/// Default implementation returns an empty list
|
|
||||||
fn attributes(&self) -> Vec<ffi::EGLint> {
|
|
||||||
vec![ffi::egl::NONE as ffi::EGLint]
|
|
||||||
}
|
|
||||||
/// Type of surfaces created
|
/// Type of surfaces created
|
||||||
fn surface_type(&self) -> ffi::EGLint {
|
fn surface_type(&self) -> ffi::EGLint {
|
||||||
ffi::egl::WINDOW_BIT as ffi::EGLint
|
ffi::egl::WINDOW_BIT as ffi::EGLint
|
||||||
}
|
}
|
||||||
/// Create a surface
|
|
||||||
fn create_surface(&mut self, args: Self::Arguments) -> Result<B::Surface, B::Error>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_gbm")]
|
||||||
unsafe impl NativeDisplay<X11> for WinitWindow {
|
impl<A: AsRawFd + Send + 'static> EGLNativeDisplay for GbmDevice<A> {
|
||||||
type Arguments = ();
|
fn required_extensions(&self) -> &'static [&'static str] {
|
||||||
|
&["EGL_MESA_platform_gbm"]
|
||||||
fn is_backend(&self) -> bool {
|
|
||||||
self.xlib_display().is_some()
|
|
||||||
}
|
}
|
||||||
|
fn platform_display(&self) -> (ffi::egl::types::EGLenum, *mut c_void, Vec<ffi::EGLint>) {
|
||||||
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
|
(ffi::egl::PLATFORM_GBM_MESA, self.as_raw() as *mut _, vec![ffi::egl::NONE as ffi::EGLint])
|
||||||
self.xlib_display()
|
|
||||||
.map(|ptr| ptr as *const _)
|
|
||||||
.ok_or(Error::NonMatchingBackend("X11"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_surface(&mut self, _args: ()) -> Result<XlibWindow, Error> {
|
|
||||||
self.xlib_window()
|
|
||||||
.map(XlibWindow)
|
|
||||||
.ok_or(Error::NonMatchingBackend("X11"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
unsafe impl NativeDisplay<Wayland> for WinitWindow {
|
impl EGLNativeDisplay for WinitWindow {
|
||||||
type Arguments = ();
|
fn required_extensions(&self) -> &'static [&'static str] {
|
||||||
|
if self.wayland_display().is_some() {
|
||||||
fn is_backend(&self) -> bool {
|
&["EGL_EXT_platform_wayland"]
|
||||||
self.wayland_display().is_some()
|
} else if self.xlib_display().is_some() {
|
||||||
}
|
&["EGL_EXT_platform_x11"]
|
||||||
|
|
||||||
fn ptr(&self) -> Result<ffi::NativeDisplayType, Error> {
|
|
||||||
self.wayland_display()
|
|
||||||
.map(|ptr| ptr as *const _)
|
|
||||||
.ok_or(Error::NonMatchingBackend("Wayland"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_surface(&mut self, _args: ()) -> Result<wegl::WlEglSurface, Error> {
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
} else {
|
} 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<ffi::EGLint>) {
|
||||||
|
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<Wayland> for WinitWindow {
|
||||||
///
|
///
|
||||||
/// The returned [`NativeWindowType`](ffi::NativeWindowType) must be valid for EGL
|
/// The returned [`NativeWindowType`](ffi::NativeWindowType) must be valid for EGL
|
||||||
/// and there is no way to test that.
|
/// 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.
|
/// 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.
|
/// Create an EGLSurface from the internal native type.
|
||||||
///
|
///
|
||||||
/// Must be able to deal with re-creation of existing resources,
|
/// Must be able to deal with re-creation of existing resources,
|
||||||
/// if `needs_recreation` can return `true`.
|
/// if `needs_recreation` can return `true`.
|
||||||
///
|
///
|
||||||
/// # Safety
|
fn create(
|
||||||
/// This is usually an unsafe operation returning a raw pointer.
|
|
||||||
unsafe fn create(
|
|
||||||
&self,
|
&self,
|
||||||
display: &Arc<EGLDisplayHandle>,
|
display: &Arc<EGLDisplayHandle>,
|
||||||
config_id: ffi::egl::types::EGLConfig,
|
config_id: ffi::egl::types::EGLConfig,
|
||||||
surface_attributes: &[c_int],
|
surface_attributes: &[c_int],
|
||||||
) -> Result<*const c_void, SurfaceCreationError<Self::Error>>;
|
) -> Result<*const c_void, super::EGLError>;
|
||||||
|
|
||||||
/// Will be called to check if any internal resources will need
|
/// Will be called to check if any internal resources will need
|
||||||
/// to be recreated. Old resources must be used until `create`
|
/// to be recreated. Old resources must be used until `create`
|
||||||
|
@ -230,6 +90,19 @@ pub unsafe trait NativeSurface {
|
||||||
false
|
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
|
/// Adds additional semantics when calling
|
||||||
/// [EGLSurface::swap_buffers](::backend::egl::surface::EGLSurface::swap_buffers)
|
/// [EGLSurface::swap_buffers](::backend::egl::surface::EGLSurface::swap_buffers)
|
||||||
///
|
///
|
||||||
|
@ -238,7 +111,7 @@ pub unsafe trait NativeSurface {
|
||||||
&self,
|
&self,
|
||||||
display: &Arc<EGLDisplayHandle>,
|
display: &Arc<EGLDisplayHandle>,
|
||||||
surface: ffi::egl::types::EGLSurface,
|
surface: ffi::egl::types::EGLSurface,
|
||||||
) -> Result<(), SwapBuffersError<Self::Error>> {
|
) -> Result<(), SwapBuffersError> {
|
||||||
wrap_egl_call(|| unsafe {
|
wrap_egl_call(|| unsafe {
|
||||||
ffi::egl::SwapBuffers(***display, surface as *const _);
|
ffi::egl::SwapBuffers(***display, surface as *const _);
|
||||||
})
|
})
|
||||||
|
@ -247,45 +120,49 @@ pub unsafe trait NativeSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
unsafe impl NativeSurface for XlibWindow {
|
/// Typed Xlib window for the `X11` backend
|
||||||
type Error = Error;
|
pub struct XlibWindow(pub u64);
|
||||||
|
|
||||||
unsafe fn create(
|
#[cfg(feature = "backend_winit")]
|
||||||
|
unsafe impl EGLNativeSurface for XlibWindow {
|
||||||
|
fn create(
|
||||||
&self,
|
&self,
|
||||||
display: &Arc<EGLDisplayHandle>,
|
display: &Arc<EGLDisplayHandle>,
|
||||||
config_id: ffi::egl::types::EGLConfig,
|
config_id: ffi::egl::types::EGLConfig,
|
||||||
surface_attributes: &[c_int],
|
surface_attributes: &[c_int],
|
||||||
) -> Result<*const c_void, SurfaceCreationError<Error>> {
|
) -> Result<*const c_void, super::EGLError> {
|
||||||
wrap_egl_call(|| {
|
wrap_egl_call(|| unsafe {
|
||||||
ffi::egl::CreateWindowSurface(
|
let mut id = self.0;
|
||||||
|
ffi::egl::CreatePlatformWindowSurfaceEXT(
|
||||||
display.handle,
|
display.handle,
|
||||||
config_id,
|
config_id,
|
||||||
self.0 as *const _,
|
(&mut id) as *mut u64 as *mut _,
|
||||||
surface_attributes.as_ptr(),
|
surface_attributes.as_ptr(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map_err(SurfaceCreationError::EGLSurfaceCreationFailed)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
unsafe impl NativeSurface for wegl::WlEglSurface {
|
unsafe impl EGLNativeSurface for wegl::WlEglSurface {
|
||||||
type Error = Error;
|
fn create(
|
||||||
|
|
||||||
unsafe fn create(
|
|
||||||
&self,
|
&self,
|
||||||
display: &Arc<EGLDisplayHandle>,
|
display: &Arc<EGLDisplayHandle>,
|
||||||
config_id: ffi::egl::types::EGLConfig,
|
config_id: ffi::egl::types::EGLConfig,
|
||||||
surface_attributes: &[c_int],
|
surface_attributes: &[c_int],
|
||||||
) -> Result<*const c_void, SurfaceCreationError<Error>> {
|
) -> Result<*const c_void, super::EGLError> {
|
||||||
wrap_egl_call(|| {
|
wrap_egl_call(|| unsafe {
|
||||||
ffi::egl::CreateWindowSurface(
|
ffi::egl::CreatePlatformWindowSurfaceEXT(
|
||||||
display.handle,
|
display.handle,
|
||||||
config_id,
|
config_id,
|
||||||
self.ptr() as *const _,
|
self.ptr() as *mut _,
|
||||||
surface_attributes.as_ptr(),
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
//! EGL surface related structs
|
//! 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::{
|
use std::sync::{
|
||||||
atomic::{AtomicPtr, Ordering},
|
atomic::{AtomicPtr, Ordering},
|
||||||
Arc,
|
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
|
/// EGL surface of a given EGL context for rendering
|
||||||
#[derive(Debug)]
|
pub struct EGLSurface {
|
||||||
pub struct EGLSurface<N: native::NativeSurface> {
|
|
||||||
pub(crate) display: Arc<EGLDisplayHandle>,
|
pub(crate) display: Arc<EGLDisplayHandle>,
|
||||||
native: N,
|
native: Box<dyn EGLNativeSurface + Send + 'static>,
|
||||||
pub(crate) surface: AtomicPtr<nix::libc::c_void>,
|
pub(crate) surface: AtomicPtr<nix::libc::c_void>,
|
||||||
config_id: ffi::egl::types::EGLConfig,
|
config_id: ffi::egl::types::EGLConfig,
|
||||||
pixel_format: PixelFormat,
|
pixel_format: PixelFormat,
|
||||||
|
@ -23,32 +26,19 @@ pub struct EGLSurface<N: native::NativeSurface> {
|
||||||
}
|
}
|
||||||
// safe because EGLConfig can be moved between threads
|
// safe because EGLConfig can be moved between threads
|
||||||
// and the other types are thread-safe
|
// and the other types are thread-safe
|
||||||
unsafe impl<N: native::NativeSurface + Send> Send for EGLSurface<N> {}
|
unsafe impl Send for EGLSurface {}
|
||||||
unsafe impl<N: native::NativeSurface + Send + Sync> Sync for EGLSurface<N> {}
|
|
||||||
|
|
||||||
impl<N: native::NativeSurface> Deref for EGLSurface<N> {
|
impl EGLSurface {
|
||||||
type Target = N;
|
pub fn new<N, L>(
|
||||||
fn deref(&self) -> &N {
|
display: &EGLDisplay,
|
||||||
&self.native
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: native::NativeSurface> DerefMut for EGLSurface<N> {
|
|
||||||
fn deref_mut(&mut self) -> &mut N {
|
|
||||||
&mut self.native
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: native::NativeSurface> EGLSurface<N> {
|
|
||||||
pub(crate) fn new<L>(
|
|
||||||
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,
|
||||||
native: N,
|
native: N,
|
||||||
log: L,
|
log: L,
|
||||||
) -> Result<EGLSurface<N>, SurfaceCreationError<N::Error>>
|
) -> Result<EGLSurface, EGLError>
|
||||||
where
|
where
|
||||||
|
N: EGLNativeSurface + Send + 'static,
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
{
|
{
|
||||||
let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "renderer_egl"));
|
let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "renderer_egl"));
|
||||||
|
@ -74,17 +64,15 @@ impl<N: native::NativeSurface> EGLSurface<N> {
|
||||||
out
|
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 {
|
if surface == ffi::egl::NO_SURFACE {
|
||||||
return Err(SurfaceCreationError::EGLSurfaceCreationFailed(
|
return Err(EGLError::BadSurface);
|
||||||
EGLError::BadSurface,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(EGLSurface {
|
Ok(EGLSurface {
|
||||||
display,
|
display: display.display.clone(),
|
||||||
native,
|
native: Box::new(native),
|
||||||
surface: AtomicPtr::new(surface as *mut _),
|
surface: AtomicPtr::new(surface as *mut _),
|
||||||
config_id: config,
|
config_id: config,
|
||||||
pixel_format,
|
pixel_format,
|
||||||
|
@ -94,7 +82,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Swaps buffers at the end of a frame.
|
/// Swaps buffers at the end of a frame.
|
||||||
pub fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError<N::Error>> {
|
pub fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||||
let surface = self.surface.load(Ordering::SeqCst);
|
let surface = self.surface.load(Ordering::SeqCst);
|
||||||
|
|
||||||
let result = if !surface.is_null() {
|
let result = if !surface.is_null() {
|
||||||
|
@ -115,14 +103,7 @@ impl<N: native::NativeSurface> EGLSurface<N> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.native
|
self.native
|
||||||
.create(&self.display, self.config_id, &self.surface_attributes)
|
.create(&self.display, self.config_id, &self.surface_attributes)
|
||||||
.map_err(|err| match err {
|
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _
|
||||||
SurfaceCreationError::EGLSurfaceCreationFailed(err) => {
|
|
||||||
SwapBuffersError::EGLCreateWindowSurface(err)
|
|
||||||
}
|
|
||||||
SurfaceCreationError::NativeSurfaceCreationFailed(err) => {
|
|
||||||
SwapBuffersError::Underlying(err)
|
|
||||||
}
|
|
||||||
})? as *mut _
|
|
||||||
},
|
},
|
||||||
Ordering::SeqCst,
|
Ordering::SeqCst,
|
||||||
);
|
);
|
||||||
|
@ -151,17 +132,30 @@ impl<N: native::NativeSurface> EGLSurface<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the egl config for this context
|
/// 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
|
self.config_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the pixel format of the main framebuffer of the context.
|
/// 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
|
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<N: native::NativeSurface> Drop for EGLSurface<N> {
|
impl Drop for EGLSurface {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
ffi::egl::DestroySurface(**self.display, *self.surface.get_mut() as *const _);
|
ffi::egl::DestroySurface(**self.display, *self.surface.get_mut() as *const _);
|
||||||
|
|
Loading…
Reference in New Issue