gbm/
buffer_object.rs

1#![allow(clippy::unnecessary_cast)]
2
3use crate::{AsRaw, Format, Modifier, Ptr};
4
5#[cfg(feature = "drm-support")]
6use drm::buffer::{Buffer as DrmBuffer, Handle, PlanarBuffer as DrmPlanarBuffer};
7use std::os::unix::io::{BorrowedFd, FromRawFd, OwnedFd};
8
9use std::error;
10use std::fmt;
11use std::io::{Error as IoError, Result as IoResult};
12use std::marker::PhantomData;
13use std::ops::{Deref, DerefMut};
14use std::ptr;
15use std::slice;
16
17/// A GBM buffer object
18pub struct BufferObject<T: 'static> {
19    // Declare `ffi` first so it is dropped before `_device`
20    pub(crate) ffi: Ptr<ffi::gbm_bo>,
21    pub(crate) _device: Ptr<ffi::gbm_device>,
22    pub(crate) _userdata: PhantomData<T>,
23}
24
25impl<T> fmt::Debug for BufferObject<T> {
26    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27        f.debug_struct("BufferObject")
28            .field("ptr", &format_args!("{:p}", self.ffi))
29            .field("device", &format_args!("{:p}", &self._device))
30            .field("width", &self.width())
31            .field("height", &self.height())
32            .field("offsets", &self.offsets())
33            .field("stride", &self.stride())
34            .field("format", &self.format())
35            .field("modifier", &self.modifier())
36            .finish()
37    }
38}
39
40bitflags! {
41    /// Flags to indicate the intended use for the buffer - these are passed into
42    /// [`Device::create_buffer_object()`].
43    ///
44    /// Use [`Device::is_format_supported()`] to check if the combination of format
45    /// and use flags are supported
46    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
47    #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
48    pub struct BufferObjectFlags: u32 {
49        /// Buffer is going to be presented to the screen using an API such as KMS
50        const SCANOUT      = ffi::gbm_bo_flags::GBM_BO_USE_SCANOUT as u32;
51        /// Buffer is going to be used as cursor
52        const CURSOR       = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR as u32;
53        /// Buffer is going to be used as cursor (deprecated)
54        #[deprecated = "Use CURSOR instead"]
55        const CURSOR_64X64 = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR_64X64 as u32;
56        /// Buffer is to be used for rendering - for example it is going to be used
57        /// as the storage for a color buffer
58        const RENDERING    = ffi::gbm_bo_flags::GBM_BO_USE_RENDERING as u32;
59        /// Buffer can be used for [`BufferObject::write()`].  This is guaranteed to work
60        /// with [`Self::CURSOR`], but may not work for other combinations.
61        const WRITE        = ffi::gbm_bo_flags::GBM_BO_USE_WRITE as u32;
62        /// Buffer is linear, i.e. not tiled.
63        const LINEAR       = ffi::gbm_bo_flags::GBM_BO_USE_LINEAR as u32;
64        /// Buffer is protected
65        const PROTECTED    = ffi::gbm_bo_flags::GBM_BO_USE_PROTECTED as u32;
66    }
67}
68
69/// Abstraction representing the handle to a buffer allocated by the manager
70pub type BufferObjectHandle = ffi::gbm_bo_handle;
71
72enum BORef<'a, T: 'static> {
73    Ref(&'a BufferObject<T>),
74    Mut(&'a mut BufferObject<T>),
75}
76
77/// A mapped buffer object
78pub struct MappedBufferObject<'a, T: 'static> {
79    bo: BORef<'a, T>,
80    buffer: &'a mut [u8],
81    data: *mut ::libc::c_void,
82    stride: u32,
83    height: u32,
84    width: u32,
85    x: u32,
86    y: u32,
87}
88
89impl<'a, T> fmt::Debug for MappedBufferObject<'a, T> {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        f.debug_struct("MappedBufferObject")
92            .field(
93                "mode",
94                &match self.bo {
95                    BORef::Ref(_) => format_args!("read"),
96                    BORef::Mut(_) => format_args!("write"),
97                },
98            )
99            .field(
100                "buffer",
101                match &self.bo {
102                    BORef::Ref(bo) => *bo,
103                    BORef::Mut(bo) => *bo,
104                },
105            )
106            .finish()
107    }
108}
109
110impl<'a, T: 'static> MappedBufferObject<'a, T> {
111    /// Get the stride of the buffer object
112    ///
113    /// This is calculated by the backend when it does the allocation of the buffer.
114    pub fn stride(&self) -> u32 {
115        self.stride
116    }
117
118    /// The height of the mapped region for the buffer
119    pub fn height(&self) -> u32 {
120        self.height
121    }
122
123    /// The width of the mapped region for the buffer
124    pub fn width(&self) -> u32 {
125        self.width
126    }
127
128    /// The X (top left origin) starting position of the mapped region for the buffer
129    pub fn x(&self) -> u32 {
130        self.x
131    }
132
133    /// The Y (top left origin) starting position of the mapped region for the buffer
134    pub fn y(&self) -> u32 {
135        self.y
136    }
137
138    /// Access to the underlying image buffer
139    pub fn buffer(&self) -> &[u8] {
140        self.buffer
141    }
142
143    /// Mutable access to the underlying image buffer
144    pub fn buffer_mut(&mut self) -> &mut [u8] {
145        self.buffer
146    }
147}
148
149impl<'a, T: 'static> Deref for MappedBufferObject<'a, T> {
150    type Target = BufferObject<T>;
151    fn deref(&self) -> &BufferObject<T> {
152        match &self.bo {
153            BORef::Ref(bo) => bo,
154            BORef::Mut(bo) => bo,
155        }
156    }
157}
158
159impl<'a, T: 'static> DerefMut for MappedBufferObject<'a, T> {
160    fn deref_mut(&mut self) -> &mut BufferObject<T> {
161        match &mut self.bo {
162            BORef::Ref(_) => unreachable!(),
163            BORef::Mut(bo) => bo,
164        }
165    }
166}
167
168impl<'a, T: 'static> Drop for MappedBufferObject<'a, T> {
169    fn drop(&mut self) {
170        let ffi = match &self.bo {
171            BORef::Ref(bo) => &bo.ffi,
172            BORef::Mut(bo) => &bo.ffi,
173        };
174        unsafe { ffi::gbm_bo_unmap(**ffi, self.data) }
175    }
176}
177
178unsafe extern "C" fn destroy<T: 'static>(_: *mut ffi::gbm_bo, ptr: *mut ::libc::c_void) {
179    let ptr = ptr as *mut T;
180    if !ptr.is_null() {
181        let _ = Box::from_raw(ptr);
182    }
183}
184
185impl<T: 'static> BufferObject<T> {
186    /// Get the width of the buffer object
187    pub fn width(&self) -> u32 {
188        unsafe { ffi::gbm_bo_get_width(*self.ffi) }
189    }
190
191    /// Get the height of the buffer object
192    pub fn height(&self) -> u32 {
193        unsafe { ffi::gbm_bo_get_height(*self.ffi) }
194    }
195
196    /// Get the stride of the buffer object
197    pub fn stride(&self) -> u32 {
198        unsafe { ffi::gbm_bo_get_stride(*self.ffi) }
199    }
200
201    /// Get the stride of the buffer object
202    pub fn stride_for_plane(&self, plane: i32) -> u32 {
203        unsafe { ffi::gbm_bo_get_stride_for_plane(*self.ffi, plane) }
204    }
205
206    /// Get the format of the buffer object
207    pub fn format(&self) -> Format {
208        Format::try_from(unsafe { ffi::gbm_bo_get_format(*self.ffi) })
209            .expect("libgbm returned invalid buffer format")
210    }
211
212    /// Get the bits per pixel of the buffer object
213    pub fn bpp(&self) -> u32 {
214        unsafe { ffi::gbm_bo_get_bpp(*self.ffi) }
215    }
216
217    /// Get the offset for a plane of the buffer object
218    pub fn offset(&self, plane: i32) -> u32 {
219        unsafe { ffi::gbm_bo_get_offset(*self.ffi, plane) }
220    }
221
222    /// Get the plane count of the buffer object
223    pub fn plane_count(&self) -> u32 {
224        unsafe { ffi::gbm_bo_get_plane_count(*self.ffi) as u32 }
225    }
226
227    /// Get the modifier of the buffer object
228    pub fn modifier(&self) -> Modifier {
229        Modifier::from(unsafe { ffi::gbm_bo_get_modifier(*self.ffi) })
230    }
231
232    /// Get a DMA-BUF file descriptor for the buffer object
233    ///
234    /// This function creates a DMA-BUF (also known as PRIME) file descriptor
235    /// handle for the buffer object.  Each call to [`Self::fd()`] returns a new
236    /// file descriptor and the caller is responsible for closing the file
237    /// descriptor.
238    pub fn fd(&self) -> Result<OwnedFd, InvalidFdError> {
239        unsafe {
240            let fd = ffi::gbm_bo_get_fd(*self.ffi);
241
242            if fd == -1 {
243                return Err(InvalidFdError);
244            }
245
246            Ok(OwnedFd::from_raw_fd(fd))
247        }
248    }
249
250    /// Get the file descriptor of the gbm device of this buffer object
251    pub fn device_fd(&self) -> BorrowedFd {
252        unsafe { BorrowedFd::borrow_raw(ffi::gbm_device_get_fd(*self._device)) }
253    }
254
255    /// Get the handle of the buffer object
256    ///
257    /// This is stored in the platform generic union [`BufferObjectHandle`] type.  However
258    /// the format of this handle is platform specific.
259    pub fn handle(&self) -> BufferObjectHandle {
260        unsafe { ffi::gbm_bo_get_handle(*self.ffi) }
261    }
262
263    /// Get a DMA-BUF file descriptor for a plane of the buffer object
264    ///
265    /// This function creates a DMA-BUF (also known as PRIME) file descriptor
266    /// handle for a plane of the buffer object. Each call to [`Self::fd_for_plane()`]
267    /// returns a new file descriptor and the caller is responsible for closing
268    /// the file descriptor.
269    pub fn fd_for_plane(&self, plane: i32) -> Result<OwnedFd, InvalidFdError> {
270        unsafe {
271            let fd = ffi::gbm_bo_get_fd_for_plane(*self.ffi, plane);
272
273            if fd == -1 {
274                return Err(InvalidFdError);
275            }
276
277            Ok(OwnedFd::from_raw_fd(fd))
278        }
279    }
280
281    /// Get the handle of a plane of the buffer object
282    ///
283    /// This is stored in the platform generic union [`BufferObjectHandle`] type.  However
284    /// the format of this handle is platform specific.
285    pub fn handle_for_plane(&self, plane: i32) -> BufferObjectHandle {
286        unsafe { ffi::gbm_bo_get_handle_for_plane(*self.ffi, plane) }
287    }
288
289    /// Map a region of a GBM buffer object for cpu access
290    ///
291    /// This function maps a region of a GBM bo for cpu read access.
292    pub fn map<'a, F, S>(&'a self, x: u32, y: u32, width: u32, height: u32, f: F) -> IoResult<S>
293    where
294        F: FnOnce(&MappedBufferObject<'a, T>) -> S,
295    {
296        unsafe {
297            let mut data: *mut ::libc::c_void = ptr::null_mut();
298            let mut stride = 0;
299            let ptr = ffi::gbm_bo_map(
300                *self.ffi,
301                x,
302                y,
303                width,
304                height,
305                ffi::gbm_bo_transfer_flags::GBM_BO_TRANSFER_READ as u32,
306                &mut stride as *mut _,
307                &mut data as *mut _,
308            );
309
310            if ptr.is_null() {
311                Err(IoError::last_os_error())
312            } else {
313                Ok(f(&MappedBufferObject {
314                    bo: BORef::Ref(self),
315                    buffer: slice::from_raw_parts_mut(ptr as *mut _, (height * stride) as usize),
316                    data,
317                    stride,
318                    height,
319                    width,
320                    x,
321                    y,
322                }))
323            }
324        }
325    }
326
327    /// Map a region of a GBM buffer object for cpu access
328    ///
329    /// This function maps a region of a GBM bo for cpu read/write access.
330    pub fn map_mut<'a, F, S>(
331        &'a mut self,
332        x: u32,
333        y: u32,
334        width: u32,
335        height: u32,
336        f: F,
337    ) -> IoResult<S>
338    where
339        F: FnOnce(&mut MappedBufferObject<'a, T>) -> S,
340    {
341        unsafe {
342            let mut data: *mut ::libc::c_void = ptr::null_mut();
343            let mut stride = 0;
344            let ptr = ffi::gbm_bo_map(
345                *self.ffi,
346                x,
347                y,
348                width,
349                height,
350                ffi::gbm_bo_transfer_flags::GBM_BO_TRANSFER_READ_WRITE as u32,
351                &mut stride as *mut _,
352                &mut data as *mut _,
353            );
354
355            if ptr.is_null() {
356                Err(IoError::last_os_error())
357            } else {
358                Ok(f(&mut MappedBufferObject {
359                    bo: BORef::Mut(self),
360                    buffer: slice::from_raw_parts_mut(ptr as *mut _, (height * stride) as usize),
361                    data,
362                    stride,
363                    height,
364                    width,
365                    x,
366                    y,
367                }))
368            }
369        }
370    }
371
372    ///  Write data into the buffer object
373    ///
374    /// If the buffer object was created with the [`BufferObjectFlags::WRITE`] flag,
375    /// this function can be used to write data into the buffer object.  The
376    /// data is copied directly into the object and it's the responsibility
377    /// of the caller to make sure the data represents valid pixel data,
378    /// according to the width, height, stride and format of the buffer object.
379    pub fn write(&mut self, buffer: &[u8]) -> IoResult<()> {
380        let result =
381            unsafe { ffi::gbm_bo_write(*self.ffi, buffer.as_ptr() as *const _, buffer.len() as _) };
382        if result != 0 {
383            Err(IoError::last_os_error())
384        } else {
385            Ok(())
386        }
387    }
388
389    /// Sets the userdata of the buffer object.
390    ///
391    /// If previously userdata was set, it is returned.
392    pub fn set_userdata(&mut self, userdata: T) -> Option<T> {
393        let old = self.take_userdata();
394
395        let boxed = Box::new(userdata);
396        unsafe {
397            ffi::gbm_bo_set_user_data(
398                *self.ffi,
399                Box::into_raw(boxed) as *mut _,
400                Some(destroy::<T>),
401            );
402        }
403
404        old
405    }
406
407    /// Clears the set userdata of the buffer object.
408    pub fn clear_userdata(&mut self) {
409        let _ = self.take_userdata();
410    }
411
412    /// Returns a reference to set userdata, if any.
413    pub fn userdata(&self) -> Option<&T> {
414        let raw = unsafe { ffi::gbm_bo_get_user_data(*self.ffi) };
415
416        if raw.is_null() {
417            None
418        } else {
419            unsafe { Some(&*(raw as *mut T)) }
420        }
421    }
422
423    /// Returns a mutable reference to set userdata, if any.
424    pub fn userdata_mut(&mut self) -> Option<&mut T> {
425        let raw = unsafe { ffi::gbm_bo_get_user_data(*self.ffi) };
426
427        if raw.is_null() {
428            None
429        } else {
430            unsafe { Some(&mut *(raw as *mut T)) }
431        }
432    }
433
434    /// Takes ownership of previously set userdata, if any.
435    ///
436    /// This removes the userdata from the buffer object.
437    pub fn take_userdata(&mut self) -> Option<T> {
438        let raw = unsafe { ffi::gbm_bo_get_user_data(*self.ffi) };
439
440        if raw.is_null() {
441            None
442        } else {
443            unsafe {
444                let boxed = Box::from_raw(raw as *mut T);
445                ffi::gbm_bo_set_user_data(*self.ffi, ptr::null_mut(), None);
446                Some(*boxed)
447            }
448        }
449    }
450
451    pub(crate) unsafe fn new(
452        ffi: *mut ffi::gbm_bo,
453        device: Ptr<ffi::gbm_device>,
454    ) -> BufferObject<T> {
455        BufferObject {
456            ffi: Ptr::<ffi::gbm_bo>::new(ffi, |ptr| ffi::gbm_bo_destroy(ptr)),
457            _device: device,
458            _userdata: PhantomData,
459        }
460    }
461
462    fn offsets(&self) -> [u32; 4] {
463        let num = self.plane_count();
464        [
465            BufferObject::<T>::offset(self, 0),
466            if num > 1 {
467                BufferObject::<T>::offset(self, 1)
468            } else {
469                0
470            },
471            if num > 2 {
472                BufferObject::<T>::offset(self, 2)
473            } else {
474                0
475            },
476            if num > 3 {
477                BufferObject::<T>::offset(self, 3)
478            } else {
479                0
480            },
481        ]
482    }
483}
484
485impl<T: 'static> AsRaw<ffi::gbm_bo> for BufferObject<T> {
486    fn as_raw(&self) -> *const ffi::gbm_bo {
487        *self.ffi
488    }
489}
490
491#[cfg(feature = "drm-support")]
492impl<T: 'static> DrmBuffer for BufferObject<T> {
493    fn size(&self) -> (u32, u32) {
494        (self.width(), self.height())
495    }
496
497    fn format(&self) -> Format {
498        BufferObject::<T>::format(self)
499    }
500
501    fn pitch(&self) -> u32 {
502        self.stride()
503    }
504
505    fn handle(&self) -> Handle {
506        use std::num::NonZeroU32;
507        unsafe { Handle::from(NonZeroU32::new_unchecked(self.handle().u32_)) }
508    }
509}
510
511#[cfg(feature = "drm-support")]
512impl<T: 'static> DrmPlanarBuffer for BufferObject<T> {
513    fn size(&self) -> (u32, u32) {
514        (self.width(), self.height())
515    }
516    fn format(&self) -> Format {
517        BufferObject::<T>::format(self)
518    }
519    fn modifier(&self) -> Option<Modifier> {
520        Some(BufferObject::<T>::modifier(self))
521    }
522    fn pitches(&self) -> [u32; 4] {
523        let num = self.plane_count();
524        [
525            BufferObject::<T>::stride_for_plane(self, 0),
526            if num > 1 {
527                BufferObject::<T>::stride_for_plane(self, 1)
528            } else {
529                0
530            },
531            if num > 2 {
532                BufferObject::<T>::stride_for_plane(self, 2)
533            } else {
534                0
535            },
536            if num > 3 {
537                BufferObject::<T>::stride_for_plane(self, 3)
538            } else {
539                0
540            },
541        ]
542    }
543    fn handles(&self) -> [Option<Handle>; 4] {
544        use std::num::NonZeroU32;
545        let num = self.plane_count();
546        [
547            Some(unsafe {
548                Handle::from(NonZeroU32::new_unchecked(
549                    BufferObject::<T>::handle_for_plane(self, 0).u32_,
550                ))
551            }),
552            if num > 1 {
553                Some(unsafe {
554                    Handle::from(NonZeroU32::new_unchecked(
555                        BufferObject::<T>::handle_for_plane(self, 1).u32_,
556                    ))
557                })
558            } else {
559                None
560            },
561            if num > 2 {
562                Some(unsafe {
563                    Handle::from(NonZeroU32::new_unchecked(
564                        BufferObject::<T>::handle_for_plane(self, 2).u32_,
565                    ))
566                })
567            } else {
568                None
569            },
570            if num > 3 {
571                Some(unsafe {
572                    Handle::from(NonZeroU32::new_unchecked(
573                        BufferObject::<T>::handle_for_plane(self, 3).u32_,
574                    ))
575                })
576            } else {
577                None
578            },
579        ]
580    }
581    fn offsets(&self) -> [u32; 4] {
582        self.offsets()
583    }
584}
585
586/// Thrown when the fd is invalid
587#[derive(Debug, Clone, Copy, PartialEq, Eq)]
588pub struct InvalidFdError;
589
590impl fmt::Display for InvalidFdError {
591    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
592        write!(f, "The returned fd is invalid")
593    }
594}
595
596impl error::Error for InvalidFdError {}