1 | use crate::{error::SwResultExt, util, Rect, SoftBufferError}; |
2 | use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle}; |
3 | use std::{ |
4 | cell::RefCell, |
5 | num::{NonZeroI32, NonZeroU32}, |
6 | rc::Rc, |
7 | }; |
8 | use 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 | |
15 | mod buffer; |
16 | use buffer::WaylandBuffer; |
17 | |
18 | struct State; |
19 | |
20 | pub struct WaylandDisplayImpl { |
21 | conn: Connection, |
22 | event_queue: RefCell<EventQueue<State>>, |
23 | qh: QueueHandle<State>, |
24 | shm: wl_shm::WlShm, |
25 | } |
26 | |
27 | impl 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 | |
47 | pub struct WaylandImpl { |
48 | display: Rc<WaylandDisplayImpl>, |
49 | surface: wl_surface::WlSurface, |
50 | buffers: Option<(WaylandBuffer, WaylandBuffer)>, |
51 | size: Option<(NonZeroI32, NonZeroI32)>, |
52 | } |
53 | |
54 | impl 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 | |
190 | pub struct BufferImpl<'a> { |
191 | stack: util::BorrowStack<'a, WaylandImpl, [u32]>, |
192 | age: u8, |
193 | } |
194 | |
195 | impl<'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 | |
229 | impl 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 | |
242 | impl 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 | |