Merge pull request #332 from Smithay/fix/egl_visibility

This commit is contained in:
Victor Brekenfeld 2021-07-11 10:31:36 +02:00 committed by GitHub
commit aa647c636e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 168 additions and 76 deletions

View File

@ -14,12 +14,14 @@ rand = "0.7"
slog = { version = "2.1.1" } slog = { version = "2.1.1" }
slog-term = "2.8" slog-term = "2.8"
slog-async = "2.2" slog-async = "2.2"
slog-stdlog = "4.1.0"
slog-scope = "4.4.0"
xkbcommon = "0.4.0" xkbcommon = "0.4.0"
[dependencies.smithay] [dependencies.smithay]
path = ".." path = ".."
default-features = false default-features = false
features = [ "renderer_gl", "backend_egl", "wayland_frontend" ] features = [ "renderer_gl", "backend_egl", "wayland_frontend", "slog-stdlog" ]
[dependencies.x11rb] [dependencies.x11rb]
optional = true optional = true

View File

@ -44,6 +44,8 @@ fn main() {
//std::sync::Mutex::new(slog_term::term_full().fuse()).fuse(), //std::sync::Mutex::new(slog_term::term_full().fuse()).fuse(),
o!(), o!(),
); );
let _guard = slog_scope::set_global_logger(log.clone());
slog_stdlog::init().expect("Could not setup log backend");
let arg = ::std::env::args().nth(1); let arg = ::std::env::args().nth(1);
match arg.as_ref().map(|s| &s[..]) { match arg.as_ref().map(|s| &s[..]) {

View File

@ -441,10 +441,13 @@ impl AnvilState<UdevData> {
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
if path.canonicalize().ok() == self.backend_data.primary_gpu { if path.canonicalize().ok() == self.backend_data.primary_gpu {
info!(self.log, "Initializing EGL Hardware Acceleration via {:?}", path); info!(self.log, "Initializing EGL Hardware Acceleration via {:?}", path);
renderer if renderer
.borrow_mut() .borrow_mut()
.bind_wl_display(&*self.display.borrow()) .bind_wl_display(&*self.display.borrow())
.expect("Unable to bind Wl Display?"); .is_ok()
{
info!(self.log, "EGL hardware-acceleration enabled");
}
} }
let backends = Rc::new(RefCell::new(scan_connectors( let backends = Rc::new(RefCell::new(scan_connectors(

View File

@ -300,9 +300,6 @@ pub struct PixelFormatRequirements {
pub depth_bits: Option<u8>, pub depth_bits: Option<u8>,
/// Minimum number of bits for the depth buffer. `None` means "don't care". The default value is `None`. /// Minimum number of bits for the depth buffer. `None` means "don't care". The default value is `None`.
pub stencil_bits: Option<u8>, pub stencil_bits: Option<u8>,
/// If `true`, only double-buffered formats will be considered. If `false`, only single-buffer formats.
/// `None` means "don't care". The default is `None`.
pub double_buffer: Option<bool>,
/// Contains the minimum number of samples per pixel in the color, depth and stencil buffers. /// Contains the minimum number of samples per pixel in the color, depth and stencil buffers.
/// `None` means "don't care". Default is `None`. A value of `Some(0)` indicates that multisampling must not be enabled. /// `None` means "don't care". Default is `None`. A value of `Some(0)` indicates that multisampling must not be enabled.
pub multisampling: Option<u16>, pub multisampling: Option<u16>,
@ -317,7 +314,6 @@ impl Default for PixelFormatRequirements {
alpha_bits: Some(8), alpha_bits: Some(8),
depth_bits: Some(24), depth_bits: Some(24),
stencil_bits: Some(8), stencil_bits: Some(8),
double_buffer: Some(true),
multisampling: None, multisampling: None,
} }
} }

View File

@ -75,24 +75,9 @@ pub struct EGLDisplay {
fn select_platform_display<N: EGLNativeDisplay + 'static>( fn select_platform_display<N: EGLNativeDisplay + 'static>(
native: &N, native: &N,
dp_extensions: &[String],
log: &::slog::Logger, log: &::slog::Logger,
) -> Result<*const c_void, Error> { ) -> Result<*const c_void, Error> {
let dp_extensions = unsafe {
let p = wrap_egl_call(|| ffi::egl::QueryString(ffi::egl::NO_DISPLAY, ffi::egl::EXTENSIONS as i32))
.map_err(Error::InitFailed)?; //TODO EGL_EXT_client_extensions not supported
// this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise
// `eglQueryString` returns an error
if p.is_null() {
return Err(Error::EglExtensionNotSupported(&["EGL_EXT_platform_base"]));
} else {
let p = CStr::from_ptr(p);
let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new());
list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
}
};
debug!(log, "Supported EGL client extensions: {:?}", dp_extensions);
for platform in native.supported_platforms() { for platform in native.supported_platforms() {
debug!(log, "Trying EGL platform: {}", platform.platform_name); debug!(log, "Trying EGL platform: {}", platform.platform_name);
@ -160,10 +145,11 @@ impl EGLDisplay {
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
let log = crate::slog_or_fallback(logger.into()).new(o!("smithay_module" => "backend_egl")); let log = crate::slog_or_fallback(logger.into()).new(o!("smithay_module" => "backend_egl"));
ffi::make_sure_egl_is_loaded();
let dp_extensions = ffi::make_sure_egl_is_loaded()?;
debug!(log, "Supported EGL client extensions: {:?}", dp_extensions);
// we create an EGLDisplay // we create an EGLDisplay
let display = select_platform_display(native, &log)?; let display = select_platform_display(native, &dp_extensions, &log)?;
// We can then query the egl api version // We can then query the egl api version
let egl_version = { let egl_version = {
@ -403,6 +389,11 @@ impl EGLDisplay {
Ok((desc, config_id)) Ok((desc, config_id))
} }
/// Get a handle to the underlying native EGLDisplay
pub fn get_display_handle(&self) -> Arc<EGLDisplayHandle> {
self.display.clone()
}
/// 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

View File

@ -127,7 +127,7 @@ impl From<u32> for EGLError {
} }
impl EGLError { impl EGLError {
fn from_last_call() -> Result<(), EGLError> { pub(super) fn from_last_call() -> Result<(), EGLError> {
match unsafe { ffi::egl::GetError() as u32 } { match unsafe { ffi::egl::GetError() as u32 } {
ffi::egl::SUCCESS => Ok(()), ffi::egl::SUCCESS => Ok(()),
x => Err(EGLError::from(x)), x => Err(EGLError::from(x)),

View File

@ -1,11 +1,14 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use super::Error;
use nix::libc::{c_long, c_uint, c_void}; use nix::libc::{c_long, c_uint, c_void};
pub type khronos_utime_nanoseconds_t = khronos_uint64_t; pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
pub type khronos_uint64_t = u64; pub type khronos_uint64_t = u64;
pub type khronos_ssize_t = c_long; pub type khronos_ssize_t = c_long;
pub type EGLint = i32; pub type EGLint = i32;
pub type EGLchar = char;
pub type EGLLabelKHR = *const c_void;
pub type EGLNativeDisplayType = NativeDisplayType; pub type EGLNativeDisplayType = NativeDisplayType;
pub type EGLNativePixmapType = NativePixmapType; pub type EGLNativePixmapType = NativePixmapType;
pub type EGLNativeWindowType = NativeWindowType; pub type EGLNativeWindowType = NativeWindowType;
@ -13,17 +16,46 @@ pub type NativeDisplayType = *const c_void;
pub type NativePixmapType = *const c_void; pub type NativePixmapType = *const c_void;
pub type NativeWindowType = *const c_void; pub type NativeWindowType = *const c_void;
pub fn make_sure_egl_is_loaded() { extern "system" fn egl_debug_log(
use std::{ffi::CString, ptr}; severity: egl::types::EGLenum,
command: *const EGLchar,
_id: EGLint,
_thread: EGLLabelKHR,
_obj: EGLLabelKHR,
message: *const EGLchar,
) {
let _ = std::panic::catch_unwind(move || unsafe {
let msg = std::ffi::CStr::from_ptr(message as *const _);
let message_utf8 = msg.to_string_lossy();
let cmd = std::ffi::CStr::from_ptr(command as *const _);
let command_utf8 = cmd.to_string_lossy();
let logger = crate::slog_or_fallback(None).new(slog::o!("backend" => "egl"));
match severity {
egl::DEBUG_MSG_CRITICAL_KHR | egl::DEBUG_MSG_ERROR_KHR => {
slog::error!(logger, "[EGL] {}: {}", command_utf8, message_utf8)
}
egl::DEBUG_MSG_WARN_KHR => slog::warn!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
egl::DEBUG_MSG_INFO_KHR => slog::info!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
_ => slog::debug!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
};
});
}
pub fn make_sure_egl_is_loaded() -> Result<Vec<String>, Error> {
use std::{
ffi::{CStr, CString},
ptr,
};
egl::LOAD.call_once(|| unsafe {
fn constrain<F>(f: F) -> F fn constrain<F>(f: F) -> F
where where
F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void, F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void,
{ {
f f
} }
let proc_address = constrain(|sym| unsafe { super::get_proc_address(sym) });
egl::LOAD.call_once(|| unsafe {
egl::load_with(|sym| { egl::load_with(|sym| {
let name = CString::new(sym).unwrap(); let name = CString::new(sym).unwrap();
let symbol = egl::LIB.get::<*mut c_void>(name.as_bytes()); let symbol = egl::LIB.get::<*mut c_void>(name.as_bytes());
@ -32,14 +64,47 @@ pub fn make_sure_egl_is_loaded() {
Err(_) => ptr::null(), Err(_) => ptr::null(),
} }
}); });
let proc_address = constrain(|sym| super::get_proc_address(sym));
egl::load_with(&proc_address); egl::load_with(&proc_address);
egl::BindWaylandDisplayWL::load_with(&proc_address); egl::BindWaylandDisplayWL::load_with(&proc_address);
egl::UnbindWaylandDisplayWL::load_with(&proc_address); egl::UnbindWaylandDisplayWL::load_with(&proc_address);
egl::QueryWaylandBufferWL::load_with(&proc_address); egl::QueryWaylandBufferWL::load_with(&proc_address);
#[cfg(feature = "backend_drm_eglstream")] egl::DebugMessageControlKHR::load_with(&proc_address);
egl::StreamConsumerAcquireAttribNV::load_with(&proc_address);
}); });
let extensions = unsafe {
let p = super::wrap_egl_call(|| egl::QueryString(egl::NO_DISPLAY, egl::EXTENSIONS as i32))
.map_err(Error::InitFailed)?; //TODO EGL_EXT_client_extensions not supported
// this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise
// `eglQueryString` returns an error
if p.is_null() {
return Err(Error::EglExtensionNotSupported(&["EGL_EXT_platform_base"]));
} else {
let p = CStr::from_ptr(p);
let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new());
list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
}
};
egl::DEBUG.call_once(|| unsafe {
if extensions.iter().any(|ext| ext == "EGL_KHR_debug") {
let debug_attribs = [
egl::DEBUG_MSG_CRITICAL_KHR as isize,
egl::TRUE as isize,
egl::DEBUG_MSG_ERROR_KHR as isize,
egl::TRUE as isize,
egl::DEBUG_MSG_WARN_KHR as isize,
egl::TRUE as isize,
egl::DEBUG_MSG_INFO_KHR as isize,
egl::TRUE as isize,
egl::NONE as isize,
];
// we do not check for success, because there is not much we can do otherwise.
egl::DebugMessageControlKHR(Some(egl_debug_log), debug_attribs.as_ptr());
}
});
Ok(extensions)
} }
#[allow(clippy::all, missing_debug_implementations)] #[allow(clippy::all, missing_debug_implementations)]
@ -53,9 +118,40 @@ pub mod egl {
} }
pub static LOAD: Once = Once::new(); pub static LOAD: Once = Once::new();
pub static DEBUG: Once = Once::new();
include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));
type EGLDEBUGPROCKHR = Option<
extern "system" fn(
_error: egl::types::EGLenum,
command: *const EGLchar,
_id: EGLint,
_thread: EGLLabelKHR,
_obj: EGLLabelKHR,
message: *const EGLchar,
),
>;
#[allow(dead_code, non_upper_case_globals)]
pub const DEBUG_MSG_CRITICAL_KHR: types::EGLenum = 0x33B9;
#[allow(dead_code, non_upper_case_globals)]
pub const DEBUG_MSG_ERROR_KHR: types::EGLenum = 0x33BA;
#[allow(dead_code, non_upper_case_globals)]
pub const DEBUG_MSG_INFO_KHR: types::EGLenum = 0x33BC;
#[allow(dead_code, non_upper_case_globals)]
pub const DEBUG_MSG_WARN_KHR: types::EGLenum = 0x33BB;
#[allow(non_snake_case, unused_variables, dead_code)]
#[inline]
pub unsafe fn DebugMessageControlKHR(
callback: EGLDEBUGPROCKHR,
attrib_list: *const types::EGLAttrib,
) -> types::EGLint {
__gl_imports::mem::transmute::<
_,
extern "system" fn(EGLDEBUGPROCKHR, *const types::EGLAttrib) -> types::EGLint,
>(wayland_storage::DebugMessageControlKHR.f)(callback, attrib_list)
}
/* /*
* `gl_generator` cannot generate bindings for the `EGL_WL_bind_wayland_display` extension. * `gl_generator` cannot generate bindings for the `EGL_WL_bind_wayland_display` extension.
* Lets do it ourselves... * Lets do it ourselves...
@ -118,6 +214,34 @@ pub mod egl {
f: super::missing_fn_panic as *const raw::c_void, f: super::missing_fn_panic as *const raw::c_void,
is_loaded: false, is_loaded: false,
}; };
pub static mut DebugMessageControlKHR: FnPtr = FnPtr {
f: super::missing_fn_panic as *const raw::c_void,
is_loaded: false,
};
}
#[allow(non_snake_case)]
pub mod DebugMessageControlKHR {
use super::FnPtr;
use super::__gl_imports::raw;
use super::{metaloadfn, wayland_storage};
#[inline]
#[allow(dead_code)]
pub fn is_loaded() -> bool {
unsafe { wayland_storage::DebugMessageControlKHR.is_loaded }
}
#[allow(dead_code)]
pub fn load_with<F>(mut loadfn: F)
where
F: FnMut(&'static str) -> *const raw::c_void,
{
unsafe {
wayland_storage::DebugMessageControlKHR =
FnPtr::new(metaloadfn(&mut loadfn, "eglDebugMessageControlKHR", &[]))
}
}
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]

View File

@ -182,7 +182,6 @@ pub unsafe trait EGLNativeSurface: Send + Sync {
&self, &self,
display: &Arc<EGLDisplayHandle>, display: &Arc<EGLDisplayHandle>,
config_id: ffi::egl::types::EGLConfig, config_id: ffi::egl::types::EGLConfig,
surface_attributes: &[c_int],
) -> Result<*const c_void, super::EGLError>; ) -> 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
@ -224,6 +223,13 @@ pub unsafe trait EGLNativeSurface: Send + Sync {
} }
} }
#[cfg(feature = "backend_winit")]
static WINIT_SURFACE_ATTRIBUTES: [c_int; 3] = [
ffi::egl::RENDER_BUFFER as c_int,
ffi::egl::BACK_BUFFER as c_int,
ffi::egl::NONE as c_int,
];
#[cfg(feature = "backend_winit")] #[cfg(feature = "backend_winit")]
/// Typed Xlib window for the `X11` backend /// Typed Xlib window for the `X11` backend
#[derive(Debug)] #[derive(Debug)]
@ -235,7 +241,6 @@ unsafe impl EGLNativeSurface for XlibWindow {
&self, &self,
display: &Arc<EGLDisplayHandle>, display: &Arc<EGLDisplayHandle>,
config_id: ffi::egl::types::EGLConfig, config_id: ffi::egl::types::EGLConfig,
surface_attributes: &[c_int],
) -> Result<*const c_void, super::EGLError> { ) -> Result<*const c_void, super::EGLError> {
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
let mut id = self.0; let mut id = self.0;
@ -243,7 +248,7 @@ unsafe impl EGLNativeSurface for XlibWindow {
display.handle, display.handle,
config_id, config_id,
(&mut id) as *mut std::os::raw::c_ulong as *mut _, (&mut id) as *mut std::os::raw::c_ulong as *mut _,
surface_attributes.as_ptr(), WINIT_SURFACE_ATTRIBUTES.as_ptr(),
) )
}) })
} }
@ -255,14 +260,13 @@ unsafe impl EGLNativeSurface for wegl::WlEglSurface {
&self, &self,
display: &Arc<EGLDisplayHandle>, display: &Arc<EGLDisplayHandle>,
config_id: ffi::egl::types::EGLConfig, config_id: ffi::egl::types::EGLConfig,
surface_attributes: &[c_int],
) -> Result<*const c_void, super::EGLError> { ) -> Result<*const c_void, super::EGLError> {
wrap_egl_call(|| unsafe { wrap_egl_call(|| unsafe {
ffi::egl::CreatePlatformWindowSurfaceEXT( ffi::egl::CreatePlatformWindowSurfaceEXT(
display.handle, display.handle,
config_id, config_id,
self.ptr() as *mut _, self.ptr() as *mut _,
surface_attributes.as_ptr(), WINIT_SURFACE_ATTRIBUTES.as_ptr(),
) )
}) })
} }

View File

@ -6,8 +6,6 @@ use std::sync::{
Arc, Arc,
}; };
use nix::libc::c_int;
use crate::backend::egl::{ use crate::backend::egl::{
display::{EGLDisplay, EGLDisplayHandle, PixelFormat}, display::{EGLDisplay, EGLDisplayHandle, PixelFormat},
ffi, ffi,
@ -15,7 +13,7 @@ use crate::backend::egl::{
EGLError, SwapBuffersError, EGLError, SwapBuffersError,
}; };
use slog::{debug, o, trace}; use slog::{debug, o};
/// EGL surface of a given EGL context for rendering /// EGL surface of a given EGL context for rendering
pub struct EGLSurface { pub struct EGLSurface {
@ -24,7 +22,6 @@ pub struct EGLSurface {
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,
surface_attributes: Vec<c_int>,
logger: ::slog::Logger, logger: ::slog::Logger,
} }
@ -36,7 +33,6 @@ impl fmt::Debug for EGLSurface {
.field("surface", &self.surface) .field("surface", &self.surface)
.field("config_id", &self.config_id) .field("config_id", &self.config_id)
.field("pixel_format", &self.pixel_format) .field("pixel_format", &self.pixel_format)
.field("surface_attributes", &self.surface_attributes)
.field("logger", &self.logger) .field("logger", &self.logger)
.finish() .finish()
} }
@ -58,7 +54,6 @@ impl EGLSurface {
pub fn new<N, L>( pub fn new<N, L>(
display: &EGLDisplay, display: &EGLDisplay,
pixel_format: PixelFormat, pixel_format: PixelFormat,
double_buffered: Option<bool>,
config: ffi::egl::types::EGLConfig, config: ffi::egl::types::EGLConfig,
native: N, native: N,
log: L, log: L,
@ -69,29 +64,7 @@ impl EGLSurface {
{ {
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"));
let surface_attributes = { let surface = native.create(&display.display, config)?;
let mut out: Vec<c_int> = Vec::with_capacity(3);
match double_buffered {
Some(true) => {
trace!(log, "Setting RENDER_BUFFER to BACK_BUFFER");
out.push(ffi::egl::RENDER_BUFFER as c_int);
out.push(ffi::egl::BACK_BUFFER as c_int);
}
Some(false) => {
trace!(log, "Setting RENDER_BUFFER to SINGLE_BUFFER");
out.push(ffi::egl::RENDER_BUFFER as c_int);
out.push(ffi::egl::SINGLE_BUFFER as c_int);
}
None => {}
}
out.push(ffi::egl::NONE as i32);
out
};
let surface = native.create(&display.display, config, &surface_attributes)?;
if surface == ffi::egl::NO_SURFACE { if surface == ffi::egl::NO_SURFACE {
return Err(EGLError::BadSurface); return Err(EGLError::BadSurface);
} }
@ -102,7 +75,6 @@ impl EGLSurface {
surface: AtomicPtr::new(surface as *mut _), surface: AtomicPtr::new(surface as *mut _),
config_id: config, config_id: config,
pixel_format, pixel_format,
surface_attributes,
logger: log, logger: log,
}) })
} }
@ -129,7 +101,7 @@ impl EGLSurface {
.compare_exchange( .compare_exchange(
surface, surface,
self.native self.native
.create(&self.display, self.config_id, &self.surface_attributes) .create(&self.display, self.config_id)
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _, .map_err(SwapBuffersError::EGLCreateSurface)? as *mut _,
Ordering::SeqCst, Ordering::SeqCst,
Ordering::SeqCst, Ordering::SeqCst,

View File

@ -172,7 +172,6 @@ where
EGLSurface::new( EGLSurface::new(
&display, &display,
context.pixel_format().unwrap(), context.pixel_format().unwrap(),
reqs.double_buffer,
context.config_id(), context.config_id(),
surface, surface,
log.clone(), log.clone(),
@ -183,7 +182,6 @@ where
EGLSurface::new( EGLSurface::new(
&display, &display,
context.pixel_format().unwrap(), context.pixel_format().unwrap(),
reqs.double_buffer,
context.config_id(), context.config_id(),
xlib_window, xlib_window,
log.clone(), log.clone(),