glutin/api/egl/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! EGL platform Api.
//!
//! This platform is typically available on Linux, Android and other Unix-like
//! platforms.
//!
//! The EGL platform allows creating a [`Display`](self::display::Display) from
//! a [`Device`](self::device::Device).

use std::ffi::{self, CString};
use std::ops::{Deref, DerefMut};

use glutin_egl_sys::egl;

use libloading::Library;
use once_cell::sync::{Lazy, OnceCell};

#[cfg(unix)]
use libloading::os::unix as libloading_os;
#[cfg(windows)]
use libloading::os::windows as libloading_os;

use crate::error::{Error, ErrorKind, Result};
use crate::lib_loading::{SymLoading, SymWrapper};

pub mod config;
pub mod context;
pub mod device;
pub mod display;
pub mod surface;

// WARNING: If this implementation is ever changed to unload or replace the
// library, note that public API functions currently retirm `&'static str`ings
// out of it, which would become invalid.
pub(crate) static EGL: Lazy<Option<Egl>> = Lazy::new(|| {
    #[cfg(windows)]
    let paths = ["libEGL.dll", "atioglxx.dll"];

    #[cfg(not(windows))]
    let paths = ["libEGL.so.1", "libEGL.so"];

    unsafe { SymWrapper::new(&paths).map(Egl).ok() }
});

type EglGetProcAddress = unsafe extern "system" fn(*const ffi::c_void) -> *const ffi::c_void;
static EGL_GET_PROC_ADDRESS: OnceCell<libloading_os::Symbol<EglGetProcAddress>> = OnceCell::new();

/// EGL interface.
#[allow(missing_debug_implementations)]
pub struct Egl(SymWrapper<egl::Egl>);

unsafe impl Sync for Egl {}
unsafe impl Send for Egl {}

impl SymLoading for egl::Egl {
    unsafe fn load_with(lib: &Library) -> Self {
        let loader = move |sym_name: &'static str| -> *const ffi::c_void {
            unsafe {
                let sym_name = CString::new(sym_name.as_bytes()).unwrap();
                if let Ok(sym) = lib.get(sym_name.as_bytes_with_nul()) {
                    return *sym;
                }

                let egl_proc_address = EGL_GET_PROC_ADDRESS.get_or_init(|| {
                    let sym: libloading::Symbol<'_, EglGetProcAddress> =
                        lib.get(b"eglGetProcAddress\0").unwrap();
                    sym.into_raw()
                });

                // The symbol was not available in the library, so ask eglGetProcAddress for it.
                // Note that eglGetProcAddress was only able to look up extension
                // functions prior to EGL 1.5, hence this two-part dance.
                (egl_proc_address)(sym_name.as_bytes_with_nul().as_ptr() as *const ffi::c_void)
            }
        };

        egl::BindWaylandDisplayWL::load_with(loader);
        egl::UnbindWaylandDisplayWL::load_with(loader);
        egl::QueryWaylandBufferWL::load_with(loader);
        egl::CreateWaylandBufferFromImageWL::load_with(loader);

        Self::load_with(loader)
    }
}

impl Deref for Egl {
    type Target = egl::Egl;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Egl {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

/// Obtain the error from the EGL.
fn check_error() -> Result<()> {
    let egl = EGL.as_ref().unwrap();
    unsafe {
        let raw_code = egl.GetError() as egl::types::EGLenum;
        let kind = match raw_code {
            egl::SUCCESS => return Ok(()),
            egl::NOT_INITIALIZED => ErrorKind::InitializationFailed,
            egl::BAD_ACCESS => ErrorKind::BadAccess,
            egl::BAD_ALLOC => ErrorKind::OutOfMemory,
            egl::BAD_ATTRIBUTE => ErrorKind::BadAttribute,
            egl::BAD_CONTEXT => ErrorKind::BadContext,
            egl::BAD_CONFIG => ErrorKind::BadConfig,
            egl::BAD_CURRENT_SURFACE => ErrorKind::BadCurrentSurface,
            egl::BAD_DISPLAY => ErrorKind::BadDisplay,
            egl::BAD_SURFACE => ErrorKind::BadSurface,
            egl::BAD_MATCH => ErrorKind::BadMatch,
            egl::BAD_PARAMETER => ErrorKind::BadParameter,
            egl::BAD_NATIVE_PIXMAP => ErrorKind::BadNativePixmap,
            egl::BAD_NATIVE_WINDOW => ErrorKind::BadNativeWindow,
            egl::CONTEXT_LOST => ErrorKind::ContextLost,
            _ => ErrorKind::Misc,
        };

        Err(Error::new(Some(raw_code as i64), None, kind))
    }
}