1#![allow(clippy::unnecessary_cast)] use std::ffi::{self, CStr, CString};
5use std::ops::{Deref, DerefMut};
6use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
7use std::sync::Mutex;
8
9use libloading::Library;
10use once_cell::sync::Lazy;
11use x11_dl::xlib::{self, XErrorEvent};
12
13use glutin_glx_sys::{glx, glx_extra};
14
15use crate::error::{Error, ErrorKind, Result};
16use crate::lib_loading::{SymLoading, SymWrapper};
17use crate::platform::x11::XLIB;
18
19pub mod config;
20pub mod context;
21pub mod display;
22pub mod surface;
23
24pub type XlibErrorHookRegistrar =
38 Box<dyn Fn(Box<dyn Fn(*mut ffi::c_void, *mut ffi::c_void) -> bool + Send + Sync>)>;
39
40static GLX_BASE_ERROR: AtomicI32 = AtomicI32::new(0);
42
43static LAST_GLX_ERROR: Lazy<Mutex<Option<Error>>> = Lazy::new(|| Mutex::new(None));
45
46static SYNCING_GLX_ERROR: AtomicBool = AtomicBool::new(false);
49
50static GLX: Lazy<Option<Glx>> = Lazy::new(|| {
51 let paths = ["libGL.so.1", "libGL.so"];
52
53 unsafe { SymWrapper::new(&paths).map(Glx).ok() }
54});
55
56static GLX_EXTRA: Lazy<Option<GlxExtra>> = Lazy::new(|| {
57 let glx = GLX.as_ref()?;
58 Some(GlxExtra::new(glx))
59});
60
61#[allow(missing_debug_implementations)]
63pub struct Glx(pub SymWrapper<glx::Glx>);
64
65unsafe impl Sync for Glx {}
66unsafe impl Send for Glx {}
67
68impl SymLoading for glx::Glx {
69 unsafe fn load_with(lib: &Library) -> Self {
70 Self::load_with(|sym| unsafe {
71 lib.get(CString::new(sym.as_bytes()).unwrap().as_bytes_with_nul())
72 .map(|sym| *sym)
73 .unwrap_or(std::ptr::null_mut())
74 })
75 }
76}
77
78impl Deref for Glx {
79 type Target = glx::Glx;
80
81 fn deref(&self) -> &Self::Target {
82 &self.0
83 }
84}
85
86impl DerefMut for Glx {
87 #[inline]
88 fn deref_mut(&mut self) -> &mut Self::Target {
89 &mut self.0
90 }
91}
92
93pub(crate) struct GlxExtra(glx_extra::Glx);
94
95unsafe impl Sync for GlxExtra {}
96unsafe impl Send for GlxExtra {}
97
98impl GlxExtra {
99 #[inline]
100 pub fn new(glx: &Glx) -> Self {
101 GlxExtra(glx_extra::Glx::load_with(|proc_name| {
102 let c_str = CString::new(proc_name).unwrap();
103 unsafe { glx.GetProcAddress(c_str.as_ptr() as *const u8) as *const _ }
104 }))
105 }
106}
107
108impl Deref for GlxExtra {
109 type Target = glx_extra::Glx;
110
111 fn deref(&self) -> &Self::Target {
112 &self.0
113 }
114}
115
116impl DerefMut for GlxExtra {
117 #[inline]
118 fn deref_mut(&mut self) -> &mut Self::Target {
119 &mut self.0
120 }
121}
122fn glx_error_hook(_display: *mut ffi::c_void, xerror_event: *mut ffi::c_void) -> bool {
124 if !SYNCING_GLX_ERROR.load(Ordering::Relaxed) {
126 return false;
127 }
128
129 let xerror = xerror_event as *mut XErrorEvent;
130 unsafe {
131 let code = (*xerror).error_code;
132 let glx_code = code as i32 - GLX_BASE_ERROR.load(Ordering::Relaxed);
133
134 let kind = match code as u8 {
136 xlib::BadValue => ErrorKind::BadAttribute,
137 xlib::BadMatch => ErrorKind::BadMatch,
138 xlib::BadWindow => ErrorKind::BadNativeWindow,
139 xlib::BadAlloc => ErrorKind::OutOfMemory,
140 xlib::BadPixmap => ErrorKind::BadPixmap,
141 xlib::BadAccess => ErrorKind::BadAccess,
142 _ if glx_code >= 0 => match glx_code as glx::types::GLenum {
143 glx::PROTO_BAD_CONTEXT => ErrorKind::BadContext,
144 glx::PROTO_BAD_CONTEXT_STATE => ErrorKind::BadContext,
145 glx::PROTO_BAD_CURRENT_DRAWABLE => ErrorKind::BadCurrentSurface,
146 glx::PROTO_BAD_CURRENT_WINDOW => ErrorKind::BadCurrentSurface,
147 glx::PROTO_BAD_FBCONFIG => ErrorKind::BadConfig,
148 glx::PROTO_BAD_PBUFFER => ErrorKind::BadPbuffer,
149 glx::PROTO_BAD_PIXMAP => ErrorKind::BadPixmap,
150 glx::PROTO_UNSUPPORTED_PRIVATE_REQUEST => ErrorKind::Misc,
151 glx::PROTO_BAD_DRAWABLE => ErrorKind::BadSurface,
152 glx::PROTO_BAD_WINDOW => ErrorKind::BadSurface,
153 glx::PROTO_BAD_CONTEXT_TAG => ErrorKind::Misc,
154 glx::PROTO_BAD_RENDER_REQUEST => ErrorKind::Misc,
155 glx::PROTO_BAD_LARGE_REQUEST => ErrorKind::Misc,
156 _ => return false,
157 },
158 _ => return false,
159 };
160
161 let mut buf = vec![0u8; 1024];
163 (XLIB.as_ref().unwrap().XGetErrorText)(
164 _display as *mut _,
165 (*xerror).error_code as _,
166 buf.as_mut_ptr() as *mut _,
167 buf.len() as _,
168 );
169 let description = CStr::from_ptr(buf.as_ptr() as *const _).to_string_lossy().to_string();
170
171 *LAST_GLX_ERROR.lock().unwrap() =
172 Some(Error::new(Some(code as _), Some(description), kind));
173
174 true
175 }
176}
177
178static ERROR_SECTION_LOCK: Mutex<()> = Mutex::new(());
181
182fn last_glx_error<T, F: FnOnce() -> T>(callback: F) -> Result<T> {
188 let _guard = ERROR_SECTION_LOCK.lock().unwrap();
189
190 SYNCING_GLX_ERROR.store(true, Ordering::Relaxed);
192
193 let result = callback();
195
196 let result = match LAST_GLX_ERROR.lock().unwrap().take() {
201 Some(error) => Err(error),
202 None => Ok(result),
203 };
204
205 SYNCING_GLX_ERROR.store(false, Ordering::Relaxed);
207
208 result
209}