gbm/
surface.rs

1use crate::{AsRaw, BufferObject, Ptr};
2use std::error;
3use std::fmt;
4use std::marker::PhantomData;
5
6/// A GBM rendering surface
7pub struct Surface<T: 'static> {
8    // Declare `ffi` first so it is dropped before `_device`
9    ffi: Ptr<ffi::gbm_surface>,
10    _device: Ptr<ffi::gbm_device>,
11    _bo_userdata: PhantomData<T>,
12}
13
14impl<T: 'static> fmt::Debug for Surface<T> {
15    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16        f.debug_struct("Surface")
17            .field("ptr", &format_args!("{:p}", &self.ffi))
18            .field("device", &format_args!("{:p}", &self._device))
19            .finish()
20    }
21}
22
23/// Errors that may happen when locking the front buffer
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct FrontBufferError;
26
27impl fmt::Display for FrontBufferError {
28    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29        write!(f, "Unknown error")
30    }
31}
32
33impl error::Error for FrontBufferError {}
34
35impl<T: 'static> Surface<T> {
36    ///  Return whether or not a surface has free (non-locked) buffers
37    ///
38    /// Before starting a new frame, the surface must have a buffer
39    /// available for rendering.  Initially, a GBM surface will have a free
40    /// buffer, but after one or more buffers
41    /// [have been locked](Self::lock_front_buffer()),
42    /// the application must check for a free buffer before rendering.
43    pub fn has_free_buffers(&self) -> bool {
44        unsafe { ffi::gbm_surface_has_free_buffers(*self.ffi) != 0 }
45    }
46
47    /// Lock the surface's current front buffer
48    ///
49    /// Locks rendering to the surface's current front buffer and returns
50    /// a handle to the underlying [`BufferObject`].
51    ///
52    /// If an error occurs a [`FrontBufferError`] is returned.
53    ///
54    /// # Safety
55    /// This function must be called exactly once after calling
56    /// `eglSwapBuffers`.  Calling it before any `eglSwapBuffers` has happened
57    /// on the surface or two or more times after `eglSwapBuffers` is an
58    /// error and may cause undefined behavior.
59    pub unsafe fn lock_front_buffer(&self) -> Result<BufferObject<T>, FrontBufferError> {
60        let buffer_ptr = ffi::gbm_surface_lock_front_buffer(*self.ffi);
61        if !buffer_ptr.is_null() {
62            let surface_ptr = self.ffi.clone();
63            let buffer = BufferObject {
64                ffi: Ptr::new(buffer_ptr, move |ptr| {
65                    ffi::gbm_surface_release_buffer(*surface_ptr, ptr);
66                }),
67                _device: self._device.clone(),
68                _userdata: std::marker::PhantomData,
69            };
70            Ok(buffer)
71        } else {
72            Err(FrontBufferError)
73        }
74    }
75
76    pub(crate) unsafe fn new(
77        ffi: *mut ffi::gbm_surface,
78        device: Ptr<ffi::gbm_device>,
79    ) -> Surface<T> {
80        Surface {
81            ffi: Ptr::new(ffi, |ptr| ffi::gbm_surface_destroy(ptr)),
82            _device: device,
83            _bo_userdata: PhantomData,
84        }
85    }
86}
87
88impl<T: 'static> AsRaw<ffi::gbm_surface> for Surface<T> {
89    fn as_raw(&self) -> *const ffi::gbm_surface {
90        *self.ffi
91    }
92}