1use crate::{error::SwResultExt, util, Rect, SoftBufferError};
2use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle};
3use std::{
4 cell::RefCell,
5 num::{NonZeroI32, NonZeroU32},
6 rc::Rc,
7};
8use wayland_client::{
9 backend::{Backend, ObjectId},
10 globals::{registry_queue_init, GlobalListContents},
11 protocol::{wl_registry, wl_shm, wl_surface},
12 Connection, Dispatch, EventQueue, Proxy, QueueHandle,
13};
14
15mod buffer;
16use buffer::WaylandBuffer;
17
18struct State;
19
20pub struct WaylandDisplayImpl {
21 conn: Connection,
22 event_queue: RefCell<EventQueue<State>>,
23 qh: QueueHandle<State>,
24 shm: wl_shm::WlShm,
25}
26
27impl WaylandDisplayImpl {
28 pub unsafe fn new(display_handle: WaylandDisplayHandle) -> Result<Self, SoftBufferError> {
29 // SAFETY: Ensured by user
30 let backend: Backend = unsafe { Backend::from_foreign_display(display_handle.display as *mut _) };
31 let conn: Connection = Connection::from_backend(backend);
32 let (globals: GlobalList, event_queue: EventQueue) =
33 registry_queue_init(&conn).swbuf_err(msg:"Failed to make round trip to server")?;
34 let qh: QueueHandle = event_queue.handle();
35 let shm: wl_shm::WlShm = globals
36 .bind(&qh, 1..=1, ())
37 .swbuf_err(msg:"Failed to instantiate Wayland Shm")?;
38 Ok(Self {
39 conn,
40 event_queue: RefCell::new(event_queue),
41 qh,
42 shm,
43 })
44 }
45}
46
47pub struct WaylandImpl {
48 display: Rc<WaylandDisplayImpl>,
49 surface: wl_surface::WlSurface,
50 buffers: Option<(WaylandBuffer, WaylandBuffer)>,
51 size: Option<(NonZeroI32, NonZeroI32)>,
52}
53
54impl WaylandImpl {
55 pub unsafe fn new(
56 window_handle: WaylandWindowHandle,
57 display: Rc<WaylandDisplayImpl>,
58 ) -> Result<Self, SoftBufferError> {
59 // SAFETY: Ensured by user
60 let surface_id = unsafe {
61 ObjectId::from_ptr(
62 wl_surface::WlSurface::interface(),
63 window_handle.surface as _,
64 )
65 }
66 .swbuf_err("Failed to create proxy for surface ID.")?;
67 let surface = wl_surface::WlSurface::from_id(&display.conn, surface_id)
68 .swbuf_err("Failed to create proxy for surface ID.")?;
69 Ok(Self {
70 display,
71 surface,
72 buffers: Default::default(),
73 size: None,
74 })
75 }
76
77 pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
78 self.size = Some(
79 (|| {
80 let width = NonZeroI32::try_from(width).ok()?;
81 let height = NonZeroI32::try_from(height).ok()?;
82 Some((width, height))
83 })()
84 .ok_or(SoftBufferError::SizeOutOfRange { width, height })?,
85 );
86 Ok(())
87 }
88
89 pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
90 let (width, height) = self
91 .size
92 .expect("Must set size of surface before calling `buffer_mut()`");
93
94 if let Some((_front, back)) = &mut self.buffers {
95 // Block if back buffer not released yet
96 if !back.released() {
97 let mut event_queue = self.display.event_queue.borrow_mut();
98 while !back.released() {
99 event_queue.blocking_dispatch(&mut State).map_err(|err| {
100 SoftBufferError::PlatformError(
101 Some("Wayland dispatch failure".to_string()),
102 Some(Box::new(err)),
103 )
104 })?;
105 }
106 }
107
108 // Resize, if buffer isn't large enough
109 back.resize(width.get(), height.get());
110 } else {
111 // Allocate front and back buffer
112 self.buffers = Some((
113 WaylandBuffer::new(
114 &self.display.shm,
115 width.get(),
116 height.get(),
117 &self.display.qh,
118 ),
119 WaylandBuffer::new(
120 &self.display.shm,
121 width.get(),
122 height.get(),
123 &self.display.qh,
124 ),
125 ));
126 };
127
128 let age = self.buffers.as_mut().unwrap().1.age;
129 Ok(BufferImpl {
130 stack: util::BorrowStack::new(self, |buffer| {
131 Ok(unsafe { buffer.buffers.as_mut().unwrap().1.mapped_mut() })
132 })?,
133 age,
134 })
135 }
136
137 /// Fetch the buffer from the window.
138 pub fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
139 Err(SoftBufferError::Unimplemented)
140 }
141
142 fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
143 let _ = self
144 .display
145 .event_queue
146 .borrow_mut()
147 .dispatch_pending(&mut State);
148
149 if let Some((front, back)) = &mut self.buffers {
150 // Swap front and back buffer
151 std::mem::swap(front, back);
152
153 front.age = 1;
154 if back.age != 0 {
155 back.age += 1;
156 }
157
158 front.attach(&self.surface);
159
160 // Like Mesa's EGL/WSI implementation, we damage the whole buffer with `i32::MAX` if
161 // the compositor doesn't support `damage_buffer`.
162 // https://bugs.freedesktop.org/show_bug.cgi?id=78190
163 if self.surface.version() < 4 {
164 self.surface.damage(0, 0, i32::MAX, i32::MAX);
165 } else {
166 for rect in damage {
167 // Introduced in version 4, it is an error to use this request in version 3 or lower.
168 let (x, y, width, height) = (|| {
169 Some((
170 i32::try_from(rect.x).ok()?,
171 i32::try_from(rect.y).ok()?,
172 i32::try_from(rect.width.get()).ok()?,
173 i32::try_from(rect.height.get()).ok()?,
174 ))
175 })()
176 .ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
177 self.surface.damage_buffer(x, y, width, height);
178 }
179 }
180
181 self.surface.commit();
182 }
183
184 let _ = self.display.event_queue.borrow_mut().flush();
185
186 Ok(())
187 }
188}
189
190pub struct BufferImpl<'a> {
191 stack: util::BorrowStack<'a, WaylandImpl, [u32]>,
192 age: u8,
193}
194
195impl<'a> BufferImpl<'a> {
196 #[inline]
197 pub fn pixels(&self) -> &[u32] {
198 self.stack.member()
199 }
200
201 #[inline]
202 pub fn pixels_mut(&mut self) -> &mut [u32] {
203 self.stack.member_mut()
204 }
205
206 pub fn age(&self) -> u8 {
207 self.age
208 }
209
210 pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
211 self.stack.into_container().present_with_damage(damage)
212 }
213
214 pub fn present(self) -> Result<(), SoftBufferError> {
215 let imp = self.stack.into_container();
216 let (width, height) = imp
217 .size
218 .expect("Must set size of surface before calling `present()`");
219 imp.present_with_damage(&[Rect {
220 x: 0,
221 y: 0,
222 // We know width/height will be non-negative
223 width: width.try_into().unwrap(),
224 height: height.try_into().unwrap(),
225 }])
226 }
227}
228
229impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
230 fn event(
231 _: &mut State,
232 _: &wl_registry::WlRegistry,
233 _: wl_registry::Event,
234 _: &GlobalListContents,
235 _: &Connection,
236 _: &QueueHandle<State>,
237 ) {
238 // Ignore globals added after initialization
239 }
240}
241
242impl Dispatch<wl_shm::WlShm, ()> for State {
243 fn event(
244 _: &mut State,
245 _: &wl_shm::WlShm,
246 _: wl_shm::Event,
247 _: &(),
248 _: &Connection,
249 _: &QueueHandle<State>,
250 ) {
251 }
252}
253