makepad_platform/os/linux/
egl_sys.rs

1#![allow(non_camel_case_types, non_snake_case, dead_code)]
2
3pub type EGLNativeDisplayType = *mut ();
4pub type EGLNativePixmapType = ::std::os::raw::c_ulong;
5pub type EGLNativeWindowType = ::std::os::raw::c_ulong;
6
7pub use core::ptr::null_mut;
8
9pub const EGL_NO_CONTEXT: EGLContext = 0 as EGLContext;
10pub const EGL_NO_SURFACE: EGLSurface = 0 as EGLSurface;
11
12pub const EGL_WINDOW_BIT: u32 = 4;
13
14pub const EGL_OPENGL_ES2_BIT: u32 = 4;
15
16pub const EGL_SUCCESS: u32 = 12288;
17pub const EGL_ALPHA_SIZE: u32 = 12321;
18pub const EGL_BLUE_SIZE: u32 = 12322;
19pub const EGL_GREEN_SIZE: u32 = 12323;
20pub const EGL_RED_SIZE: u32 = 12324;
21pub const EGL_DEPTH_SIZE: u32 = 12325;
22pub const EGL_STENCIL_SIZE: u32 = 12326;
23pub const EGL_NATIVE_VISUAL_ID: u32 = 12334;
24pub const EGL_SURFACE_TYPE: u32 = 12339;
25pub const EGL_NONE: u32 = 12344;
26pub const EGL_RENDERABLE_TYPE: u32 = 12352;
27pub const EGL_HEIGHT: u32 = 12374;
28pub const EGL_WIDTH: u32 = 12375;
29pub const EGL_CONTEXT_CLIENT_VERSION: u32 = 12440;
30pub const EGL_OPENGL_ES_API: u32 = 12448;
31
32pub const EGL_GL_TEXTURE_2D_KHR: u32 = 12465;
33
34pub const EGL_PLATFORM_X11_EXT: u32 = 12757;
35pub const EGL_PLATFORM_GBM_KHR: u32 = 12759;
36
37pub const EGL_LINUX_DMA_BUF_EXT: u32 = 12912;
38pub const EGL_LINUX_DRM_FOURCC_EXT: u32 = 12913;
39pub const EGL_DMA_BUF_PLANE0_FD_EXT: u32 = 12914;
40pub const EGL_DMA_BUF_PLANE0_OFFSET_EXT: u32 = 12915;
41pub const EGL_DMA_BUF_PLANE0_PITCH_EXT: u32 = 12916;
42pub const EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT: u32 = 13379;
43pub const EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT: u32 = 13380;
44
45pub type NativeDisplayType = EGLNativeDisplayType;
46pub type NativePixmapType = EGLNativePixmapType;
47pub type NativeWindowType = EGLNativeWindowType;
48pub type EGLint = i32;
49pub type EGLuint64KHR = u64;
50pub type EGLenum = ::std::os::raw::c_uint;
51pub type EGLBoolean = ::std::os::raw::c_uint;
52pub type EGLDisplay = *mut ::std::os::raw::c_void;
53pub type EGLConfig = *mut ::std::os::raw::c_void;
54pub type EGLSurface = *mut ::std::os::raw::c_void;
55pub type EGLContext = *mut ::std::os::raw::c_void;
56pub type EGLClientBuffer = *mut ::std::os::raw::c_void;
57pub type EGLImageKHR = *mut ::std::os::raw::c_void;
58pub type __eglMustCastToProperFunctionPointerType = ::std::option::Option<unsafe extern "C" fn()>;
59pub type PFNEGLBINDAPIPROC = ::std::option::Option<unsafe extern "C" fn(api: EGLenum) -> EGLBoolean>;
60pub type PFNEGLCHOOSECONFIGPROC = ::std::option::Option<
61unsafe extern "C" fn(
62    dpy: EGLDisplay,
63    attrib_list: *const EGLint,
64    configs: *mut EGLConfig,
65    config_size: EGLint,
66    num_config: *mut EGLint,
67) -> EGLBoolean,
68>;
69pub type PFNEGLCOPYBUFFERSPROC = ::std::option::Option<
70unsafe extern "C" fn(
71    dpy: EGLDisplay,
72    surface: EGLSurface,
73    target: EGLNativePixmapType,
74) -> EGLBoolean,
75>;
76pub type PFNEGLCREATECONTEXTPROC = ::std::option::Option<
77unsafe extern "C" fn(
78    dpy: EGLDisplay,
79    config: EGLConfig,
80    share_context: EGLContext,
81    attrib_list: *const EGLint,
82) -> EGLContext,
83>;
84pub type PFNEGLCREATEIMAGEKHRPROC = ::std::option::Option<
85unsafe extern "C" fn(
86    dpy: EGLDisplay,
87    ctx: EGLContext,
88    target: EGLenum,
89    buffer: EGLClientBuffer,
90    attrib_list: *const EGLint,
91) -> EGLImageKHR,
92>;
93pub type PFNEGLDESTROYIMAGEKHRPROC = ::std::option::Option<
94unsafe extern "C" fn(
95    dpy: EGLDisplay,
96    image: EGLImageKHR,
97) -> EGLBoolean,
98>;
99pub type PFNEGLCREATEPBUFFERSURFACEPROC = ::std::option::Option<
100unsafe extern "C" fn(
101    dpy: EGLDisplay,
102    config: EGLConfig,
103    attrib_list: *const EGLint,
104) -> EGLSurface,
105>;
106pub type PFNEGLCREATEPIXMAPSURFACEPROC = ::std::option::Option<
107unsafe extern "C" fn(
108    dpy: EGLDisplay,
109    config: EGLConfig,
110    pixmap: EGLNativePixmapType,
111    attrib_list: *const EGLint,
112) -> EGLSurface,
113>;
114pub type PFNEGLCREATEWINDOWSURFACEPROC = ::std::option::Option<
115unsafe extern "C" fn(
116    dpy: EGLDisplay,
117    config: EGLConfig,
118    win: EGLNativeWindowType,
119    attrib_list: *const EGLint,
120) -> EGLSurface,
121>;
122pub type PFNEGLDESTROYCONTEXTPROC =
123::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, ctx: EGLContext) -> EGLBoolean>;
124pub type PFNEGLDESTROYSURFACEPROC =
125::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface) -> EGLBoolean>;
126pub type PFNEGLGETCONFIGATTRIBPROC = ::std::option::Option<
127unsafe extern "C" fn(
128    dpy: EGLDisplay,
129    config: EGLConfig,
130    attribute: EGLint,
131    value: *mut EGLint,
132) -> EGLBoolean,
133>;
134pub type PFNEGLGETCONFIGSPROC = ::std::option::Option<
135unsafe extern "C" fn(
136    dpy: EGLDisplay,
137    configs: *mut EGLConfig,
138    config_size: EGLint,
139    num_config: *mut EGLint,
140) -> EGLBoolean,
141>;
142pub type PFNEGLGETCURRENTDISPLAYPROC = ::std::option::Option<unsafe extern "C" fn() -> EGLDisplay>;
143pub type PFNEGLGETCURRENTSURFACEPROC =
144::std::option::Option<unsafe extern "C" fn(readdraw: EGLint) -> EGLSurface>;
145pub type PFNEGLGETDISPLAYPROC =
146::std::option::Option<unsafe extern "C" fn(display_id: EGLNativeDisplayType) -> EGLDisplay>;
147pub type PFNEGLGETERRORPROC = ::std::option::Option<unsafe extern "C" fn() -> EGLint>;
148pub type PFNEGLGETPROCADDRESSPROC = ::std::option::Option<
149unsafe extern "C" fn(
150    procname: *const ::std::os::raw::c_char,
151) -> *mut ::std::os::raw::c_void,
152>;
153pub type PFNEGLINITIALIZEPROC = ::std::option::Option<
154unsafe extern "C" fn(dpy: EGLDisplay, major: *mut EGLint, minor: *mut EGLint) -> EGLBoolean,
155>;
156pub type PFNEGLMAKECURRENTPROC = ::std::option::Option<
157unsafe extern "C" fn(
158    dpy: EGLDisplay,
159    draw: EGLSurface,
160    read: EGLSurface,
161    ctx: EGLContext,
162) -> EGLBoolean,
163>;
164pub type PFNEGLQUERYCONTEXTPROC = ::std::option::Option<
165unsafe extern "C" fn(
166    dpy: EGLDisplay,
167    ctx: EGLContext,
168    attribute: EGLint,
169    value: *mut EGLint,
170) -> EGLBoolean,
171>;
172pub type PFNEGLQUERYSTRINGPROC = ::std::option::Option<
173unsafe extern "C" fn(dpy: EGLDisplay, name: EGLint) -> *const ::std::os::raw::c_char,
174>;
175pub type PFNEGLQUERYSURFACEPROC = ::std::option::Option<
176unsafe extern "C" fn(
177    dpy: EGLDisplay,
178    surface: EGLSurface,
179    attribute: EGLint,
180    value: *mut EGLint,
181) -> EGLBoolean,
182>;
183pub type PFNEGLSWAPBUFFERSPROC =
184::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface) -> EGLBoolean>;
185pub type PFNEGLTERMINATEPROC =
186::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay) -> EGLBoolean>;
187pub type PFNEGLWAITGLPROC = ::std::option::Option<unsafe extern "C" fn() -> EGLBoolean>;
188pub type PFNEGLWAITNATIVEPROC =
189::std::option::Option<unsafe extern "C" fn(engine: EGLint) -> EGLBoolean>;
190pub type PFNEGLBINDTEXIMAGEPROC = ::std::option::Option<
191unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface, buffer: EGLint) -> EGLBoolean,
192>;
193pub type PFNEGLRELEASETEXIMAGEPROC = ::std::option::Option<
194unsafe extern "C" fn(dpy: EGLDisplay, surface: EGLSurface, buffer: EGLint) -> EGLBoolean,
195>;
196pub type PFNEGLSURFACEATTRIBPROC = ::std::option::Option<
197unsafe extern "C" fn(
198    dpy: EGLDisplay,
199    surface: EGLSurface,
200    attribute: EGLint,
201    value: EGLint,
202) -> EGLBoolean,
203>;
204pub type PFNEGLSWAPINTERVALPROC =
205::std::option::Option<unsafe extern "C" fn(dpy: EGLDisplay, interval: EGLint) -> EGLBoolean>;
206
207pub type PFNEGLGETPLATFORMDISPLAYEXTPROC = ::std::option::Option<
208unsafe extern "C" fn(
209    platform: EGLenum,
210    native_display: *mut ::std::os::raw::c_void,
211    attrib_list: *const EGLint,
212) -> EGLDisplay,
213>;
214
215pub type PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC = ::std::option::Option<
216unsafe extern "C" fn(
217    dpy: EGLDisplay,
218    image: EGLImageKHR,
219    fourcc: *mut i32,
220    num_planes: *mut i32,
221    modifiers: *mut EGLuint64KHR,
222) -> EGLBoolean,
223>;
224pub type PFNEGLEXPORTDMABUFIMAGEMESAPROC = ::std::option::Option<
225unsafe extern "C" fn(
226    dpy: EGLDisplay,
227    image: EGLImageKHR,
228    fds: *mut i32,
229    strides: *mut EGLint,
230    offsets: *mut EGLint,
231) -> EGLBoolean,
232>;
233
234// HACK(eddyb) this is actually an OpenGL extension function.
235type PFNGLEGLIMAGETARGETTEXTURE2DOESPROC = ::std::option::Option<
236unsafe extern "C" fn(
237    super::gl_sys::GLenum,
238    EGLImageKHR,
239),
240>;
241
242struct Module(::std::ptr::NonNull<::std::os::raw::c_void>);
243
244pub struct LibEgl {
245    pub eglBindAPI: PFNEGLBINDAPIPROC,
246    pub eglChooseConfig: PFNEGLCHOOSECONFIGPROC,
247    pub eglCopyBuffers: PFNEGLCOPYBUFFERSPROC,
248    pub eglCreateContext: PFNEGLCREATECONTEXTPROC,
249    pub eglCreatePbufferSurface: PFNEGLCREATEPBUFFERSURFACEPROC,
250    pub eglCreatePixmapSurface: PFNEGLCREATEPIXMAPSURFACEPROC,
251    pub eglCreateWindowSurface: PFNEGLCREATEWINDOWSURFACEPROC,
252    pub eglDestroyContext: PFNEGLDESTROYCONTEXTPROC,
253    pub eglDestroySurface: PFNEGLDESTROYSURFACEPROC,
254    pub eglGetConfigAttrib: PFNEGLGETCONFIGATTRIBPROC,
255    pub eglGetConfigs: PFNEGLGETCONFIGSPROC,
256    pub eglGetCurrentDisplay: PFNEGLGETCURRENTDISPLAYPROC,
257    pub eglGetCurrentSurface: PFNEGLGETCURRENTSURFACEPROC,
258    pub eglGetDisplay: PFNEGLGETDISPLAYPROC,
259    pub eglGetError: PFNEGLGETERRORPROC,
260    pub eglGetProcAddress: PFNEGLGETPROCADDRESSPROC,
261    pub eglInitialize: PFNEGLINITIALIZEPROC,
262    pub eglMakeCurrent: PFNEGLMAKECURRENTPROC,
263    pub eglQueryContext: PFNEGLQUERYCONTEXTPROC,
264    pub eglQueryString: PFNEGLQUERYSTRINGPROC,
265    pub eglQuerySurface: PFNEGLQUERYSURFACEPROC,
266    pub eglSwapBuffers: PFNEGLSWAPBUFFERSPROC,
267    pub eglTerminate: PFNEGLTERMINATEPROC,
268    pub eglWaitGL: PFNEGLWAITGLPROC,
269    pub eglWaitNative: PFNEGLWAITNATIVEPROC,
270    pub eglBindTexImage: PFNEGLBINDTEXIMAGEPROC,
271    pub eglReleaseTexImage: PFNEGLRELEASETEXIMAGEPROC,
272    pub eglSurfaceAttrib: PFNEGLSURFACEATTRIBPROC,
273    pub eglSwapInterval: PFNEGLSWAPINTERVALPROC,
274
275    pub eglCreateImageKHR: PFNEGLCREATEIMAGEKHRPROC,
276    pub eglDestroyImageKHR: PFNEGLDESTROYIMAGEKHRPROC,
277    pub eglExportDMABUFImageQueryMESA: PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC,
278    pub eglExportDMABUFImageMESA: PFNEGLEXPORTDMABUFIMAGEMESAPROC,
279    pub eglGetPlatformDisplayEXT: PFNEGLGETPLATFORMDISPLAYEXTPROC,
280
281    // HACK(eddyb) this is actually an OpenGL extension function.
282    pub glEGLImageTargetTexture2DOES: PFNGLEGLIMAGETARGETTEXTURE2DOESPROC,
283
284    _keep_module_alive: Module,
285}
286
287impl LibEgl {
288    pub fn try_load() -> Option<LibEgl> {
289        use self::super::libc_sys::{dlclose, dlopen, dlsym, RTLD_LAZY, RTLD_LOCAL};
290        use std::{
291            ffi::{CString, CStr},
292            ptr::NonNull,
293        };
294        
295        impl Module {
296            pub fn load(path: &str) -> Result<Self,()> {
297                let path = CString::new(path).unwrap();
298                
299                let module = unsafe {dlopen(path.as_ptr(), RTLD_LAZY | RTLD_LOCAL)};
300                if module.is_null() {
301                    Err(())
302                } else {
303                    Ok(Module(unsafe {NonNull::new_unchecked(module)}))
304                }
305            }
306            
307            pub fn get_symbol<F: Sized>(&self, name: &str) -> Result<F, ()> {
308                let name = CString::new(name).unwrap();
309                
310                let symbol = unsafe {dlsym(self.0.as_ptr(), name.as_ptr())};
311                
312                if symbol.is_null() {
313                    return Err(());
314                }
315                
316                Ok(unsafe {std::mem::transmute_copy::<_, F>(&symbol)})
317            }
318        }
319        
320        impl Drop for Module {
321            fn drop(&mut self) {
322                unsafe {dlclose(self.0.as_ptr())};
323            }
324        }
325
326        let module = Module::load("libEGL.so").or_else(|_| Module::load("libEGL.so.1")).ok()?;
327
328        let eglGetProcAddress: PFNEGLGETPROCADDRESSPROC = module.get_symbol("eglGetProcAddress").ok();
329        macro_rules! get_ext_fn {
330            ($name:literal) => {
331                eglGetProcAddress.and_then(|gpa| unsafe {
332                    std::mem::transmute(gpa(CStr::from_bytes_with_nul(concat!($name, "\0").as_bytes()).unwrap().as_ptr()))
333                })
334            }
335        }
336
337        Some(LibEgl {
338            eglBindAPI: module.get_symbol("eglBindAPI").ok(),
339            eglChooseConfig: module.get_symbol("eglChooseConfig").ok(),
340            eglCopyBuffers: module.get_symbol("eglCopyBuffers").ok(),
341            eglCreateContext: module.get_symbol("eglCreateContext").ok(),
342            eglCreatePbufferSurface: module.get_symbol("eglCreatePbufferSurface").ok(),
343            eglCreatePixmapSurface: module.get_symbol("eglCreatePixmapSurface").ok(),
344            eglCreateWindowSurface: module.get_symbol("eglCreateWindowSurface").ok(),
345            eglDestroyContext: module.get_symbol("eglDestroyContext").ok(),
346            eglDestroySurface: module.get_symbol("eglDestroySurface").ok(),
347            eglGetConfigAttrib: module.get_symbol("eglGetConfigAttrib").ok(),
348            eglGetConfigs: module.get_symbol("eglGetConfigs").ok(),
349            eglGetCurrentDisplay: module.get_symbol("eglGetCurrentDisplay").ok(),
350            eglGetCurrentSurface: module.get_symbol("eglGetCurrentSurface").ok(),
351            eglGetDisplay: module.get_symbol("eglGetDisplay").ok(),
352            eglGetError: module.get_symbol("eglGetError").ok(),
353            eglGetProcAddress,
354            eglInitialize: module.get_symbol("eglInitialize").ok(),
355            eglMakeCurrent: module.get_symbol("eglMakeCurrent").ok(),
356            eglQueryContext: module.get_symbol("eglQueryContext").ok(),
357            eglQueryString: module.get_symbol("eglQueryString").ok(),
358            eglQuerySurface: module.get_symbol("eglQuerySurface").ok(),
359            eglSwapBuffers: module.get_symbol("eglSwapBuffers").ok(),
360            eglTerminate: module.get_symbol("eglTerminate").ok(),
361            eglWaitGL: module.get_symbol("eglWaitGL").ok(),
362            eglWaitNative: module.get_symbol("eglWaitNative").ok(),
363            eglBindTexImage: module.get_symbol("eglBindTexImage").ok(),
364            eglReleaseTexImage: module.get_symbol("eglReleaseTexImage").ok(),
365            eglSurfaceAttrib: module.get_symbol("eglSurfaceAttrib").ok(),
366            eglSwapInterval: module.get_symbol("eglSwapInterval").ok(),
367
368            eglCreateImageKHR: get_ext_fn!("eglCreateImageKHR"),
369            eglDestroyImageKHR: get_ext_fn!("eglDestroyImageKHR"),
370            eglExportDMABUFImageQueryMESA: get_ext_fn!("eglExportDMABUFImageQueryMESA"),
371            eglExportDMABUFImageMESA: get_ext_fn!("eglExportDMABUFImageMESA"),
372            eglGetPlatformDisplayEXT: get_ext_fn!("eglGetPlatformDisplayEXT"),
373
374            glEGLImageTargetTexture2DOES: get_ext_fn!("glEGLImageTargetTexture2DOES"),
375
376            _keep_module_alive: module,
377        })
378    }
379}
380
381#[derive(Debug)]
382pub enum EglError {
383    NoDisplay,
384    InitializeFailed,
385    CreateContextFailed,
386}
387
388pub struct Egl {}
389
390#[cfg(target_os="android")]
391pub unsafe fn create_egl_context(
392    egl: &mut LibEgl,
393    display: *mut std::ffi::c_void,
394    alpha: bool,
395) -> Result<(EGLContext, EGLConfig, EGLDisplay), EglError> {
396
397    let display = (egl.eglGetDisplay.unwrap())(display as _);
398    if display == /* EGL_NO_DISPLAY */ null_mut() {
399        return Err(EglError::NoDisplay);
400    }
401
402    if (egl.eglInitialize.unwrap())(display, null_mut(), null_mut()) == 0 {
403        return Err(EglError::InitializeFailed);
404    }
405
406    let alpha_size = if alpha {8} else {0};
407    #[rustfmt::skip]
408    let cfg_attributes = vec![
409        EGL_SURFACE_TYPE,
410        EGL_WINDOW_BIT,
411        EGL_RED_SIZE,
412        8,
413        EGL_GREEN_SIZE,
414        8,
415        EGL_BLUE_SIZE,
416        8,
417        EGL_ALPHA_SIZE,
418        alpha_size,
419        EGL_DEPTH_SIZE,
420        24,
421        EGL_STENCIL_SIZE,
422        0,
423        EGL_NONE,
424    ];
425    let mut available_cfgs: Vec<EGLConfig> = vec![null_mut(); 32];
426    let mut cfg_count = 0;
427
428    (egl.eglChooseConfig.unwrap())(
429        display,
430        cfg_attributes.as_ptr() as _,
431        available_cfgs.as_ptr() as _,
432        32,
433        &mut cfg_count as *mut _ as *mut _,
434    );
435    assert!(cfg_count > 0);
436    assert!(cfg_count <= 32);
437    
438    // find config with 8-bit rgb buffer if available, ndk sample does not trust egl spec
439    let mut config: EGLConfig = null_mut();
440    let mut exact_cfg_found = false;
441    for c in &mut available_cfgs[0..cfg_count] {
442        let mut r: i32 = 0;
443        let mut g: i32 = 0;
444        let mut b: i32 = 0;
445        let mut a: i32 = 0;
446        let mut d: i32 = 0;
447        if (egl.eglGetConfigAttrib.unwrap())(display, *c, EGL_RED_SIZE as _, &mut r) == 1
448            && (egl.eglGetConfigAttrib.unwrap())(display, *c, EGL_GREEN_SIZE as _, &mut g) == 1
449            && (egl.eglGetConfigAttrib.unwrap())(display, *c, EGL_BLUE_SIZE as _, &mut b) == 1
450            && (egl.eglGetConfigAttrib.unwrap())(display, *c, EGL_ALPHA_SIZE as _, &mut a) == 1
451            && (egl.eglGetConfigAttrib.unwrap())(display, *c, EGL_DEPTH_SIZE as _, &mut d) == 1
452            && r == 8
453            && g == 8
454            && b == 8
455            && (alpha_size == 0 || a == alpha_size as _)
456            && d == 16
457        {
458            exact_cfg_found = true;
459            config = *c;
460            break;
461        }
462    }
463    if !exact_cfg_found {
464        config = available_cfgs[0];
465    }
466    let ctx_attributes = vec![EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE];
467    let context = (egl.eglCreateContext.unwrap())(
468        display,
469        config,
470        /* EGL_NO_CONTEXT */ null_mut(),
471        ctx_attributes.as_ptr() as _,
472    );
473    if context.is_null() {
474        return Err(EglError::CreateContextFailed);
475    }
476    
477    return Ok((context, config, display));
478}