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 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 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 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 #[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}