1use super::device::{Device, NativeDevice};
4use super::surface::NativeWidget;
5use crate::base::egl::device::EGL_FUNCTIONS;
6use crate::base::egl::ffi::EGL_PLATFORM_X11_KHR;
7use crate::egl;
8use crate::egl::types::{EGLAttrib, EGLDisplay};
9use crate::error::Error;
10use crate::info::GLApi;
11use crate::mesa_surfaceless::device::Adapter;
12
13use euclid::default::Size2D;
14
15use std::marker::PhantomData;
16use std::os::raw::c_void;
17use std::ptr;
18use std::sync::{Arc, Once};
19use x11_dl::xlib::{Display, Xlib};
20
21static X_THREADS_INIT: Once = Once::new();
22
23#[derive(Clone)]
25pub struct Connection {
26 pub(crate) native_connection: Arc<NativeConnectionWrapper>,
27}
28
29unsafe impl Send for Connection {}
30
31pub(crate) struct NativeConnectionWrapper {
32 pub(crate) xlib: Xlib,
33 pub(crate) egl_display: EGLDisplay,
34 egl_display_is_owned: bool,
37 x11_display: *mut Display,
38 x11_display_is_owned: bool,
41}
42
43#[derive(Clone)]
45pub struct NativeConnection {
46 pub egl_display: EGLDisplay,
52 pub x11_display: *mut Display,
54}
55
56impl Drop for NativeConnectionWrapper {
57 #[inline]
58 fn drop(&mut self) {
59 unsafe {
60 if self.egl_display_is_owned {
61 terminate_egl_display(self.egl_display);
62 }
63 if self.x11_display_is_owned {
64 (self.xlib.XCloseDisplay)(self.x11_display);
65 }
66 self.x11_display = ptr::null_mut();
67 }
68 }
69}
70
71impl Connection {
72 #[inline]
74 pub fn new() -> Result<Connection, Error> {
75 unsafe {
76 let xlib = Xlib::open().map_err(|_| Error::ConnectionFailed)?;
77
78 X_THREADS_INIT.call_once(|| {
79 (xlib.XInitThreads)();
80 });
81
82 let x11_display = (xlib.XOpenDisplay)(ptr::null());
83 if x11_display.is_null() {
84 return Err(Error::ConnectionFailed);
85 }
86
87 let egl_display = create_egl_display(x11_display);
88
89 Ok(Connection {
90 native_connection: Arc::new(NativeConnectionWrapper {
91 xlib,
92 egl_display,
93 egl_display_is_owned: true,
94 x11_display,
95 x11_display_is_owned: true,
96 }),
97 })
98 }
99 }
100
101 #[inline]
113 pub unsafe fn from_native_connection(
114 native_connection: NativeConnection,
115 ) -> Result<Connection, Error> {
116 let xlib = Xlib::open().map_err(|_| Error::ConnectionFailed)?;
117 Ok(Connection {
118 native_connection: Arc::new(NativeConnectionWrapper {
119 xlib,
120 egl_display: native_connection.egl_display,
121 egl_display_is_owned: false,
122 x11_display: native_connection.x11_display,
123 x11_display_is_owned: false,
124 }),
125 })
126 }
127
128 fn from_x11_display(x11_display: *mut Display, is_owned: bool) -> Result<Connection, Error> {
129 let xlib = Xlib::open().map_err(|_| Error::ConnectionFailed)?;
130 unsafe {
131 let egl_display = create_egl_display(x11_display);
132 Ok(Connection {
133 native_connection: Arc::new(NativeConnectionWrapper {
134 xlib,
135 egl_display,
136 egl_display_is_owned: true,
137 x11_display,
138 x11_display_is_owned: is_owned,
139 }),
140 })
141 }
142 }
143
144 #[inline]
146 pub fn native_connection(&self) -> NativeConnection {
147 NativeConnection {
148 egl_display: self.native_connection.egl_display,
149 x11_display: self.native_connection.x11_display,
150 }
151 }
152
153 #[inline]
155 pub fn gl_api(&self) -> GLApi {
156 GLApi::GL
157 }
158
159 #[inline]
163 pub fn create_adapter(&self) -> Result<Adapter, Error> {
164 self.create_hardware_adapter()
165 }
166
167 #[inline]
169 pub fn create_hardware_adapter(&self) -> Result<Adapter, Error> {
170 Ok(Adapter::hardware())
171 }
172
173 #[inline]
175 pub fn create_low_power_adapter(&self) -> Result<Adapter, Error> {
176 Ok(Adapter::low_power())
177 }
178
179 #[inline]
181 pub fn create_software_adapter(&self) -> Result<Adapter, Error> {
182 Ok(Adapter::software())
183 }
184
185 #[inline]
189 pub fn create_device(&self, adapter: &Adapter) -> Result<Device, Error> {
190 Device::new(self, adapter)
191 }
192
193 #[inline]
198 pub unsafe fn create_device_from_native_device(
199 &self,
200 native_device: NativeDevice,
201 ) -> Result<Device, Error> {
202 Device::new(self, &native_device.adapter)
203 }
204
205 #[cfg(feature = "sm-raw-window-handle-05")]
207 pub fn from_raw_display_handle(
208 raw_handle: rwh_05::RawDisplayHandle,
209 ) -> Result<Connection, Error> {
210 use rwh_05::RawDisplayHandle::Xcb;
211 use rwh_05::RawDisplayHandle::Xlib;
212 use rwh_05::XlibDisplayHandle;
213 let display = match raw_handle {
214 Xlib(XlibDisplayHandle { display, .. }) => display as *mut Display,
215 Xcb(_) => return Err(Error::Unimplemented),
216 _ => return Err(Error::IncompatibleRawDisplayHandle),
217 };
218
219 Connection::from_x11_display(display, false)
220 }
221
222 #[cfg(feature = "sm-raw-window-handle-06")]
224 pub fn from_display_handle(handle: rwh_06::DisplayHandle) -> Result<Connection, Error> {
225 use rwh_06::RawDisplayHandle::Xcb;
226 use rwh_06::RawDisplayHandle::Xlib;
227 use rwh_06::XlibDisplayHandle;
228 let display = match handle.as_raw() {
229 Xlib(XlibDisplayHandle {
230 display: Some(display),
231 ..
232 }) => display.as_ptr() as *mut Display,
233 Xcb(_) => return Err(Error::Unimplemented),
234 _ => return Err(Error::IncompatibleRawDisplayHandle),
235 };
236
237 Connection::from_x11_display(display, false)
238 }
239
240 pub unsafe fn create_native_widget_from_ptr(
242 &self,
243 raw: *mut c_void,
244 _size: Size2D<i32>,
245 ) -> NativeWidget {
246 NativeWidget {
247 window: std::mem::transmute(raw),
248 }
249 }
250
251 #[cfg(feature = "sm-raw-window-handle-05")]
253 pub fn create_native_widget_from_raw_window_handle(
254 &self,
255 raw_handle: rwh_05::RawWindowHandle,
256 _size: Size2D<i32>,
257 ) -> Result<NativeWidget, Error> {
258 use rwh_05::RawWindowHandle::Xlib;
259
260 match raw_handle {
261 Xlib(handle) => Ok(NativeWidget {
262 window: handle.window,
263 }),
264 _ => Err(Error::IncompatibleNativeWidget),
265 }
266 }
267
268 #[cfg(feature = "sm-raw-window-handle-06")]
270 pub fn create_native_widget_from_window_handle(
271 &self,
272 handle: rwh_06::WindowHandle,
273 _size: Size2D<i32>,
274 ) -> Result<NativeWidget, Error> {
275 use rwh_06::RawWindowHandle::Xlib;
276
277 match handle.as_raw() {
278 Xlib(handle) => Ok(NativeWidget {
279 window: handle.window,
280 }),
281 _ => Err(Error::IncompatibleNativeWidget),
282 }
283 }
284}
285
286impl NativeConnectionWrapper {
287 #[inline]
288 pub(crate) fn lock_display(&self) -> DisplayGuard<'_> {
289 unsafe {
290 let display = self.x11_display;
291 let xlib = &self.xlib;
292 (xlib.XLockDisplay)(display);
293 DisplayGuard {
294 xlib,
295 display,
296 phantom: PhantomData,
297 }
298 }
299 }
300}
301
302pub(crate) struct DisplayGuard<'a> {
303 xlib: &'a Xlib,
304 display: *mut Display,
305 phantom: PhantomData<&'a ()>,
306}
307
308impl<'a> Drop for DisplayGuard<'a> {
309 fn drop(&mut self) {
310 unsafe {
311 (self.xlib.XUnlockDisplay)(self.display);
312 }
313 }
314}
315
316impl<'a> DisplayGuard<'a> {
317 #[inline]
318 pub(crate) fn display(&self) -> *mut Display {
319 self.display
320 }
321}
322
323unsafe fn create_egl_display(display: *mut Display) -> EGLDisplay {
324 EGL_FUNCTIONS.with(|egl| {
325 let display_attributes = [egl::NONE as EGLAttrib];
326 let egl_display = egl.GetPlatformDisplay(
327 EGL_PLATFORM_X11_KHR,
328 display as *mut c_void,
329 display_attributes.as_ptr(),
330 );
331
332 let (mut egl_major_version, mut egl_minor_version) = (0, 0);
333 let ok = egl.Initialize(egl_display, &mut egl_major_version, &mut egl_minor_version);
334 assert_ne!(ok, egl::FALSE);
335
336 egl_display
337 })
338}
339
340unsafe fn terminate_egl_display(display: EGLDisplay) {
341 EGL_FUNCTIONS.with(|egl| {
342 egl.Terminate(display);
343 })
344}