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
17pub struct BufferObject<T: 'static> {
19 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 #[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 const SCANOUT = ffi::gbm_bo_flags::GBM_BO_USE_SCANOUT as u32;
52 const CURSOR = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR as u32;
54 #[deprecated = "Use CURSOR instead"]
56 const CURSOR_64X64 = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR_64X64 as u32;
57 const RENDERING = ffi::gbm_bo_flags::GBM_BO_USE_RENDERING as u32;
60 const WRITE = ffi::gbm_bo_flags::GBM_BO_USE_WRITE as u32;
63 const LINEAR = ffi::gbm_bo_flags::GBM_BO_USE_LINEAR as u32;
65 const PROTECTED = ffi::gbm_bo_flags::GBM_BO_USE_PROTECTED as u32;
67 }
68}
69
70pub 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
78pub 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 pub fn stride(&self) -> u32 {
117 self.stride
118 }
119
120 pub fn height(&self) -> u32 {
122 self.height
123 }
124
125 pub fn width(&self) -> u32 {
127 self.width
128 }
129
130 pub fn x(&self) -> u32 {
133 self.x
134 }
135
136 pub fn y(&self) -> u32 {
139 self.y
140 }
141
142 pub fn buffer(&self) -> &[u8] {
144 self.buffer
145 }
146
147 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 pub fn width(&self) -> u32 {
193 unsafe { self.gbm.gbm_bo_get_width(*self.ffi) }
194 }
195
196 pub fn height(&self) -> u32 {
198 unsafe { self.gbm.gbm_bo_get_height(*self.ffi) }
199 }
200
201 pub fn stride(&self) -> u32 {
203 unsafe { self.gbm.gbm_bo_get_stride(*self.ffi) }
204 }
205
206 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 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 pub fn bpp(&self) -> u32 {
219 unsafe { self.gbm.gbm_bo_get_bpp(*self.ffi) }
220 }
221
222 pub fn offset(&self, plane: i32) -> u32 {
224 unsafe { self.gbm.gbm_bo_get_offset(*self.ffi, plane) }
225 }
226
227 pub fn plane_count(&self) -> u32 {
229 unsafe { self.gbm.gbm_bo_get_plane_count(*self.ffi) as u32 }
230 }
231
232 pub fn modifier(&self) -> Modifier {
234 Modifier::from(unsafe { self.gbm.gbm_bo_get_modifier(*self.ffi) })
235 }
236
237 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 pub fn device_fd(&'_ self) -> BorrowedFd<'_> {
257 unsafe { BorrowedFd::borrow_raw(self.gbm.gbm_device_get_fd(*self._device)) }
258 }
259
260 pub fn handle(&self) -> BufferObjectHandle {
265 unsafe { self.gbm.gbm_bo_get_handle(*self.ffi) }
266 }
267
268 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 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 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 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 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 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 pub fn clear_userdata(&mut self) {
417 let _ = self.take_userdata();
418 }
419
420 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 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 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#[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 {}