Merge pull request #332 from Smithay/fix/egl_visibility
This commit is contained in:
commit
aa647c636e
|
@ -14,12 +14,14 @@ rand = "0.7"
|
|||
slog = { version = "2.1.1" }
|
||||
slog-term = "2.8"
|
||||
slog-async = "2.2"
|
||||
slog-stdlog = "4.1.0"
|
||||
slog-scope = "4.4.0"
|
||||
xkbcommon = "0.4.0"
|
||||
|
||||
[dependencies.smithay]
|
||||
path = ".."
|
||||
default-features = false
|
||||
features = [ "renderer_gl", "backend_egl", "wayland_frontend" ]
|
||||
features = [ "renderer_gl", "backend_egl", "wayland_frontend", "slog-stdlog" ]
|
||||
|
||||
[dependencies.x11rb]
|
||||
optional = true
|
||||
|
|
|
@ -44,6 +44,8 @@ fn main() {
|
|||
//std::sync::Mutex::new(slog_term::term_full().fuse()).fuse(),
|
||||
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);
|
||||
match arg.as_ref().map(|s| &s[..]) {
|
||||
|
|
|
@ -441,10 +441,13 @@ impl AnvilState<UdevData> {
|
|||
#[cfg(feature = "egl")]
|
||||
if path.canonicalize().ok() == self.backend_data.primary_gpu {
|
||||
info!(self.log, "Initializing EGL Hardware Acceleration via {:?}", path);
|
||||
renderer
|
||||
if renderer
|
||||
.borrow_mut()
|
||||
.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(
|
||||
|
|
|
@ -300,9 +300,6 @@ pub struct PixelFormatRequirements {
|
|||
pub depth_bits: Option<u8>,
|
||||
/// Minimum number of bits for the depth buffer. `None` means "don't care". The default value is `None`.
|
||||
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.
|
||||
/// `None` means "don't care". Default is `None`. A value of `Some(0)` indicates that multisampling must not be enabled.
|
||||
pub multisampling: Option<u16>,
|
||||
|
@ -317,7 +314,6 @@ impl Default for PixelFormatRequirements {
|
|||
alpha_bits: Some(8),
|
||||
depth_bits: Some(24),
|
||||
stencil_bits: Some(8),
|
||||
double_buffer: Some(true),
|
||||
multisampling: None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,24 +75,9 @@ pub struct EGLDisplay {
|
|||
|
||||
fn select_platform_display<N: EGLNativeDisplay + 'static>(
|
||||
native: &N,
|
||||
dp_extensions: &[String],
|
||||
log: &::slog::Logger,
|
||||
) -> 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() {
|
||||
debug!(log, "Trying EGL platform: {}", platform.platform_name);
|
||||
|
||||
|
@ -160,10 +145,11 @@ impl EGLDisplay {
|
|||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
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
|
||||
let display = select_platform_display(native, &log)?;
|
||||
let display = select_platform_display(native, &dp_extensions, &log)?;
|
||||
|
||||
// We can then query the egl api version
|
||||
let egl_version = {
|
||||
|
@ -403,6 +389,11 @@ impl EGLDisplay {
|
|||
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
|
||||
pub fn get_egl_version(&self) -> (i32, i32) {
|
||||
self.egl_version
|
||||
|
|
|
@ -127,7 +127,7 @@ impl From<u32> for EGLError {
|
|||
}
|
||||
|
||||
impl EGLError {
|
||||
fn from_last_call() -> Result<(), EGLError> {
|
||||
pub(super) fn from_last_call() -> Result<(), EGLError> {
|
||||
match unsafe { ffi::egl::GetError() as u32 } {
|
||||
ffi::egl::SUCCESS => Ok(()),
|
||||
x => Err(EGLError::from(x)),
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use super::Error;
|
||||
use nix::libc::{c_long, c_uint, c_void};
|
||||
|
||||
pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
|
||||
pub type khronos_uint64_t = u64;
|
||||
pub type khronos_ssize_t = c_long;
|
||||
pub type EGLint = i32;
|
||||
pub type EGLchar = char;
|
||||
pub type EGLLabelKHR = *const c_void;
|
||||
pub type EGLNativeDisplayType = NativeDisplayType;
|
||||
pub type EGLNativePixmapType = NativePixmapType;
|
||||
pub type EGLNativeWindowType = NativeWindowType;
|
||||
|
@ -13,17 +16,46 @@ pub type NativeDisplayType = *const c_void;
|
|||
pub type NativePixmapType = *const c_void;
|
||||
pub type NativeWindowType = *const c_void;
|
||||
|
||||
pub fn make_sure_egl_is_loaded() {
|
||||
use std::{ffi::CString, ptr};
|
||||
extern "system" fn egl_debug_log(
|
||||
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
|
||||
where
|
||||
F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void,
|
||||
{
|
||||
f
|
||||
}
|
||||
let proc_address = constrain(|sym| unsafe { super::get_proc_address(sym) });
|
||||
|
||||
egl::LOAD.call_once(|| unsafe {
|
||||
egl::load_with(|sym| {
|
||||
let name = CString::new(sym).unwrap();
|
||||
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(),
|
||||
}
|
||||
});
|
||||
let proc_address = constrain(|sym| super::get_proc_address(sym));
|
||||
egl::load_with(&proc_address);
|
||||
egl::BindWaylandDisplayWL::load_with(&proc_address);
|
||||
egl::UnbindWaylandDisplayWL::load_with(&proc_address);
|
||||
egl::QueryWaylandBufferWL::load_with(&proc_address);
|
||||
#[cfg(feature = "backend_drm_eglstream")]
|
||||
egl::StreamConsumerAcquireAttribNV::load_with(&proc_address);
|
||||
egl::DebugMessageControlKHR::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)]
|
||||
|
@ -53,9 +118,40 @@ pub mod egl {
|
|||
}
|
||||
|
||||
pub static LOAD: Once = Once::new();
|
||||
pub static DEBUG: Once = Once::new();
|
||||
|
||||
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.
|
||||
* Lets do it ourselves...
|
||||
|
@ -118,6 +214,34 @@ pub mod egl {
|
|||
f: super::missing_fn_panic as *const raw::c_void,
|
||||
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)]
|
||||
|
|
|
@ -182,7 +182,6 @@ pub unsafe trait EGLNativeSurface: Send + Sync {
|
|||
&self,
|
||||
display: &Arc<EGLDisplayHandle>,
|
||||
config_id: ffi::egl::types::EGLConfig,
|
||||
surface_attributes: &[c_int],
|
||||
) -> Result<*const c_void, super::EGLError>;
|
||||
|
||||
/// 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")]
|
||||
/// Typed Xlib window for the `X11` backend
|
||||
#[derive(Debug)]
|
||||
|
@ -235,7 +241,6 @@ unsafe impl EGLNativeSurface for XlibWindow {
|
|||
&self,
|
||||
display: &Arc<EGLDisplayHandle>,
|
||||
config_id: ffi::egl::types::EGLConfig,
|
||||
surface_attributes: &[c_int],
|
||||
) -> Result<*const c_void, super::EGLError> {
|
||||
wrap_egl_call(|| unsafe {
|
||||
let mut id = self.0;
|
||||
|
@ -243,7 +248,7 @@ unsafe impl EGLNativeSurface for XlibWindow {
|
|||
display.handle,
|
||||
config_id,
|
||||
(&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,
|
||||
display: &Arc<EGLDisplayHandle>,
|
||||
config_id: ffi::egl::types::EGLConfig,
|
||||
surface_attributes: &[c_int],
|
||||
) -> Result<*const c_void, super::EGLError> {
|
||||
wrap_egl_call(|| unsafe {
|
||||
ffi::egl::CreatePlatformWindowSurfaceEXT(
|
||||
display.handle,
|
||||
config_id,
|
||||
self.ptr() as *mut _,
|
||||
surface_attributes.as_ptr(),
|
||||
WINIT_SURFACE_ATTRIBUTES.as_ptr(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ use std::sync::{
|
|||
Arc,
|
||||
};
|
||||
|
||||
use nix::libc::c_int;
|
||||
|
||||
use crate::backend::egl::{
|
||||
display::{EGLDisplay, EGLDisplayHandle, PixelFormat},
|
||||
ffi,
|
||||
|
@ -15,7 +13,7 @@ use crate::backend::egl::{
|
|||
EGLError, SwapBuffersError,
|
||||
};
|
||||
|
||||
use slog::{debug, o, trace};
|
||||
use slog::{debug, o};
|
||||
|
||||
/// EGL surface of a given EGL context for rendering
|
||||
pub struct EGLSurface {
|
||||
|
@ -24,7 +22,6 @@ pub struct EGLSurface {
|
|||
pub(crate) surface: AtomicPtr<nix::libc::c_void>,
|
||||
config_id: ffi::egl::types::EGLConfig,
|
||||
pixel_format: PixelFormat,
|
||||
surface_attributes: Vec<c_int>,
|
||||
logger: ::slog::Logger,
|
||||
}
|
||||
|
||||
|
@ -36,7 +33,6 @@ impl fmt::Debug for EGLSurface {
|
|||
.field("surface", &self.surface)
|
||||
.field("config_id", &self.config_id)
|
||||
.field("pixel_format", &self.pixel_format)
|
||||
.field("surface_attributes", &self.surface_attributes)
|
||||
.field("logger", &self.logger)
|
||||
.finish()
|
||||
}
|
||||
|
@ -58,7 +54,6 @@ impl EGLSurface {
|
|||
pub fn new<N, L>(
|
||||
display: &EGLDisplay,
|
||||
pixel_format: PixelFormat,
|
||||
double_buffered: Option<bool>,
|
||||
config: ffi::egl::types::EGLConfig,
|
||||
native: N,
|
||||
log: L,
|
||||
|
@ -69,29 +64,7 @@ impl EGLSurface {
|
|||
{
|
||||
let log = crate::slog_or_fallback(log.into()).new(o!("smithay_module" => "renderer_egl"));
|
||||
|
||||
let surface_attributes = {
|
||||
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)?;
|
||||
|
||||
let surface = native.create(&display.display, config)?;
|
||||
if surface == ffi::egl::NO_SURFACE {
|
||||
return Err(EGLError::BadSurface);
|
||||
}
|
||||
|
@ -102,7 +75,6 @@ impl EGLSurface {
|
|||
surface: AtomicPtr::new(surface as *mut _),
|
||||
config_id: config,
|
||||
pixel_format,
|
||||
surface_attributes,
|
||||
logger: log,
|
||||
})
|
||||
}
|
||||
|
@ -129,7 +101,7 @@ impl EGLSurface {
|
|||
.compare_exchange(
|
||||
surface,
|
||||
self.native
|
||||
.create(&self.display, self.config_id, &self.surface_attributes)
|
||||
.create(&self.display, self.config_id)
|
||||
.map_err(SwapBuffersError::EGLCreateSurface)? as *mut _,
|
||||
Ordering::SeqCst,
|
||||
Ordering::SeqCst,
|
||||
|
|
|
@ -172,7 +172,6 @@ where
|
|||
EGLSurface::new(
|
||||
&display,
|
||||
context.pixel_format().unwrap(),
|
||||
reqs.double_buffer,
|
||||
context.config_id(),
|
||||
surface,
|
||||
log.clone(),
|
||||
|
@ -183,7 +182,6 @@ where
|
|||
EGLSurface::new(
|
||||
&display,
|
||||
context.pixel_format().unwrap(),
|
||||
reqs.double_buffer,
|
||||
context.config_id(),
|
||||
xlib_window,
|
||||
log.clone(),
|
||||
|
|
Loading…
Reference in New Issue