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 /// 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 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result34 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) => write!(f, "Buffer was destroyed: {}", err), 39 } 40 } 41 } 42 43 impl error::Error for FrontBufferError { cause(&self) -> Option<&dyn error::Error>44 fn cause(&self) -> Option<&dyn error::Error> { 45 match *self { 46 FrontBufferError::Destroyed(ref err) => 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. has_free_buffers(&self) -> bool60 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. lock_front_buffer(&self) -> Result<BufferObject<T>, FrontBufferError>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 new( ffi: *mut ffi::gbm_surface, device: WeakPtr<ffi::gbm_device>, ) -> Surface<T>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> { as_raw(&self) -> *const ffi::gbm_surface122 fn as_raw(&self) -> *const ffi::gbm_surface { 123 *self.ffi 124 } 125 } 126