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