surfman/x11/
connection.rs1use 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 x11_display: *mut Display,
35 is_owned: bool,
39}
40
41#[derive(Clone)]
43pub struct NativeConnection {
44 pub egl_display: EGLDisplay,
50 pub x11_display: *mut Display,
52}
53
54impl Drop for NativeConnectionWrapper {
55 #[inline]
56 fn drop(&mut self) {
57 unsafe {
58 if self.is_owned {
59 terminate_egl_display(self.egl_display);
60 (self.xlib.XCloseDisplay)(self.x11_display);
61 }
62 self.x11_display = ptr::null_mut();
63 }
64 }
65}
66
67impl Connection {
68 #[inline]
70 pub fn new() -> Result<Connection, Error> {
71 unsafe {
72 let xlib = Xlib::open().map_err(|_| Error::ConnectionFailed)?;
73
74 X_THREADS_INIT.call_once(|| {
75 (xlib.XInitThreads)();
76 });
77
78 let x11_display = (xlib.XOpenDisplay)(ptr::null());
79 if x11_display.is_null() {
80 return Err(Error::ConnectionFailed);
81 }
82
83 let egl_display = create_egl_display(x11_display);
84
85 Ok(Connection {
86 native_connection: Arc::new(NativeConnectionWrapper {
87 xlib,
88 egl_display,
89 x11_display,
90 is_owned: true,
91 }),
92 })
93 }
94 }
95
96 #[inline]
108 pub unsafe fn from_native_connection(
109 native_connection: NativeConnection,
110 ) -> Result<Connection, Error> {
111 let xlib = Xlib::open().map_err(|_| Error::ConnectionFailed)?;
112 Ok(Connection {
113 native_connection: Arc::new(NativeConnectionWrapper {
114 xlib,
115 egl_display: native_connection.egl_display,
116 x11_display: native_connection.x11_display,
117 is_owned: false,
118 }),
119 })
120 }
121
122 fn from_x11_display(x11_display: *mut Display) -> Result<Connection, Error> {
123 let xlib = Xlib::open().map_err(|_| Error::ConnectionFailed)?;
124 unsafe {
125 let egl_display = create_egl_display(x11_display);
126 Ok(Connection {
127 native_connection: Arc::new(NativeConnectionWrapper {
128 xlib,
129 egl_display,
130 x11_display,
131 is_owned: false,
132 }),
133 })
134 }
135 }
136
137 #[inline]
139 pub fn native_connection(&self) -> NativeConnection {
140 NativeConnection {
141 egl_display: self.native_connection.egl_display,
142 x11_display: self.native_connection.x11_display,
143 }
144 }
145
146 #[inline]
148 pub fn gl_api(&self) -> GLApi {
149 GLApi::GL
150 }
151
152 #[inline]
156 pub fn create_adapter(&self) -> Result<Adapter, Error> {
157 self.create_hardware_adapter()
158 }
159
160 #[inline]
162 pub fn create_hardware_adapter(&self) -> Result<Adapter, Error> {
163 Ok(Adapter::hardware())
164 }
165
166 #[inline]
168 pub fn create_low_power_adapter(&self) -> Result<Adapter, Error> {
169 Ok(Adapter::low_power())
170 }
171
172 #[inline]
174 pub fn create_software_adapter(&self) -> Result<Adapter, Error> {
175 Ok(Adapter::software())
176 }
177
178 #[inline]
182 pub fn create_device(&self, adapter: &Adapter) -> Result<Device, Error> {
183 Device::new(self, adapter)
184 }
185
186 #[inline]
191 pub unsafe fn create_device_from_native_device(
192 &self,
193 native_device: NativeDevice,
194 ) -> Result<Device, Error> {
195 Device::new(self, &native_device.adapter)
196 }
197
198 pub fn from_display_handle(
200 handle: raw_window_handle::DisplayHandle,
201 ) -> Result<Connection, Error> {
202 use raw_window_handle::RawDisplayHandle::Xcb;
203 use raw_window_handle::RawDisplayHandle::Xlib;
204 use raw_window_handle::XlibDisplayHandle;
205 let display = match handle.as_raw() {
206 Xlib(XlibDisplayHandle {
207 display: Some(display),
208 ..
209 }) => display.as_ptr() as *mut Display,
210 Xcb(_) => return Err(Error::Unimplemented),
211 _ => return Err(Error::IncompatibleRawDisplayHandle),
212 };
213
214 Connection::from_x11_display(display)
215 }
216
217 pub unsafe fn create_native_widget_from_ptr(
219 &self,
220 raw: *mut c_void,
221 _size: Size2D<i32>,
222 ) -> NativeWidget {
223 NativeWidget {
224 window: std::mem::transmute(raw),
225 }
226 }
227
228 pub fn create_native_widget_from_window_handle(
230 &self,
231 handle: raw_window_handle::WindowHandle,
232 _size: Size2D<i32>,
233 ) -> Result<NativeWidget, Error> {
234 use raw_window_handle::RawWindowHandle::Xlib;
235
236 match handle.as_raw() {
237 Xlib(handle) => Ok(NativeWidget {
238 window: handle.window,
239 }),
240 _ => Err(Error::IncompatibleNativeWidget),
241 }
242 }
243}
244
245impl NativeConnectionWrapper {
246 #[inline]
247 pub(crate) fn lock_display(&self) -> DisplayGuard<'_> {
248 unsafe {
249 let display = self.x11_display;
250 let xlib = &self.xlib;
251 (xlib.XLockDisplay)(display);
252 DisplayGuard {
253 xlib,
254 display,
255 phantom: PhantomData,
256 }
257 }
258 }
259}
260
261pub(crate) struct DisplayGuard<'a> {
262 xlib: &'a Xlib,
263 display: *mut Display,
264 phantom: PhantomData<&'a ()>,
265}
266
267impl<'a> Drop for DisplayGuard<'a> {
268 fn drop(&mut self) {
269 unsafe {
270 (self.xlib.XUnlockDisplay)(self.display);
271 }
272 }
273}
274
275impl<'a> DisplayGuard<'a> {
276 #[inline]
277 pub(crate) fn display(&self) -> *mut Display {
278 self.display
279 }
280}
281
282unsafe fn create_egl_display(display: *mut Display) -> EGLDisplay {
283 EGL_FUNCTIONS.with(|egl| {
284 let display_attributes = [egl::NONE as EGLAttrib];
285 let egl_display = egl.GetPlatformDisplay(
286 EGL_PLATFORM_X11_KHR,
287 display as *mut c_void,
288 display_attributes.as_ptr(),
289 );
290
291 let (mut egl_major_version, mut egl_minor_version) = (0, 0);
292 let ok = egl.Initialize(egl_display, &mut egl_major_version, &mut egl_minor_version);
293 assert_ne!(ok, egl::FALSE);
294
295 egl_display
296 })
297}
298
299unsafe fn terminate_egl_display(display: EGLDisplay) {
300 EGL_FUNCTIONS.with(|egl| {
301 let ok = egl.Terminate(display);
302 debug_assert_ne!(ok, egl::FALSE);
303 })
304}
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309
310 #[cfg_attr(not(feature = "sm-test"), test)]
311 pub fn test_from_x11_display() {
312 use crate::{ContextAttributeFlags, ContextAttributes, GLVersion};
313
314 let connection = Connection::new().unwrap();
315 let adapter = connection.create_low_power_adapter().unwrap();
316 let device = match connection.create_device(&adapter) {
317 Ok(device) => device,
318 Err(Error::RequiredExtensionUnavailable) => {
319 return;
321 }
322 Err(error) => panic!("Failed to create device: {error:?}"),
323 };
324
325 let context_descriptor = device
326 .create_context_descriptor(&ContextAttributes {
327 version: GLVersion::new(3, 0),
328 flags: ContextAttributeFlags::empty(),
329 })
330 .unwrap();
331
332 let mut context = device.create_context(&context_descriptor, None).unwrap();
333 device.make_context_current(&context).unwrap();
334
335 {
336 let _second_connection =
337 Connection::from_x11_display(connection.native_connection().x11_display).unwrap();
338 }
339
340 device.destroy_context(&mut context).unwrap();
341 }
342}