2021-05-24 17:15:46 +00:00
|
|
|
//! Module for Buffers created using [libgbm](gbm).
|
2021-05-23 13:13:04 +00:00
|
|
|
//!
|
2021-05-24 17:15:46 +00:00
|
|
|
//! The re-exported [`GbmDevice`](gbm::Device) implements the [`Allocator`](super::Allocator) trait
|
|
|
|
//! and [`GbmBuffer`](gbm::BufferObject) satisfies the [`Buffer`](super::Buffer) trait while also allowing
|
2021-05-23 13:13:04 +00:00
|
|
|
//! conversions to and from [dmabufs](super::dmabuf).
|
2021-04-30 15:21:35 +00:00
|
|
|
|
2021-05-15 16:17:43 +00:00
|
|
|
use super::{
|
|
|
|
dmabuf::{AsDmabuf, Dmabuf},
|
|
|
|
Allocator, Buffer, Format, Fourcc, Modifier,
|
|
|
|
};
|
2021-05-23 13:13:04 +00:00
|
|
|
pub use gbm::{BufferObject as GbmBuffer, BufferObjectFlags as GbmBufferFlags, Device as GbmDevice};
|
2021-04-06 22:54:46 +00:00
|
|
|
use std::os::unix::io::AsRawFd;
|
|
|
|
|
|
|
|
impl<A: AsRawFd + 'static, T> Allocator<GbmBuffer<T>> for GbmDevice<A> {
|
|
|
|
type Error = std::io::Error;
|
|
|
|
|
|
|
|
fn create_buffer(&mut self, width: u32, height: u32, format: Format) -> std::io::Result<GbmBuffer<T>> {
|
|
|
|
if format.modifier == Modifier::Invalid || format.modifier == Modifier::Linear {
|
2021-05-23 13:13:04 +00:00
|
|
|
let mut usage = GbmBufferFlags::SCANOUT | GbmBufferFlags::RENDERING;
|
2021-04-06 22:54:46 +00:00
|
|
|
if format.modifier == Modifier::Linear {
|
2021-05-23 13:13:04 +00:00
|
|
|
usage |= GbmBufferFlags::LINEAR;
|
2021-04-06 22:54:46 +00:00
|
|
|
}
|
|
|
|
self.create_buffer_object(width, height, format.code, usage)
|
|
|
|
} else {
|
2021-04-28 22:32:47 +00:00
|
|
|
self.create_buffer_object_with_modifiers(
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
format.code,
|
|
|
|
Some(format.modifier).into_iter(),
|
|
|
|
)
|
2021-04-06 22:54:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Buffer for GbmBuffer<T> {
|
|
|
|
fn width(&self) -> u32 {
|
|
|
|
self.width().unwrap_or(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn height(&self) -> u32 {
|
|
|
|
self.height().unwrap_or(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn format(&self) -> Format {
|
|
|
|
Format {
|
|
|
|
code: self.format().unwrap_or(Fourcc::Argb8888), // we got to return something, but this should never happen anyway
|
|
|
|
modifier: self.modifier().unwrap_or(Modifier::Invalid),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-30 15:21:35 +00:00
|
|
|
/// Errors during conversion to a dmabuf handle from a gbm buffer object
|
2021-04-06 22:54:46 +00:00
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
|
|
pub enum GbmConvertError {
|
2021-04-30 15:21:35 +00:00
|
|
|
/// The gbm device was destroyed
|
2021-04-06 22:54:46 +00:00
|
|
|
#[error("The gbm device was destroyed")]
|
|
|
|
DeviceDestroyed(#[from] gbm::DeviceDestroyedError),
|
2021-04-30 15:21:35 +00:00
|
|
|
/// The buffer consists out of multiple file descriptions, which is currently unsupported
|
2021-04-06 22:54:46 +00:00
|
|
|
#[error("Buffer consists out of multiple file descriptors, which is currently unsupported")]
|
|
|
|
UnsupportedBuffer,
|
2021-04-30 15:21:35 +00:00
|
|
|
/// The conversion returned an invalid file descriptor
|
2021-04-06 22:54:46 +00:00
|
|
|
#[error("Buffer returned invalid file descriptor")]
|
|
|
|
InvalidFD,
|
|
|
|
}
|
|
|
|
|
2021-05-13 12:38:00 +00:00
|
|
|
impl<T> AsDmabuf for GbmBuffer<T> {
|
2021-04-06 22:54:46 +00:00
|
|
|
type Error = GbmConvertError;
|
|
|
|
|
2021-05-13 12:38:00 +00:00
|
|
|
fn export(&self) -> Result<Dmabuf, GbmConvertError> {
|
|
|
|
let planes = self.plane_count()? as i32;
|
2021-04-06 22:54:46 +00:00
|
|
|
|
|
|
|
//TODO switch to gbm_bo_get_plane_fd when it lands
|
2021-05-13 12:38:00 +00:00
|
|
|
let mut iter = (0i32..planes).map(|i| self.handle_for_plane(i));
|
2021-04-06 22:54:46 +00:00
|
|
|
let first = iter.next().expect("Encountered a buffer with zero planes");
|
2021-04-28 22:31:49 +00:00
|
|
|
// check that all handles are the same
|
|
|
|
let handle = iter.try_fold(first, |first, next| {
|
2021-04-06 22:54:46 +00:00
|
|
|
if let (Ok(next), Ok(first)) = (next, first) {
|
|
|
|
if unsafe { next.u64_ == first.u64_ } {
|
|
|
|
return Some(Ok(first));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
2021-04-28 22:31:49 +00:00
|
|
|
});
|
|
|
|
if handle.is_none() {
|
2021-04-06 22:54:46 +00:00
|
|
|
// GBM is lacking a function to get a FD for a given plane. Instead,
|
|
|
|
// check all planes have the same handle. We can't use
|
|
|
|
// drmPrimeHandleToFD because that messes up handle ref'counting in
|
|
|
|
// the user-space driver.
|
|
|
|
return Err(GbmConvertError::UnsupportedBuffer); //TODO
|
|
|
|
}
|
|
|
|
|
2021-05-13 12:38:00 +00:00
|
|
|
let fds = [self.fd()?, 0, 0, 0];
|
2021-04-06 22:54:46 +00:00
|
|
|
//if fds.iter().any(|fd| fd == 0) {
|
|
|
|
if fds[0] < 0 {
|
|
|
|
return Err(GbmConvertError::InvalidFD);
|
|
|
|
}
|
|
|
|
|
2021-04-28 22:32:47 +00:00
|
|
|
let offsets = (0i32..planes)
|
2021-05-13 12:38:00 +00:00
|
|
|
.map(|i| self.offset(i))
|
2021-04-28 22:32:47 +00:00
|
|
|
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
|
|
|
let strides = (0i32..planes)
|
2021-05-13 12:38:00 +00:00
|
|
|
.map(|i| self.stride_for_plane(i))
|
2021-04-28 22:32:47 +00:00
|
|
|
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
2021-04-06 22:54:46 +00:00
|
|
|
|
2021-05-13 12:38:00 +00:00
|
|
|
Ok(Dmabuf::new(self, planes as usize, &offsets, &strides, &fds).unwrap())
|
2021-04-06 22:54:46 +00:00
|
|
|
}
|
2021-04-11 21:00:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Dmabuf {
|
2021-04-30 15:21:35 +00:00
|
|
|
/// Import a Dmabuf using libgbm, creating a gbm Buffer Object to the same underlying data.
|
2021-05-23 13:13:04 +00:00
|
|
|
pub fn import_to<A: AsRawFd + 'static, T>(
|
2021-04-28 22:32:47 +00:00
|
|
|
&self,
|
|
|
|
gbm: &GbmDevice<A>,
|
2021-05-23 13:13:04 +00:00
|
|
|
usage: GbmBufferFlags,
|
2021-04-28 22:32:47 +00:00
|
|
|
) -> std::io::Result<GbmBuffer<T>> {
|
2021-04-11 21:00:22 +00:00
|
|
|
let buf = &*self.0;
|
|
|
|
if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 {
|
|
|
|
gbm.import_buffer_object_from_dma_buf_with_modifiers(
|
|
|
|
buf.num_planes as u32,
|
|
|
|
buf.fds,
|
|
|
|
buf.width,
|
|
|
|
buf.height,
|
|
|
|
buf.format.code,
|
|
|
|
usage,
|
|
|
|
unsafe { std::mem::transmute::<[u32; 4], [i32; 4]>(buf.strides) },
|
|
|
|
unsafe { std::mem::transmute::<[u32; 4], [i32; 4]>(buf.offsets) },
|
|
|
|
buf.format.modifier,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
gbm.import_buffer_object_from_dma_buf(
|
|
|
|
buf.fds[0],
|
|
|
|
buf.width,
|
|
|
|
buf.height,
|
|
|
|
buf.strides[0],
|
|
|
|
buf.format.code,
|
2021-04-28 22:32:47 +00:00
|
|
|
if buf.format.modifier == Modifier::Linear {
|
2021-05-23 13:13:04 +00:00
|
|
|
usage | GbmBufferFlags::LINEAR
|
2021-04-28 22:32:47 +00:00
|
|
|
} else {
|
|
|
|
usage
|
|
|
|
},
|
2021-04-11 21:00:22 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2021-04-28 22:32:47 +00:00
|
|
|
}
|