| 1 | use crate::{ |
| 2 | backend_interface::*, |
| 3 | error::{InitError, SwResultExt}, |
| 4 | util, Rect, SoftBufferError, |
| 5 | }; |
| 6 | use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; |
| 7 | use std::{ |
| 8 | num::{NonZeroI32, NonZeroU32}, |
| 9 | sync::{Arc, Mutex}, |
| 10 | }; |
| 11 | use wayland_client::{ |
| 12 | backend::{Backend, ObjectId}, |
| 13 | globals::{registry_queue_init, GlobalListContents}, |
| 14 | protocol::{wl_registry, wl_shm, wl_surface}, |
| 15 | Connection, Dispatch, EventQueue, Proxy, QueueHandle, |
| 16 | }; |
| 17 | |
| 18 | mod buffer; |
| 19 | use buffer::WaylandBuffer; |
| 20 | |
| 21 | struct State; |
| 22 | |
| 23 | pub struct WaylandDisplayImpl<D: ?Sized> { |
| 24 | conn: Option<Connection>, |
| 25 | event_queue: Mutex<EventQueue<State>>, |
| 26 | qh: QueueHandle<State>, |
| 27 | shm: wl_shm::WlShm, |
| 28 | |
| 29 | /// The object that owns the display handle. |
| 30 | /// |
| 31 | /// This has to be dropped *after* the `conn` field, because the `conn` field implicitly borrows |
| 32 | /// this. |
| 33 | _display: D, |
| 34 | } |
| 35 | |
| 36 | impl<D: HasDisplayHandle + ?Sized> WaylandDisplayImpl<D> { |
| 37 | fn conn(&self) -> &Connection { |
| 38 | self.conn.as_ref().unwrap() |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | impl<D: HasDisplayHandle + ?Sized> ContextInterface<D> for Arc<WaylandDisplayImpl<D>> { |
| 43 | fn new(display: D) -> Result<Self, InitError<D>> |
| 44 | where |
| 45 | D: Sized, |
| 46 | { |
| 47 | let raw = display.display_handle()?.as_raw(); |
| 48 | let wayland_handle = match raw { |
| 49 | RawDisplayHandle::Wayland(w) => w.display, |
| 50 | _ => return Err(InitError::Unsupported(display)), |
| 51 | }; |
| 52 | |
| 53 | let backend = unsafe { Backend::from_foreign_display(wayland_handle.as_ptr().cast()) }; |
| 54 | let conn = Connection::from_backend(backend); |
| 55 | let (globals, event_queue) = |
| 56 | registry_queue_init(&conn).swbuf_err("Failed to make round trip to server" )?; |
| 57 | let qh = event_queue.handle(); |
| 58 | let shm: wl_shm::WlShm = globals |
| 59 | .bind(&qh, 1..=1, ()) |
| 60 | .swbuf_err("Failed to instantiate Wayland Shm" )?; |
| 61 | Ok(Arc::new(WaylandDisplayImpl { |
| 62 | conn: Some(conn), |
| 63 | event_queue: Mutex::new(event_queue), |
| 64 | qh, |
| 65 | shm, |
| 66 | _display: display, |
| 67 | })) |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | impl<D: ?Sized> Drop for WaylandDisplayImpl<D> { |
| 72 | fn drop(&mut self) { |
| 73 | // Make sure the connection is dropped first. |
| 74 | self.conn = None; |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | pub struct WaylandImpl<D: ?Sized, W: ?Sized> { |
| 79 | display: Arc<WaylandDisplayImpl<D>>, |
| 80 | surface: Option<wl_surface::WlSurface>, |
| 81 | buffers: Option<(WaylandBuffer, WaylandBuffer)>, |
| 82 | size: Option<(NonZeroI32, NonZeroI32)>, |
| 83 | |
| 84 | /// The pointer to the window object. |
| 85 | /// |
| 86 | /// This has to be dropped *after* the `surface` field, because the `surface` field implicitly |
| 87 | /// borrows this. |
| 88 | window_handle: W, |
| 89 | } |
| 90 | |
| 91 | impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> WaylandImpl<D, W> { |
| 92 | fn surface(&self) -> &wl_surface::WlSurface { |
| 93 | self.surface.as_ref().unwrap() |
| 94 | } |
| 95 | |
| 96 | fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> { |
| 97 | let _ = self |
| 98 | .display |
| 99 | .event_queue |
| 100 | .lock() |
| 101 | .unwrap_or_else(|x| x.into_inner()) |
| 102 | .dispatch_pending(&mut State); |
| 103 | |
| 104 | if let Some((front, back)) = &mut self.buffers { |
| 105 | // Swap front and back buffer |
| 106 | std::mem::swap(front, back); |
| 107 | |
| 108 | front.age = 1; |
| 109 | if back.age != 0 { |
| 110 | back.age += 1; |
| 111 | } |
| 112 | |
| 113 | front.attach(self.surface.as_ref().unwrap()); |
| 114 | |
| 115 | // Like Mesa's EGL/WSI implementation, we damage the whole buffer with `i32::MAX` if |
| 116 | // the compositor doesn't support `damage_buffer`. |
| 117 | // https://bugs.freedesktop.org/show_bug.cgi?id=78190 |
| 118 | if self.surface().version() < 4 { |
| 119 | self.surface().damage(0, 0, i32::MAX, i32::MAX); |
| 120 | } else { |
| 121 | for rect in damage { |
| 122 | // Introduced in version 4, it is an error to use this request in version 3 or lower. |
| 123 | let (x, y, width, height) = (|| { |
| 124 | Some(( |
| 125 | i32::try_from(rect.x).ok()?, |
| 126 | i32::try_from(rect.y).ok()?, |
| 127 | i32::try_from(rect.width.get()).ok()?, |
| 128 | i32::try_from(rect.height.get()).ok()?, |
| 129 | )) |
| 130 | })() |
| 131 | .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?; |
| 132 | self.surface().damage_buffer(x, y, width, height); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | self.surface().commit(); |
| 137 | } |
| 138 | |
| 139 | let _ = self |
| 140 | .display |
| 141 | .event_queue |
| 142 | .lock() |
| 143 | .unwrap_or_else(|x| x.into_inner()) |
| 144 | .flush(); |
| 145 | |
| 146 | Ok(()) |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> |
| 151 | for WaylandImpl<D, W> |
| 152 | { |
| 153 | type Context = Arc<WaylandDisplayImpl<D>>; |
| 154 | type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a; |
| 155 | |
| 156 | fn new(window: W, display: &Arc<WaylandDisplayImpl<D>>) -> Result<Self, InitError<W>> { |
| 157 | // Get the raw Wayland window. |
| 158 | let raw = window.window_handle()?.as_raw(); |
| 159 | let wayland_handle = match raw { |
| 160 | RawWindowHandle::Wayland(w) => w.surface, |
| 161 | _ => return Err(InitError::Unsupported(window)), |
| 162 | }; |
| 163 | |
| 164 | let surface_id = unsafe { |
| 165 | ObjectId::from_ptr( |
| 166 | wl_surface::WlSurface::interface(), |
| 167 | wayland_handle.as_ptr().cast(), |
| 168 | ) |
| 169 | } |
| 170 | .swbuf_err("Failed to create proxy for surface ID." )?; |
| 171 | let surface = wl_surface::WlSurface::from_id(display.conn(), surface_id) |
| 172 | .swbuf_err("Failed to create proxy for surface ID." )?; |
| 173 | Ok(Self { |
| 174 | display: display.clone(), |
| 175 | surface: Some(surface), |
| 176 | buffers: Default::default(), |
| 177 | size: None, |
| 178 | window_handle: window, |
| 179 | }) |
| 180 | } |
| 181 | |
| 182 | #[inline ] |
| 183 | fn window(&self) -> &W { |
| 184 | &self.window_handle |
| 185 | } |
| 186 | |
| 187 | fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { |
| 188 | self.size = Some( |
| 189 | (|| { |
| 190 | let width = NonZeroI32::try_from(width).ok()?; |
| 191 | let height = NonZeroI32::try_from(height).ok()?; |
| 192 | Some((width, height)) |
| 193 | })() |
| 194 | .ok_or(SoftBufferError::SizeOutOfRange { width, height })?, |
| 195 | ); |
| 196 | Ok(()) |
| 197 | } |
| 198 | |
| 199 | fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> { |
| 200 | let (width, height) = self |
| 201 | .size |
| 202 | .expect("Must set size of surface before calling `buffer_mut()`" ); |
| 203 | |
| 204 | if let Some((_front, back)) = &mut self.buffers { |
| 205 | // Block if back buffer not released yet |
| 206 | if !back.released() { |
| 207 | let mut event_queue = self |
| 208 | .display |
| 209 | .event_queue |
| 210 | .lock() |
| 211 | .unwrap_or_else(|x| x.into_inner()); |
| 212 | while !back.released() { |
| 213 | event_queue.blocking_dispatch(&mut State).map_err(|err| { |
| 214 | SoftBufferError::PlatformError( |
| 215 | Some("Wayland dispatch failure" .to_string()), |
| 216 | Some(Box::new(err)), |
| 217 | ) |
| 218 | })?; |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | // Resize, if buffer isn't large enough |
| 223 | back.resize(width.get(), height.get()); |
| 224 | } else { |
| 225 | // Allocate front and back buffer |
| 226 | self.buffers = Some(( |
| 227 | WaylandBuffer::new( |
| 228 | &self.display.shm, |
| 229 | width.get(), |
| 230 | height.get(), |
| 231 | &self.display.qh, |
| 232 | ), |
| 233 | WaylandBuffer::new( |
| 234 | &self.display.shm, |
| 235 | width.get(), |
| 236 | height.get(), |
| 237 | &self.display.qh, |
| 238 | ), |
| 239 | )); |
| 240 | }; |
| 241 | |
| 242 | let age = self.buffers.as_mut().unwrap().1.age; |
| 243 | Ok(BufferImpl { |
| 244 | stack: util::BorrowStack::new(self, |buffer| { |
| 245 | Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() }) |
| 246 | })?, |
| 247 | age, |
| 248 | }) |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | impl<D: ?Sized, W: ?Sized> Drop for WaylandImpl<D, W> { |
| 253 | fn drop(&mut self) { |
| 254 | // Make sure the surface is dropped first. |
| 255 | self.surface = None; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | pub struct BufferImpl<'a, D: ?Sized, W> { |
| 260 | stack: util::BorrowStack<'a, WaylandImpl<D, W>, [u32]>, |
| 261 | age: u8, |
| 262 | } |
| 263 | |
| 264 | impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferInterface |
| 265 | for BufferImpl<'a, D, W> |
| 266 | { |
| 267 | #[inline ] |
| 268 | fn pixels(&self) -> &[u32] { |
| 269 | self.stack.member() |
| 270 | } |
| 271 | |
| 272 | #[inline ] |
| 273 | fn pixels_mut(&mut self) -> &mut [u32] { |
| 274 | self.stack.member_mut() |
| 275 | } |
| 276 | |
| 277 | fn age(&self) -> u8 { |
| 278 | self.age |
| 279 | } |
| 280 | |
| 281 | fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { |
| 282 | self.stack.into_container().present_with_damage(damage) |
| 283 | } |
| 284 | |
| 285 | fn present(self) -> Result<(), SoftBufferError> { |
| 286 | let imp = self.stack.into_container(); |
| 287 | let (width, height) = imp |
| 288 | .size |
| 289 | .expect("Must set size of surface before calling `present()`" ); |
| 290 | imp.present_with_damage(&[Rect { |
| 291 | x: 0, |
| 292 | y: 0, |
| 293 | // We know width/height will be non-negative |
| 294 | width: width.try_into().unwrap(), |
| 295 | height: height.try_into().unwrap(), |
| 296 | }]) |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State { |
| 301 | fn event( |
| 302 | _: &mut State, |
| 303 | _: &wl_registry::WlRegistry, |
| 304 | _: wl_registry::Event, |
| 305 | _: &GlobalListContents, |
| 306 | _: &Connection, |
| 307 | _: &QueueHandle<State>, |
| 308 | ) { |
| 309 | // Ignore globals added after initialization |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | impl Dispatch<wl_shm::WlShm, ()> for State { |
| 314 | fn event( |
| 315 | _: &mut State, |
| 316 | _: &wl_shm::WlShm, |
| 317 | _: wl_shm::Event, |
| 318 | _: &(), |
| 319 | _: &Connection, |
| 320 | _: &QueueHandle<State>, |
| 321 | ) { |
| 322 | } |
| 323 | } |
| 324 | |