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
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}
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 #[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 const SCANOUT = ffi::gbm_bo_flags::GBM_BO_USE_SCANOUT as u32;
51 const CURSOR = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR as u32;
53 #[deprecated = "Use CURSOR instead"]
55 const CURSOR_64X64 = ffi::gbm_bo_flags::GBM_BO_USE_CURSOR_64X64 as u32;
56 const RENDERING = ffi::gbm_bo_flags::GBM_BO_USE_RENDERING as u32;
59 const WRITE = ffi::gbm_bo_flags::GBM_BO_USE_WRITE as u32;
62 const LINEAR = ffi::gbm_bo_flags::GBM_BO_USE_LINEAR as u32;
64 const PROTECTED = ffi::gbm_bo_flags::GBM_BO_USE_PROTECTED as u32;
66 }
67}
68
69pub 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
77pub 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 pub fn stride(&self) -> u32 {
115 self.stride
116 }
117
118 pub fn height(&self) -> u32 {
120 self.height
121 }
122
123 pub fn width(&self) -> u32 {
125 self.width
126 }
127
128 pub fn x(&self) -> u32 {
130 self.x
131 }
132
133 pub fn y(&self) -> u32 {
135 self.y
136 }
137
138 pub fn buffer(&self) -> &[u8] {
140 self.buffer
141 }
142
143 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 pub fn width(&self) -> u32 {
188 unsafe { ffi::gbm_bo_get_width(*self.ffi) }
189 }
190
191 pub fn height(&self) -> u32 {
193 unsafe { ffi::gbm_bo_get_height(*self.ffi) }
194 }
195
196 pub fn stride(&self) -> u32 {
198 unsafe { ffi::gbm_bo_get_stride(*self.ffi) }
199 }
200
201 pub fn stride_for_plane(&self, plane: i32) -> u32 {
203 unsafe { ffi::gbm_bo_get_stride_for_plane(*self.ffi, plane) }
204 }
205
206 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 pub fn bpp(&self) -> u32 {
214 unsafe { ffi::gbm_bo_get_bpp(*self.ffi) }
215 }
216
217 pub fn offset(&self, plane: i32) -> u32 {
219 unsafe { ffi::gbm_bo_get_offset(*self.ffi, plane) }
220 }
221
222 pub fn plane_count(&self) -> u32 {
224 unsafe { ffi::gbm_bo_get_plane_count(*self.ffi) as u32 }
225 }
226
227 pub fn modifier(&self) -> Modifier {
229 Modifier::from(unsafe { ffi::gbm_bo_get_modifier(*self.ffi) })
230 }
231
232 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 pub fn device_fd(&self) -> BorrowedFd {
252 unsafe { BorrowedFd::borrow_raw(ffi::gbm_device_get_fd(*self._device)) }
253 }
254
255 pub fn handle(&self) -> BufferObjectHandle {
260 unsafe { ffi::gbm_bo_get_handle(*self.ffi) }
261 }
262
263 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 pub fn handle_for_plane(&self, plane: i32) -> BufferObjectHandle {
286 unsafe { ffi::gbm_bo_get_handle_for_plane(*self.ffi, plane) }
287 }
288
289 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 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 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 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 pub fn clear_userdata(&mut self) {
409 let _ = self.take_userdata();
410 }
411
412 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 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 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#[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 {}