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