Skip to main content

surfman/base/egl/
device.rs

1//! Functionality common to backends using EGL displays.
2
3use crate::egl::Egl;
4
5#[cfg(not(target_os = "windows"))]
6use libc::{dlopen, dlsym, RTLD_LAZY};
7use std::ffi::{CStr, CString};
8use std::mem;
9use std::os::raw::c_void;
10use std::sync::LazyLock;
11#[cfg(target_os = "windows")]
12use winapi::shared::minwindef::HMODULE;
13#[cfg(target_os = "windows")]
14use winapi::um::libloaderapi;
15
16thread_local! {
17    pub static EGL_FUNCTIONS: Egl = Egl::load_with(get_proc_address);
18}
19
20#[cfg(target_os = "windows")]
21static EGL_LIBRARY: LazyLock<EGLLibraryWrapper> = LazyLock::new(|| unsafe {
22    let module = libloaderapi::LoadLibraryA(c"libEGL.dll".as_ptr());
23    EGLLibraryWrapper(module)
24});
25
26#[cfg(target_env = "ohos")]
27static EGL_POTENTIAL_SO_NAMES: [&CStr; 1] = [c"libEGL.so"];
28
29#[cfg(not(any(target_os = "windows", target_os = "macos", target_env = "ohos")))]
30static EGL_POTENTIAL_SO_NAMES: [&CStr; 2] = [c"libEGL.so.1", c"libEGL.so"];
31
32#[cfg(not(any(target_os = "windows", target_os = "macos")))]
33static EGL_LIBRARY: LazyLock<EGLLibraryWrapper> = LazyLock::new(|| {
34    for soname in EGL_POTENTIAL_SO_NAMES {
35        unsafe {
36            let handle = dlopen(soname.as_ptr(), RTLD_LAZY);
37            if !handle.is_null() {
38                return EGLLibraryWrapper(handle);
39            }
40        }
41    }
42    panic!("Unable to load the libEGL shared object");
43});
44
45#[cfg(target_os = "windows")]
46struct EGLLibraryWrapper(HMODULE);
47#[cfg(not(target_os = "windows"))]
48struct EGLLibraryWrapper(*mut c_void);
49
50unsafe impl Send for EGLLibraryWrapper {}
51unsafe impl Sync for EGLLibraryWrapper {}
52
53#[cfg(target_os = "windows")]
54fn get_proc_address(symbol_name: &str) -> *const c_void {
55    unsafe {
56        let symbol_name: CString = CString::new(symbol_name).unwrap();
57        let symbol_ptr = symbol_name.as_ptr();
58        libloaderapi::GetProcAddress(EGL_LIBRARY.0, symbol_ptr).cast()
59    }
60}
61
62#[cfg(not(target_os = "windows"))]
63fn get_proc_address(symbol_name: &str) -> *const c_void {
64    unsafe {
65        let symbol_name: CString = CString::new(symbol_name).unwrap();
66        let symbol_ptr = symbol_name.as_ptr();
67        dlsym(EGL_LIBRARY.0, symbol_ptr).cast_const()
68    }
69}
70
71pub(crate) unsafe fn lookup_egl_extension(name: &CStr) -> *mut c_void {
72    EGL_FUNCTIONS.with(|egl| mem::transmute(egl.GetProcAddress(name.as_ptr())))
73}