|
13 | 13 | mod egl {
|
14 | 14 | use super::ffi;
|
15 | 15 | use crate::api::dlloader::{SymTrait, SymWrapper};
|
| 16 | + use libloading; |
| 17 | + use std::sync::{Arc, Mutex}; |
| 18 | + |
| 19 | + #[cfg(unix)] |
| 20 | + use libloading::os::unix as libloading_os; |
| 21 | + #[cfg(windows)] |
| 22 | + use libloading::os::windows as libloading_os; |
16 | 23 |
|
17 | 24 | #[derive(Clone)]
|
18 | 25 | pub struct Egl(pub SymWrapper<ffi::egl::Egl>);
|
19 | 26 |
|
20 | 27 | /// Because `*const raw::c_void` doesn't implement `Sync`.
|
21 | 28 | unsafe impl Sync for Egl {}
|
22 | 29 |
|
| 30 | + type EglGetProcAddressType = libloading_os::Symbol< |
| 31 | + unsafe extern "C" fn( |
| 32 | + *const std::os::raw::c_void, |
| 33 | + ) -> *const std::os::raw::c_void, |
| 34 | + >; |
| 35 | + |
| 36 | + lazy_static! { |
| 37 | + static ref EGL_GET_PROC_ADDRESS: Arc<Mutex<Option<EglGetProcAddressType>>> = |
| 38 | + Arc::new(Mutex::new(None)); |
| 39 | + } |
| 40 | + |
23 | 41 | impl SymTrait for ffi::egl::Egl {
|
24 |
| - fn load_with<F>(loadfn: F) -> Self |
25 |
| - where |
26 |
| - F: FnMut(&'static str) -> *const std::os::raw::c_void, |
27 |
| - { |
28 |
| - Self::load_with(loadfn) |
| 42 | + fn load_with(lib: &libloading::Library) -> Self { |
| 43 | + let f = move |s: &'static str| -> *const std::os::raw::c_void { |
| 44 | + // Check if the symbol is available in the library directly. If |
| 45 | + // it is, just return it. |
| 46 | + match unsafe { |
| 47 | + lib.get( |
| 48 | + std::ffi::CString::new(s.as_bytes()) |
| 49 | + .unwrap() |
| 50 | + .as_bytes_with_nul(), |
| 51 | + ) |
| 52 | + } { |
| 53 | + Ok(sym) => return *sym, |
| 54 | + Err(_) => (), |
| 55 | + }; |
| 56 | + |
| 57 | + let mut egl_get_proc_address = |
| 58 | + (*EGL_GET_PROC_ADDRESS).lock().unwrap(); |
| 59 | + if egl_get_proc_address.is_none() { |
| 60 | + unsafe { |
| 61 | + let sym: libloading::Symbol< |
| 62 | + unsafe extern "C" fn( |
| 63 | + *const std::os::raw::c_void, |
| 64 | + ) |
| 65 | + -> *const std::os::raw::c_void, |
| 66 | + > = lib.get(b"eglGetProcAddress").unwrap(); |
| 67 | + *egl_get_proc_address = Some(sym.into_raw()); |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + // The symbol was not available in the library, so ask |
| 72 | + // eglGetProcAddress for it. Note that eglGetProcAddress was |
| 73 | + // only able to look up extension functions prior to EGL 1.5, |
| 74 | + // hence this two-part dance. |
| 75 | + unsafe { |
| 76 | + (egl_get_proc_address.as_ref().unwrap())( |
| 77 | + std::ffi::CString::new(s.as_bytes()) |
| 78 | + .unwrap() |
| 79 | + .as_bytes_with_nul() |
| 80 | + .as_ptr() |
| 81 | + as *const std::os::raw::c_void, |
| 82 | + ) |
| 83 | + } |
| 84 | + }; |
| 85 | + |
| 86 | + Self::load_with(f) |
29 | 87 | }
|
30 | 88 | }
|
31 | 89 |
|
@@ -65,7 +123,7 @@ use crate::platform_impl::PlatformAttributes;
|
65 | 123 | use crate::{
|
66 | 124 | Api, ContextBuilderWrapper, ContextError, ContextSupports, CreationError,
|
67 | 125 | GlAttributes, GlRequest, PixelFormat, PixelFormatRequirements,
|
68 |
| - ReleaseBehavior, Robustness, |
| 126 | + ReleaseBehavior, Robustness, Rect, |
69 | 127 | };
|
70 | 128 |
|
71 | 129 | use glutin_egl_sys as ffi;
|
@@ -943,6 +1001,55 @@ impl WindowSurface {
|
943 | 1001 | Ok(())
|
944 | 1002 | }
|
945 | 1003 | }
|
| 1004 | + |
| 1005 | + #[inline] |
| 1006 | + pub fn swap_buffers_with_damage( |
| 1007 | + &self, |
| 1008 | + rects: &[Rect], |
| 1009 | + ) -> Result<(), ContextError> { |
| 1010 | + let egl = EGL.as_ref().unwrap(); |
| 1011 | + |
| 1012 | + if !egl.SwapBuffersWithDamageKHR.is_loaded() { |
| 1013 | + return Err(ContextError::OsError("buffer damage not suported".to_string())); |
| 1014 | + } |
| 1015 | + |
| 1016 | + if *self.surface == ffi::egl::NO_SURFACE { |
| 1017 | + return Err(ContextError::ContextLost); |
| 1018 | + } |
| 1019 | + |
| 1020 | + let mut ffirects: Vec<ffi::egl::types::EGLint> = |
| 1021 | + Vec::with_capacity(rects.len() * 4); |
| 1022 | + |
| 1023 | + for rect in rects { |
| 1024 | + ffirects.push(rect.x as ffi::egl::types::EGLint); |
| 1025 | + ffirects.push(rect.y as ffi::egl::types::EGLint); |
| 1026 | + ffirects.push(rect.width as ffi::egl::types::EGLint); |
| 1027 | + ffirects.push(rect.height as ffi::egl::types::EGLint); |
| 1028 | + } |
| 1029 | + |
| 1030 | + let ret = unsafe { |
| 1031 | + egl.SwapBuffersWithDamageKHR( |
| 1032 | + **self.display, |
| 1033 | + *self.surface, |
| 1034 | + ffirects.as_mut_ptr(), |
| 1035 | + rects.len() as ffi::egl::types::EGLint, |
| 1036 | + ) |
| 1037 | + }; |
| 1038 | + |
| 1039 | + if ret == ffi::egl::FALSE { |
| 1040 | + match unsafe { egl.GetError() } as u32 { |
| 1041 | + ffi::egl::CONTEXT_LOST => { |
| 1042 | + return Err(ContextError::ContextLost) |
| 1043 | + } |
| 1044 | + err => panic!( |
| 1045 | + "swap_buffers: eglSwapBuffers failed (eglGetError returned 0x{:x})", |
| 1046 | + err |
| 1047 | + ), |
| 1048 | + } |
| 1049 | + } else { |
| 1050 | + Ok(()) |
| 1051 | + } |
| 1052 | + } |
946 | 1053 | }
|
947 | 1054 |
|
948 | 1055 | impl PBuffer {
|
|
0 commit comments