Skip to main content

edgefirst_gbm/
buffer_object.rs

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