1 | use crate::{AsRaw, BufferObject, Ptr}; |
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 | // 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 | |
14 | impl<T: 'static> fmt::Debug for Surface<T> { |
15 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
16 | f&mut DebugStruct<'_, '_>.debug_struct("Surface" ) |
17 | .field("ptr" , &format_args!(" {:p}" , &self.ffi)) |
18 | .field(name:"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)] |
25 | pub struct FrontBufferError; |
26 | |
27 | impl fmt::Display for FrontBufferError { |
28 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
29 | write!(f, "Unknown error" ) |
30 | } |
31 | } |
32 | |
33 | impl error::Error for FrontBufferError {} |
34 | |
35 | impl<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 | |
88 | impl<T: 'static> AsRaw<ffi::gbm_surface> for Surface<T> { |
89 | fn as_raw(&self) -> *const ffi::gbm_surface { |
90 | *self.ffi |
91 | } |
92 | } |
93 | |