Skip to main content

surfman/wayland/
connection.rs

1//! A wrapper for Wayland connections (displays).
2
3use super::device::{Adapter, Device, NativeDevice};
4use super::surface::NativeWidget;
5use crate::base::egl::device::EGL_FUNCTIONS;
6use crate::base::egl::ffi::EGL_PLATFORM_WAYLAND_KHR;
7use crate::egl;
8use crate::egl::types::{EGLAttrib, EGLDisplay};
9use crate::info::GLApi;
10use crate::Error;
11
12use euclid::default::Size2D;
13use std::os::raw::c_void;
14use std::ptr;
15use std::sync::Arc;
16use wayland_sys::client::{wayland_client_handle, wl_display, wl_proxy};
17
18/// A connection to the Wayland server.
19#[derive(Clone)]
20pub struct Connection {
21    pub(crate) native_connection: Arc<NativeConnectionWrapper>,
22}
23
24pub(crate) struct NativeConnectionWrapper {
25    pub(crate) egl_display: EGLDisplay,
26    wayland_display: Option<*mut wl_display>,
27}
28
29/// An EGL display wrapping a Wayland display.
30pub struct NativeConnection(pub EGLDisplay);
31
32unsafe impl Send for Connection {}
33
34impl Connection {
35    /// Connects to the default Wayland server.
36    #[inline]
37    pub fn new() -> Result<Connection, Error> {
38        unsafe {
39            let wayland_display = (wayland_client_handle().wl_display_connect)(ptr::null());
40            Connection::from_wayland_display(wayland_display, true)
41        }
42    }
43
44    /// Wraps an existing EGL display in a `Connection`.
45    ///
46    /// The display is not retained, as there is no way to do this in the EGL API. Therefore, it is
47    /// the caller's responsibility to ensure that the EGL display remains alive as long as the
48    /// connection is.
49    pub unsafe fn from_native_connection(
50        native_connection: NativeConnection,
51    ) -> Result<Connection, Error> {
52        Connection::from_egl_display(native_connection.0, None)
53    }
54
55    /// Returns the underlying native connection.
56    #[inline]
57    pub fn native_connection(&self) -> NativeConnection {
58        NativeConnection(self.native_connection.egl_display)
59    }
60
61    /// Returns the OpenGL API flavor that this connection supports (OpenGL or OpenGL ES).
62    #[inline]
63    pub fn gl_api(&self) -> GLApi {
64        if std::env::var("SURFMAN_FORCE_GLES").is_ok() {
65            GLApi::GLES
66        } else {
67            GLApi::GL
68        }
69    }
70
71    /// Returns the "best" adapter on this system, preferring high-performance hardware adapters.
72    ///
73    /// This is an alias for `Connection::create_hardware_adapter()`.
74    #[inline]
75    pub fn create_adapter(&self) -> Result<Adapter, Error> {
76        self.create_hardware_adapter()
77    }
78
79    /// Returns the "best" adapter on this system, preferring high-performance hardware adapters.
80    #[inline]
81    pub fn create_hardware_adapter(&self) -> Result<Adapter, Error> {
82        Ok(Adapter::hardware())
83    }
84
85    /// Returns the "best" adapter on this system, preferring low-power hardware adapters.
86    #[inline]
87    pub fn create_low_power_adapter(&self) -> Result<Adapter, Error> {
88        Ok(Adapter::low_power())
89    }
90
91    /// Returns the "best" adapter on this system, preferring software adapters.
92    #[inline]
93    pub fn create_software_adapter(&self) -> Result<Adapter, Error> {
94        Ok(Adapter::software())
95    }
96
97    /// Opens the hardware device corresponding to the given adapter.
98    ///
99    /// Device handles are local to a single thread.
100    #[inline]
101    pub fn create_device(&self, adapter: &Adapter) -> Result<Device, Error> {
102        Device::new(self, adapter)
103    }
104
105    /// Opens the hardware device corresponding to the adapter wrapped in the given native
106    /// device.
107    ///
108    /// This is present for compatibility with other backends.
109    #[inline]
110    pub unsafe fn create_device_from_native_device(
111        &self,
112        native_device: NativeDevice,
113    ) -> Result<Device, Error> {
114        Device::new(self, &native_device.adapter)
115    }
116
117    unsafe fn from_wayland_display(
118        wayland_display: *mut wl_display,
119        is_owned: bool,
120    ) -> Result<Connection, Error> {
121        if wayland_display.is_null() {
122            return Err(Error::ConnectionFailed);
123        }
124
125        EGL_FUNCTIONS.with(|egl| {
126            let display_attributes = [egl::NONE as EGLAttrib];
127            let egl_display = egl.GetPlatformDisplay(
128                EGL_PLATFORM_WAYLAND_KHR,
129                wayland_display as *mut c_void,
130                display_attributes.as_ptr(),
131            );
132            if egl_display == egl::NO_DISPLAY {
133                return Err(Error::DeviceOpenFailed);
134            }
135
136            let (mut egl_major_version, mut egl_minor_version) = (0, 0);
137            let ok = egl.Initialize(egl_display, &mut egl_major_version, &mut egl_minor_version);
138            assert_ne!(ok, egl::FALSE);
139
140            let owned_display = if is_owned {
141                Some(wayland_display)
142            } else {
143                None
144            };
145            Connection::from_egl_display(egl_display, owned_display)
146        })
147    }
148
149    fn from_egl_display(
150        egl_display: EGLDisplay,
151        wayland_display: Option<*mut wl_display>,
152    ) -> Result<Connection, Error> {
153        Ok(Connection {
154            native_connection: Arc::new(NativeConnectionWrapper {
155                egl_display,
156                wayland_display,
157            }),
158        })
159    }
160
161    /// Opens the display connection corresponding to the given `DisplayHandle`.
162    pub fn from_display_handle(
163        handle: raw_window_handle::DisplayHandle,
164    ) -> Result<Connection, Error> {
165        use raw_window_handle::RawDisplayHandle::Wayland;
166        use raw_window_handle::WaylandDisplayHandle;
167        unsafe {
168            let wayland_display = match handle.as_raw() {
169                Wayland(WaylandDisplayHandle { display, .. }) => {
170                    display.as_ptr() as *mut wl_display
171                }
172                _ => return Err(Error::IncompatibleRawDisplayHandle),
173            };
174
175            Connection::from_wayland_display(wayland_display, false)
176        }
177    }
178
179    /// Create a native widget from a raw pointer
180    pub unsafe fn create_native_widget_from_ptr(
181        &self,
182        raw: *mut c_void,
183        size: Size2D<i32>,
184    ) -> NativeWidget {
185        NativeWidget {
186            wayland_surface: raw as *mut wl_proxy,
187            size,
188        }
189    }
190
191    /// Creates a native widget type from the given `WindowHandle`
192    pub fn create_native_widget_from_window_handle(
193        &self,
194        handle: raw_window_handle::WindowHandle,
195        window_size: Size2D<i32>,
196    ) -> Result<NativeWidget, Error> {
197        use raw_window_handle::RawWindowHandle::Wayland;
198
199        let wayland_surface = match handle.as_raw() {
200            Wayland(handle) => handle.surface.as_ptr() as *mut wl_proxy,
201            _ => return Err(Error::IncompatibleNativeWidget),
202        };
203
204        Ok(NativeWidget {
205            wayland_surface,
206            size: window_size,
207        })
208    }
209}
210
211impl Drop for NativeConnectionWrapper {
212    fn drop(&mut self) {
213        unsafe {
214            if let Some(wayland_display) = self.wayland_display {
215                (wayland_client_handle().wl_display_disconnect)(wayland_display);
216            }
217        }
218    }
219}
220
221impl NativeConnection {
222    /// Returns the current native connection, if applicable.
223    #[inline]
224    pub fn current() -> Result<NativeConnection, Error> {
225        unsafe {
226            EGL_FUNCTIONS.with(|egl| {
227                let display = egl.GetCurrentDisplay();
228                if display != egl::NO_DISPLAY {
229                    Ok(NativeConnection(display))
230                } else {
231                    Err(Error::NoCurrentConnection)
232                }
233            })
234        }
235    }
236}