glutin/api/egl/
mod.rs

1//! EGL platform Api.
2//!
3//! This platform is typically available on Linux, Android and other Unix-like
4//! platforms.
5//!
6//! The EGL platform allows creating a [`Display`](self::display::Display) from
7//! a [`Device`](self::device::Device).
8
9use std::ffi::{self, CString};
10use std::ops::{Deref, DerefMut};
11
12use glutin_egl_sys::egl;
13
14use libloading::Library;
15use once_cell::sync::{Lazy, OnceCell};
16
17#[cfg(unix)]
18use libloading::os::unix as libloading_os;
19#[cfg(windows)]
20use libloading::os::windows as libloading_os;
21
22use crate::error::{Error, ErrorKind, Result};
23use crate::lib_loading::{SymLoading, SymWrapper};
24
25pub mod config;
26pub mod context;
27pub mod device;
28pub mod display;
29pub mod surface;
30
31// WARNING: If this implementation is ever changed to unload or replace the
32// library, note that public API functions currently retirm `&'static str`ings
33// out of it, which would become invalid.
34pub(crate) static EGL: Lazy<Option<Egl>> = Lazy::new(|| {
35    #[cfg(windows)]
36    let paths = ["libEGL.dll", "atioglxx.dll"];
37
38    #[cfg(not(windows))]
39    let paths = ["libEGL.so.1", "libEGL.so"];
40
41    unsafe { SymWrapper::new(&paths).map(Egl).ok() }
42});
43
44type EglGetProcAddress = unsafe extern "system" fn(*const ffi::c_void) -> *const ffi::c_void;
45static EGL_GET_PROC_ADDRESS: OnceCell<libloading_os::Symbol<EglGetProcAddress>> = OnceCell::new();
46
47/// EGL interface.
48#[allow(missing_debug_implementations)]
49pub struct Egl(SymWrapper<egl::Egl>);
50
51unsafe impl Sync for Egl {}
52unsafe impl Send for Egl {}
53
54impl SymLoading for egl::Egl {
55    unsafe fn load_with(lib: &Library) -> Self {
56        let loader = move |sym_name: &'static str| -> *const ffi::c_void {
57            unsafe {
58                let sym_name = CString::new(sym_name.as_bytes()).unwrap();
59                if let Ok(sym) = lib.get(sym_name.as_bytes_with_nul()) {
60                    return *sym;
61                }
62
63                let egl_proc_address = EGL_GET_PROC_ADDRESS.get_or_init(|| {
64                    let sym: libloading::Symbol<'_, EglGetProcAddress> =
65                        lib.get(b"eglGetProcAddress\0").unwrap();
66                    sym.into_raw()
67                });
68
69                // The symbol was not available in the library, so ask eglGetProcAddress for it.
70                // Note that eglGetProcAddress was only able to look up extension
71                // functions prior to EGL 1.5, hence this two-part dance.
72                (egl_proc_address)(sym_name.as_bytes_with_nul().as_ptr() as *const ffi::c_void)
73            }
74        };
75
76        egl::BindWaylandDisplayWL::load_with(loader);
77        egl::UnbindWaylandDisplayWL::load_with(loader);
78        egl::QueryWaylandBufferWL::load_with(loader);
79        egl::CreateWaylandBufferFromImageWL::load_with(loader);
80
81        Self::load_with(loader)
82    }
83}
84
85impl Deref for Egl {
86    type Target = egl::Egl;
87
88    fn deref(&self) -> &Self::Target {
89        &self.0
90    }
91}
92
93impl DerefMut for Egl {
94    fn deref_mut(&mut self) -> &mut Self::Target {
95        &mut self.0
96    }
97}
98
99/// Obtain the error from the EGL.
100fn check_error() -> Result<()> {
101    let egl = EGL.as_ref().unwrap();
102    unsafe {
103        let raw_code = egl.GetError() as egl::types::EGLenum;
104        let kind = match raw_code {
105            egl::SUCCESS => return Ok(()),
106            egl::NOT_INITIALIZED => ErrorKind::InitializationFailed,
107            egl::BAD_ACCESS => ErrorKind::BadAccess,
108            egl::BAD_ALLOC => ErrorKind::OutOfMemory,
109            egl::BAD_ATTRIBUTE => ErrorKind::BadAttribute,
110            egl::BAD_CONTEXT => ErrorKind::BadContext,
111            egl::BAD_CONFIG => ErrorKind::BadConfig,
112            egl::BAD_CURRENT_SURFACE => ErrorKind::BadCurrentSurface,
113            egl::BAD_DISPLAY => ErrorKind::BadDisplay,
114            egl::BAD_SURFACE => ErrorKind::BadSurface,
115            egl::BAD_MATCH => ErrorKind::BadMatch,
116            egl::BAD_PARAMETER => ErrorKind::BadParameter,
117            egl::BAD_NATIVE_PIXMAP => ErrorKind::BadNativePixmap,
118            egl::BAD_NATIVE_WINDOW => ErrorKind::BadNativeWindow,
119            egl::CONTEXT_LOST => ErrorKind::ContextLost,
120            _ => ErrorKind::Misc,
121        };
122
123        Err(Error::new(Some(raw_code as i64), None, kind))
124    }
125}