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
31pub(crate) static EGL: Lazy<Option<Egl>> = Lazy::new(|| {
32 #[cfg(windows)]
33 let paths = ["libEGL.dll", "atioglxx.dll"];
34
35 #[cfg(not(windows))]
36 let paths: [&str; 2] = ["libEGL.so.1", "libEGL.so"];
37
38 unsafe { SymWrapper::new(&paths).map(op:Egl).ok() }
39});
40
41type EglGetProcAddress = unsafe extern "C" fn(*const ffi::c_void) -> *const ffi::c_void;
42static EGL_GET_PROC_ADDRESS: OnceCell<libloading_os::Symbol<EglGetProcAddress>> = OnceCell::new();
43
44pub(crate) struct Egl(pub SymWrapper<egl::Egl>);
45
46unsafe impl Sync for Egl {}
47unsafe impl Send for Egl {}
48
49impl SymLoading for egl::Egl {
50 unsafe fn load_with(lib: &Library) -> Self {
51 let loader = move |sym_name: &'static str| -> *const ffi::c_void {
52 unsafe {
53 let sym_name = CString::new(sym_name.as_bytes()).unwrap();
54 if let Ok(sym) = lib.get(sym_name.as_bytes_with_nul()) {
55 return *sym;
56 }
57
58 let egl_proc_address = EGL_GET_PROC_ADDRESS.get_or_init(|| {
59 let sym: libloading::Symbol<'_, EglGetProcAddress> =
60 lib.get(b"eglGetProcAddress\0").unwrap();
61 sym.into_raw()
62 });
63
64 // The symbol was not available in the library, so ask eglGetProcAddress for it.
65 // Note that eglGetProcAddress was only able to look up extension
66 // functions prior to EGL 1.5, hence this two-part dance.
67 (egl_proc_address)(sym_name.as_bytes_with_nul().as_ptr() as *const ffi::c_void)
68 }
69 };
70
71 Self::load_with(loader)
72 }
73}
74
75impl Deref for Egl {
76 type Target = egl::Egl;
77
78 fn deref(&self) -> &Self::Target {
79 &self.0
80 }
81}
82
83impl DerefMut for Egl {
84 fn deref_mut(&mut self) -> &mut Self::Target {
85 &mut self.0
86 }
87}
88
89/// Obtain the error from the EGL.
90fn check_error() -> Result<()> {
91 let egl = EGL.as_ref().unwrap();
92 unsafe {
93 let raw_code = egl.GetError() as egl::types::EGLenum;
94 let kind = match raw_code {
95 egl::SUCCESS => return Ok(()),
96 egl::NOT_INITIALIZED => ErrorKind::InitializationFailed,
97 egl::BAD_ACCESS => ErrorKind::BadAccess,
98 egl::BAD_ALLOC => ErrorKind::OutOfMemory,
99 egl::BAD_ATTRIBUTE => ErrorKind::BadAttribute,
100 egl::BAD_CONTEXT => ErrorKind::BadContext,
101 egl::BAD_CONFIG => ErrorKind::BadConfig,
102 egl::BAD_CURRENT_SURFACE => ErrorKind::BadCurrentSurface,
103 egl::BAD_DISPLAY => ErrorKind::BadDisplay,
104 egl::BAD_SURFACE => ErrorKind::BadSurface,
105 egl::BAD_MATCH => ErrorKind::BadMatch,
106 egl::BAD_PARAMETER => ErrorKind::BadParameter,
107 egl::BAD_NATIVE_PIXMAP => ErrorKind::BadNativePixmap,
108 egl::BAD_NATIVE_WINDOW => ErrorKind::BadNativeWindow,
109 egl::CONTEXT_LOST => ErrorKind::ContextLost,
110 _ => ErrorKind::Misc,
111 };
112
113 Err(Error::new(Some(raw_code as i64), None, kind))
114 }
115}
116