1 use crate::{AsRaw, BufferObject, BufferObjectFlags, Format, Modifier, Ptr, Surface};
2 
3 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd};
4 
5 use std::error;
6 use std::ffi::CStr;
7 use std::fmt;
8 use std::io::{Error as IoError, Result as IoResult};
9 use std::ops::{Deref, DerefMut};
10 
11 #[cfg(feature = "import-wayland")]
12 use wayland_server::protocol::wl_buffer::WlBuffer;
13 
14 #[cfg(feature = "import-egl")]
15 /// An EGLImage handle
16 pub type EGLImage = *mut libc::c_void;
17 
18 #[cfg(feature = "drm-support")]
19 use drm::control::Device as DrmControlDevice;
20 #[cfg(feature = "drm-support")]
21 use drm::Device as DrmDevice;
22 
23 /// An open GBM device
24 pub struct Device<T: AsFd> {
25     // Declare `ffi` first so it is dropped before `fd`
26     ffi: Ptr<ffi::gbm_device>,
27     fd: T,
28 }
29 
30 impl<T: AsFd> fmt::Debug for Device<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result31     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32         f.debug_struct("Device")
33             .field("ptr", &format_args!("{:p}", &self.ffi))
34             .finish()
35     }
36 }
37 
38 impl<T: AsFd + Clone> Clone for Device<T> {
clone(&self) -> Device<T>39     fn clone(&self) -> Device<T> {
40         Device {
41             fd: self.fd.clone(),
42             ffi: self.ffi.clone(),
43         }
44     }
45 }
46 
47 impl<T: AsFd> AsFd for Device<T> {
as_fd(&self) -> BorrowedFd48     fn as_fd(&self) -> BorrowedFd {
49         unsafe { BorrowedFd::borrow_raw(ffi::gbm_device_get_fd(*self.ffi)) }
50     }
51 }
52 
53 impl<T: AsFd> AsRaw<ffi::gbm_device> for Device<T> {
as_raw(&self) -> *const ffi::gbm_device54     fn as_raw(&self) -> *const ffi::gbm_device {
55         *self.ffi
56     }
57 }
58 
59 impl<T: AsFd> Deref for Device<T> {
60     type Target = T;
deref(&self) -> &T61     fn deref(&self) -> &T {
62         &self.fd
63     }
64 }
65 
66 impl<T: AsFd> DerefMut for Device<T> {
deref_mut(&mut self) -> &mut T67     fn deref_mut(&mut self) -> &mut T {
68         &mut self.fd
69     }
70 }
71 
72 impl<T: AsFd> Device<T> {
73     /// Open a GBM device from a given open DRM device.
74     ///
75     /// The underlying file descriptor passed in is used by the backend to communicate with
76     /// platform for allocating the memory.  For allocations using DRI this would be
77     /// the file descriptor returned when opening a device such as `/dev/dri/card0`.
new(fd: T) -> IoResult<Device<T>>78     pub fn new(fd: T) -> IoResult<Device<T>> {
79         let ptr = unsafe { ffi::gbm_create_device(fd.as_fd().as_raw_fd()) };
80         if ptr.is_null() {
81             Err(IoError::last_os_error())
82         } else {
83             Ok(Device {
84                 fd,
85                 ffi: Ptr::<ffi::gbm_device>::new(ptr, |ptr| unsafe {
86                     ffi::gbm_device_destroy(ptr)
87                 }),
88             })
89         }
90     }
91 
92     /// Get the backend name
backend_name(&self) -> &str93     pub fn backend_name(&self) -> &str {
94         unsafe {
95             CStr::from_ptr(ffi::gbm_device_get_backend_name(*self.ffi))
96                 .to_str()
97                 .expect("GBM passed invalid utf8 string")
98         }
99     }
100 
101     /// Test if a format is supported for a given set of usage flags
is_format_supported(&self, format: Format, usage: BufferObjectFlags) -> bool102     pub fn is_format_supported(&self, format: Format, usage: BufferObjectFlags) -> bool {
103         unsafe { ffi::gbm_device_is_format_supported(*self.ffi, format as u32, usage.bits()) != 0 }
104     }
105 
106     /// Allocate a new surface object
create_surface<U: 'static>( &self, width: u32, height: u32, format: Format, usage: BufferObjectFlags, ) -> IoResult<Surface<U>>107     pub fn create_surface<U: 'static>(
108         &self,
109         width: u32,
110         height: u32,
111         format: Format,
112         usage: BufferObjectFlags,
113     ) -> IoResult<Surface<U>> {
114         let ptr = unsafe {
115             ffi::gbm_surface_create(*self.ffi, width, height, format as u32, usage.bits())
116         };
117         if ptr.is_null() {
118             Err(IoError::last_os_error())
119         } else {
120             Ok(unsafe { Surface::new(ptr, self.ffi.downgrade()) })
121         }
122     }
123 
124     /// Allocate a new surface object with explicit modifiers
create_surface_with_modifiers<U: 'static>( &self, width: u32, height: u32, format: Format, modifiers: impl Iterator<Item = Modifier>, ) -> IoResult<Surface<U>>125     pub fn create_surface_with_modifiers<U: 'static>(
126         &self,
127         width: u32,
128         height: u32,
129         format: Format,
130         modifiers: impl Iterator<Item = Modifier>,
131     ) -> IoResult<Surface<U>> {
132         let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
133         let ptr = unsafe {
134             ffi::gbm_surface_create_with_modifiers(
135                 *self.ffi,
136                 width,
137                 height,
138                 format as u32,
139                 mods.as_ptr(),
140                 mods.len() as u32,
141             )
142         };
143         if ptr.is_null() {
144             Err(IoError::last_os_error())
145         } else {
146             Ok(unsafe { Surface::new(ptr, self.ffi.downgrade()) })
147         }
148     }
149 
150     /// Allocate a new surface object with explicit modifiers and flags
create_surface_with_modifiers2<U: 'static>( &self, width: u32, height: u32, format: Format, modifiers: impl Iterator<Item = Modifier>, usage: BufferObjectFlags, ) -> IoResult<Surface<U>>151     pub fn create_surface_with_modifiers2<U: 'static>(
152         &self,
153         width: u32,
154         height: u32,
155         format: Format,
156         modifiers: impl Iterator<Item = Modifier>,
157         usage: BufferObjectFlags,
158     ) -> IoResult<Surface<U>> {
159         let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
160         let ptr = unsafe {
161             ffi::gbm_surface_create_with_modifiers2(
162                 *self.ffi,
163                 width,
164                 height,
165                 format as u32,
166                 mods.as_ptr(),
167                 mods.len() as u32,
168                 usage.bits(),
169             )
170         };
171         if ptr.is_null() {
172             Err(IoError::last_os_error())
173         } else {
174             Ok(unsafe { Surface::new(ptr, self.ffi.downgrade()) })
175         }
176     }
177 
178     ///  Allocate a buffer object for the given dimensions
create_buffer_object<U: 'static>( &self, width: u32, height: u32, format: Format, usage: BufferObjectFlags, ) -> IoResult<BufferObject<U>>179     pub fn create_buffer_object<U: 'static>(
180         &self,
181         width: u32,
182         height: u32,
183         format: Format,
184         usage: BufferObjectFlags,
185     ) -> IoResult<BufferObject<U>> {
186         let ptr =
187             unsafe { ffi::gbm_bo_create(*self.ffi, width, height, format as u32, usage.bits()) };
188         if ptr.is_null() {
189             Err(IoError::last_os_error())
190         } else {
191             Ok(unsafe { BufferObject::new(ptr, self.ffi.downgrade()) })
192         }
193     }
194 
195     ///  Allocate a buffer object for the given dimensions with explicit modifiers
create_buffer_object_with_modifiers<U: 'static>( &self, width: u32, height: u32, format: Format, modifiers: impl Iterator<Item = Modifier>, ) -> IoResult<BufferObject<U>>196     pub fn create_buffer_object_with_modifiers<U: 'static>(
197         &self,
198         width: u32,
199         height: u32,
200         format: Format,
201         modifiers: impl Iterator<Item = Modifier>,
202     ) -> IoResult<BufferObject<U>> {
203         let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
204         let ptr = unsafe {
205             ffi::gbm_bo_create_with_modifiers(
206                 *self.ffi,
207                 width,
208                 height,
209                 format as u32,
210                 mods.as_ptr(),
211                 mods.len() as u32,
212             )
213         };
214         if ptr.is_null() {
215             Err(IoError::last_os_error())
216         } else {
217             Ok(unsafe { BufferObject::new(ptr, self.ffi.downgrade()) })
218         }
219     }
220 
221     ///  Allocate a buffer object for the given dimensions with explicit modifiers and flags
create_buffer_object_with_modifiers2<U: 'static>( &self, width: u32, height: u32, format: Format, modifiers: impl Iterator<Item = Modifier>, usage: BufferObjectFlags, ) -> IoResult<BufferObject<U>>222     pub fn create_buffer_object_with_modifiers2<U: 'static>(
223         &self,
224         width: u32,
225         height: u32,
226         format: Format,
227         modifiers: impl Iterator<Item = Modifier>,
228         usage: BufferObjectFlags,
229     ) -> IoResult<BufferObject<U>> {
230         let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
231         let ptr = unsafe {
232             ffi::gbm_bo_create_with_modifiers2(
233                 *self.ffi,
234                 width,
235                 height,
236                 format as u32,
237                 mods.as_ptr(),
238                 mods.len() as u32,
239                 usage.bits(),
240             )
241         };
242         if ptr.is_null() {
243             Err(IoError::last_os_error())
244         } else {
245             Ok(unsafe { BufferObject::new(ptr, self.ffi.downgrade()) })
246         }
247     }
248 
249     /// Create a GBM buffer object from a wayland buffer
250     ///
251     /// This function imports a foreign [`WlBuffer`] object and creates a new GBM
252     /// buffer object for it.
253     /// This enables using the foreign object with a display API such as KMS.
254     ///
255     /// The GBM bo shares the underlying pixels but its life-time is
256     /// independent of the foreign object.
257     #[cfg(feature = "import-wayland")]
import_buffer_object_from_wayland<U: 'static>( &self, buffer: &WlBuffer, usage: BufferObjectFlags, ) -> IoResult<BufferObject<U>>258     pub fn import_buffer_object_from_wayland<U: 'static>(
259         &self,
260         buffer: &WlBuffer,
261         usage: BufferObjectFlags,
262     ) -> IoResult<BufferObject<U>> {
263         use wayland_server::Resource;
264 
265         let ptr = unsafe {
266             ffi::gbm_bo_import(
267                 *self.ffi,
268                 ffi::GBM_BO_IMPORT_WL_BUFFER as u32,
269                 buffer.id().as_ptr() as *mut _,
270                 usage.bits(),
271             )
272         };
273         if ptr.is_null() {
274             Err(IoError::last_os_error())
275         } else {
276             Ok(unsafe { BufferObject::new(ptr, self.ffi.downgrade()) })
277         }
278     }
279 
280     /// Create a GBM buffer object from an egl buffer
281     ///
282     /// This function imports a foreign [`EGLImage`] object and creates a new GBM
283     /// buffer object for it.
284     /// This enables using the foreign object with a display API such as KMS.
285     ///
286     /// The GBM bo shares the underlying pixels but its life-time is
287     /// independent of the foreign object.
288     ///
289     /// # Safety
290     ///
291     /// The given [`EGLImage`] is a raw pointer.  Passing null or an invalid [`EGLImage`] will
292     /// cause undefined behavior.
293     #[cfg(feature = "import-egl")]
import_buffer_object_from_egl<U: 'static>( &self, buffer: EGLImage, usage: BufferObjectFlags, ) -> IoResult<BufferObject<U>>294     pub unsafe fn import_buffer_object_from_egl<U: 'static>(
295         &self,
296         buffer: EGLImage,
297         usage: BufferObjectFlags,
298     ) -> IoResult<BufferObject<U>> {
299         let ptr = ffi::gbm_bo_import(
300             *self.ffi,
301             ffi::GBM_BO_IMPORT_EGL_IMAGE as u32,
302             buffer,
303             usage.bits(),
304         );
305         if ptr.is_null() {
306             Err(IoError::last_os_error())
307         } else {
308             Ok(BufferObject::new(ptr, self.ffi.downgrade()))
309         }
310     }
311 
312     /// Create a GBM buffer object from a dma buffer
313     ///
314     /// This function imports a foreign dma buffer from an open file descriptor
315     /// and creates a new GBM buffer object for it.
316     /// This enables using the foreign object with a display API such as KMS.
317     ///
318     /// The GBM bo shares the underlying pixels but its life-time is
319     /// independent of the foreign object.
import_buffer_object_from_dma_buf<U: 'static>( &self, buffer: BorrowedFd<'_>, width: u32, height: u32, stride: u32, format: Format, usage: BufferObjectFlags, ) -> IoResult<BufferObject<U>>320     pub fn import_buffer_object_from_dma_buf<U: 'static>(
321         &self,
322         buffer: BorrowedFd<'_>,
323         width: u32,
324         height: u32,
325         stride: u32,
326         format: Format,
327         usage: BufferObjectFlags,
328     ) -> IoResult<BufferObject<U>> {
329         let mut fd_data = ffi::gbm_import_fd_data {
330             fd: buffer.as_raw_fd(),
331             width,
332             height,
333             stride,
334             format: format as u32,
335         };
336 
337         let ptr = unsafe {
338             ffi::gbm_bo_import(
339                 *self.ffi,
340                 ffi::GBM_BO_IMPORT_FD as u32,
341                 &mut fd_data as *mut ffi::gbm_import_fd_data as *mut _,
342                 usage.bits(),
343             )
344         };
345         if ptr.is_null() {
346             Err(IoError::last_os_error())
347         } else {
348             Ok(unsafe { BufferObject::new(ptr, self.ffi.downgrade()) })
349         }
350     }
351 
352     /// Create a GBM buffer object from a dma buffer with explicit modifiers
353     ///
354     /// This function imports a foreign dma buffer from an open file descriptor
355     /// and creates a new GBM buffer object for it.
356     /// This enables using the foreign object with a display API such as KMS.
357     ///
358     /// The GBM bo shares the underlying pixels but its life-time is
359     /// independent of the foreign object.
360     #[allow(clippy::too_many_arguments)]
import_buffer_object_from_dma_buf_with_modifiers<U: 'static>( &self, len: u32, buffers: [Option<BorrowedFd<'_>>; 4], width: u32, height: u32, format: Format, usage: BufferObjectFlags, strides: [i32; 4], offsets: [i32; 4], modifier: Modifier, ) -> IoResult<BufferObject<U>>361     pub fn import_buffer_object_from_dma_buf_with_modifiers<U: 'static>(
362         &self,
363         len: u32,
364         buffers: [Option<BorrowedFd<'_>>; 4],
365         width: u32,
366         height: u32,
367         format: Format,
368         usage: BufferObjectFlags,
369         strides: [i32; 4],
370         offsets: [i32; 4],
371         modifier: Modifier,
372     ) -> IoResult<BufferObject<U>> {
373         let fds = buffers.map(|fd| fd.map_or(-1, |x| x.as_raw_fd()));
374         let mut fd_data = ffi::gbm_import_fd_modifier_data {
375             fds,
376             width,
377             height,
378             format: format as u32,
379             strides,
380             offsets,
381             modifier: modifier.into(),
382             num_fds: len,
383         };
384 
385         let ptr = unsafe {
386             ffi::gbm_bo_import(
387                 *self.ffi,
388                 ffi::GBM_BO_IMPORT_FD_MODIFIER as u32,
389                 &mut fd_data as *mut ffi::gbm_import_fd_modifier_data as *mut _,
390                 usage.bits(),
391             )
392         };
393         if ptr.is_null() {
394             Err(IoError::last_os_error())
395         } else {
396             Ok(unsafe { BufferObject::new(ptr, self.ffi.downgrade()) })
397         }
398     }
399 }
400 
401 #[cfg(feature = "drm-support")]
402 impl<T: DrmDevice + AsFd> DrmDevice for Device<T> {}
403 
404 #[cfg(feature = "drm-support")]
405 impl<T: DrmControlDevice + AsFd> DrmControlDevice for Device<T> {}
406 
407 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
408 /// Thrown when the underlying GBM device was already destroyed
409 pub struct DeviceDestroyedError;
410 
411 impl fmt::Display for DeviceDestroyedError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result412     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413         write!(f, "The underlying GBM device was already destroyed")
414     }
415 }
416 
417 impl error::Error for DeviceDestroyedError {
cause(&self) -> Option<&dyn error::Error>418     fn cause(&self) -> Option<&dyn error::Error> {
419         None
420     }
421 }
422