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