softbuffer/wayland/
mod.rs

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