surfman/platform/unix/wayland/
connection.rs1use super::device::{Adapter, Device, NativeDevice};
6use super::surface::NativeWidget;
7use crate::egl;
8use crate::egl::types::{EGLAttrib, EGLDisplay};
9use crate::info::GLApi;
10use crate::platform::generic::egl::device::EGL_FUNCTIONS;
11use crate::platform::generic::egl::ffi::EGL_PLATFORM_WAYLAND_KHR;
12use crate::Error;
13
14use euclid::default::Size2D;
15use std::os::raw::c_void;
16use std::ptr;
17use std::sync::Arc;
18use wayland_sys::client::{wayland_client_handle, wl_display, wl_proxy};
19
20#[derive(Clone)]
22pub struct Connection {
23 pub(crate) native_connection: Arc<NativeConnectionWrapper>,
24}
25
26pub(crate) struct NativeConnectionWrapper {
27 pub(crate) egl_display: EGLDisplay,
28 wayland_display: Option<*mut wl_display>,
29}
30
31pub struct NativeConnection(pub EGLDisplay);
33
34unsafe impl Send for Connection {}
35
36impl Connection {
37 #[inline]
39 pub fn new() -> Result<Connection, Error> {
40 unsafe {
41 let wayland_display = (wayland_client_handle().wl_display_connect)(ptr::null());
42 Connection::from_wayland_display(wayland_display, true)
43 }
44 }
45
46 pub unsafe fn from_native_connection(
52 native_connection: NativeConnection,
53 ) -> Result<Connection, Error> {
54 Connection::from_egl_display(native_connection.0, None)
55 }
56
57 #[inline]
59 pub fn native_connection(&self) -> NativeConnection {
60 NativeConnection(self.native_connection.egl_display)
61 }
62
63 #[inline]
65 pub fn gl_api(&self) -> GLApi {
66 if std::env::var("SURFMAN_FORCE_GLES").is_ok() {
67 GLApi::GLES
68 } else {
69 GLApi::GL
70 }
71 }
72
73 #[inline]
77 pub fn create_adapter(&self) -> Result<Adapter, Error> {
78 self.create_hardware_adapter()
79 }
80
81 #[inline]
83 pub fn create_hardware_adapter(&self) -> Result<Adapter, Error> {
84 Ok(Adapter::hardware())
85 }
86
87 #[inline]
89 pub fn create_low_power_adapter(&self) -> Result<Adapter, Error> {
90 Ok(Adapter::low_power())
91 }
92
93 #[inline]
95 pub fn create_software_adapter(&self) -> Result<Adapter, Error> {
96 Ok(Adapter::software())
97 }
98
99 #[inline]
103 pub fn create_device(&self, adapter: &Adapter) -> Result<Device, Error> {
104 Device::new(self, adapter)
105 }
106
107 #[inline]
112 pub unsafe fn create_device_from_native_device(
113 &self,
114 native_device: NativeDevice,
115 ) -> Result<Device, Error> {
116 Device::new(self, &native_device.adapter)
117 }
118
119 unsafe fn from_wayland_display(
120 wayland_display: *mut wl_display,
121 is_owned: bool,
122 ) -> Result<Connection, Error> {
123 if wayland_display.is_null() {
124 return Err(Error::ConnectionFailed);
125 }
126
127 EGL_FUNCTIONS.with(|egl| {
128 let display_attributes = [egl::NONE as EGLAttrib];
129 let egl_display = egl.GetPlatformDisplay(
130 EGL_PLATFORM_WAYLAND_KHR,
131 wayland_display as *mut c_void,
132 display_attributes.as_ptr(),
133 );
134 if egl_display == egl::NO_DISPLAY {
135 return Err(Error::DeviceOpenFailed);
136 }
137
138 let (mut egl_major_version, mut egl_minor_version) = (0, 0);
139 let ok = egl.Initialize(egl_display, &mut egl_major_version, &mut egl_minor_version);
140 assert_ne!(ok, egl::FALSE);
141
142 let owned_display = if is_owned {
143 Some(wayland_display)
144 } else {
145 None
146 };
147 Connection::from_egl_display(egl_display, owned_display)
148 })
149 }
150
151 fn from_egl_display(
152 egl_display: EGLDisplay,
153 wayland_display: Option<*mut wl_display>,
154 ) -> Result<Connection, Error> {
155 Ok(Connection {
156 native_connection: Arc::new(NativeConnectionWrapper {
157 egl_display,
158 wayland_display,
159 }),
160 })
161 }
162
163 #[cfg(feature = "sm-raw-window-handle-05")]
165 pub fn from_raw_display_handle(
166 raw_handle: rwh_05::RawDisplayHandle,
167 ) -> Result<Connection, Error> {
168 use rwh_05::RawDisplayHandle::Wayland;
169 use rwh_05::WaylandDisplayHandle;
170 unsafe {
171 let wayland_display = match raw_handle {
172 Wayland(WaylandDisplayHandle { display, .. }) => display as *mut wl_display,
173 _ => return Err(Error::IncompatibleRawDisplayHandle),
174 };
175
176 Connection::from_wayland_display(wayland_display, false)
177 }
178 }
179
180 #[cfg(feature = "sm-raw-window-handle-06")]
182 pub fn from_display_handle(handle: rwh_06::DisplayHandle) -> Result<Connection, Error> {
183 use rwh_06::RawDisplayHandle::Wayland;
184 use rwh_06::WaylandDisplayHandle;
185 unsafe {
186 let wayland_display = match handle.as_raw() {
187 Wayland(WaylandDisplayHandle { display, .. }) => {
188 display.as_ptr() as *mut wl_display
189 }
190 _ => return Err(Error::IncompatibleRawDisplayHandle),
191 };
192
193 Connection::from_wayland_display(wayland_display, false)
194 }
195 }
196
197 pub unsafe fn create_native_widget_from_ptr(
199 &self,
200 raw: *mut c_void,
201 size: Size2D<i32>,
202 ) -> NativeWidget {
203 NativeWidget {
204 wayland_surface: raw as *mut wl_proxy,
205 size,
206 }
207 }
208
209 #[cfg(feature = "sm-raw-window-handle-05")]
211 pub fn create_native_widget_from_raw_window_handle(
212 &self,
213 raw_handle: rwh_05::RawWindowHandle,
214 window_size: Size2D<i32>,
215 ) -> Result<NativeWidget, Error> {
216 use rwh_05::RawWindowHandle::Wayland;
217
218 let wayland_surface = match raw_handle {
219 Wayland(handle) => handle.surface as *mut wl_proxy,
220 _ => return Err(Error::IncompatibleNativeWidget),
221 };
222
223 Ok(NativeWidget {
224 wayland_surface,
225 size: window_size,
226 })
227 }
228
229 #[cfg(feature = "sm-raw-window-handle-06")]
231 pub fn create_native_widget_from_window_handle(
232 &self,
233 handle: rwh_06::WindowHandle,
234 window_size: Size2D<i32>,
235 ) -> Result<NativeWidget, Error> {
236 use rwh_06::RawWindowHandle::Wayland;
237
238 let wayland_surface = match handle.as_raw() {
239 Wayland(handle) => handle.surface.as_ptr() as *mut wl_proxy,
240 _ => return Err(Error::IncompatibleNativeWidget),
241 };
242
243 Ok(NativeWidget {
244 wayland_surface,
245 size: window_size,
246 })
247 }
248}
249
250impl Drop for NativeConnectionWrapper {
251 fn drop(&mut self) {
252 unsafe {
253 if let Some(wayland_display) = self.wayland_display {
254 (wayland_client_handle().wl_display_disconnect)(wayland_display);
255 }
256 }
257 }
258}
259
260impl NativeConnection {
261 #[inline]
263 pub fn current() -> Result<NativeConnection, Error> {
264 unsafe {
265 EGL_FUNCTIONS.with(|egl| {
266 let display = egl.GetCurrentDisplay();
267 if display != egl::NO_DISPLAY {
268 Ok(NativeConnection(display))
269 } else {
270 Err(Error::NoCurrentConnection)
271 }
272 })
273 }
274 }
275}