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 | |
9 | use std::ffi::{self, CString}; |
10 | use std::ops::{Deref, DerefMut}; |
11 | |
12 | use glutin_egl_sys::egl; |
13 | |
14 | use libloading::Library; |
15 | use once_cell::sync::{Lazy, OnceCell}; |
16 | |
17 | #[cfg (unix)] |
18 | use libloading::os::unix as libloading_os; |
19 | #[cfg (windows)] |
20 | use libloading::os::windows as libloading_os; |
21 | |
22 | use crate::error::{Error, ErrorKind, Result}; |
23 | use crate::lib_loading::{SymLoading, SymWrapper}; |
24 | |
25 | pub mod config; |
26 | pub mod context; |
27 | pub mod device; |
28 | pub mod display; |
29 | pub mod surface; |
30 | |
31 | pub(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 | |
41 | type EglGetProcAddress = unsafe extern "C" fn(*const ffi::c_void) -> *const ffi::c_void; |
42 | static EGL_GET_PROC_ADDRESS: OnceCell<libloading_os::Symbol<EglGetProcAddress>> = OnceCell::new(); |
43 | |
44 | pub(crate) struct Egl(pub SymWrapper<egl::Egl>); |
45 | |
46 | unsafe impl Sync for Egl {} |
47 | unsafe impl Send for Egl {} |
48 | |
49 | impl 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 | |
75 | impl Deref for Egl { |
76 | type Target = egl::Egl; |
77 | |
78 | fn deref(&self) -> &Self::Target { |
79 | &self.0 |
80 | } |
81 | } |
82 | |
83 | impl 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. |
90 | fn 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 | |