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