surfman/wayland/
connection.rs1use 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#[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
29pub struct NativeConnection(pub EGLDisplay);
31
32unsafe impl Send for Connection {}
33
34impl Connection {
35 #[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 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 #[inline]
57 pub fn native_connection(&self) -> NativeConnection {
58 NativeConnection(self.native_connection.egl_display)
59 }
60
61 #[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 #[inline]
75 pub fn create_adapter(&self) -> Result<Adapter, Error> {
76 self.create_hardware_adapter()
77 }
78
79 #[inline]
81 pub fn create_hardware_adapter(&self) -> Result<Adapter, Error> {
82 Ok(Adapter::hardware())
83 }
84
85 #[inline]
87 pub fn create_low_power_adapter(&self) -> Result<Adapter, Error> {
88 Ok(Adapter::low_power())
89 }
90
91 #[inline]
93 pub fn create_software_adapter(&self) -> Result<Adapter, Error> {
94 Ok(Adapter::software())
95 }
96
97 #[inline]
101 pub fn create_device(&self, adapter: &Adapter) -> Result<Device, Error> {
102 Device::new(self, adapter)
103 }
104
105 #[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 #[cfg(feature = "sm-raw-window-handle-05")]
163 pub fn from_raw_display_handle(
164 raw_handle: rwh_05::RawDisplayHandle,
165 ) -> Result<Connection, Error> {
166 use rwh_05::RawDisplayHandle::Wayland;
167 use rwh_05::WaylandDisplayHandle;
168 unsafe {
169 let wayland_display = match raw_handle {
170 Wayland(WaylandDisplayHandle { display, .. }) => display as *mut wl_display,
171 _ => return Err(Error::IncompatibleRawDisplayHandle),
172 };
173
174 Connection::from_wayland_display(wayland_display, false)
175 }
176 }
177
178 #[cfg(feature = "sm-raw-window-handle-06")]
180 pub fn from_display_handle(handle: rwh_06::DisplayHandle) -> Result<Connection, Error> {
181 use rwh_06::RawDisplayHandle::Wayland;
182 use rwh_06::WaylandDisplayHandle;
183 unsafe {
184 let wayland_display = match handle.as_raw() {
185 Wayland(WaylandDisplayHandle { display, .. }) => {
186 display.as_ptr() as *mut wl_display
187 }
188 _ => return Err(Error::IncompatibleRawDisplayHandle),
189 };
190
191 Connection::from_wayland_display(wayland_display, false)
192 }
193 }
194
195 pub unsafe fn create_native_widget_from_ptr(
197 &self,
198 raw: *mut c_void,
199 size: Size2D<i32>,
200 ) -> NativeWidget {
201 NativeWidget {
202 wayland_surface: raw as *mut wl_proxy,
203 size,
204 }
205 }
206
207 #[cfg(feature = "sm-raw-window-handle-05")]
209 pub fn create_native_widget_from_raw_window_handle(
210 &self,
211 raw_handle: rwh_05::RawWindowHandle,
212 window_size: Size2D<i32>,
213 ) -> Result<NativeWidget, Error> {
214 use rwh_05::RawWindowHandle::Wayland;
215
216 let wayland_surface = match raw_handle {
217 Wayland(handle) => handle.surface as *mut wl_proxy,
218 _ => return Err(Error::IncompatibleNativeWidget),
219 };
220
221 Ok(NativeWidget {
222 wayland_surface,
223 size: window_size,
224 })
225 }
226
227 #[cfg(feature = "sm-raw-window-handle-06")]
229 pub fn create_native_widget_from_window_handle(
230 &self,
231 handle: rwh_06::WindowHandle,
232 window_size: Size2D<i32>,
233 ) -> Result<NativeWidget, Error> {
234 use rwh_06::RawWindowHandle::Wayland;
235
236 let wayland_surface = match handle.as_raw() {
237 Wayland(handle) => handle.surface.as_ptr() as *mut wl_proxy,
238 _ => return Err(Error::IncompatibleNativeWidget),
239 };
240
241 Ok(NativeWidget {
242 wayland_surface,
243 size: window_size,
244 })
245 }
246}
247
248impl Drop for NativeConnectionWrapper {
249 fn drop(&mut self) {
250 unsafe {
251 if let Some(wayland_display) = self.wayland_display {
252 (wayland_client_handle().wl_display_disconnect)(wayland_display);
253 }
254 }
255 }
256}
257
258impl NativeConnection {
259 #[inline]
261 pub fn current() -> Result<NativeConnection, Error> {
262 unsafe {
263 EGL_FUNCTIONS.with(|egl| {
264 let display = egl.GetCurrentDisplay();
265 if display != egl::NO_DISPLAY {
266 Ok(NativeConnection(display))
267 } else {
268 Err(Error::NoCurrentConnection)
269 }
270 })
271 }
272 }
273}