use super::{Buffer, Format, Fourcc, Modifier};
use crate::utils::{Buffer as BufferCoords, Size};
use std::hash::{Hash, Hasher};
use std::os::unix::io::{IntoRawFd, RawFd};
use std::sync::{Arc, Weak};
pub const MAX_PLANES: usize = 4;
#[derive(Debug)]
pub(crate) struct DmabufInternal {
pub planes: Vec<Plane>,
pub size: Size<i32, BufferCoords>,
pub format: Fourcc,
pub flags: DmabufFlags,
}
#[derive(Debug)]
pub(crate) struct Plane {
pub fd: Option<RawFd>,
pub plane_idx: u32,
pub offset: u32,
pub stride: u32,
pub modifier: Modifier,
}
impl IntoRawFd for Plane {
fn into_raw_fd(mut self) -> RawFd {
self.fd.take().unwrap()
}
}
impl Drop for Plane {
fn drop(&mut self) {
if let Some(fd) = self.fd.take() {
let _ = nix::unistd::close(fd);
}
}
}
bitflags::bitflags! {
pub struct DmabufFlags: u32 {
const Y_INVERT = 1;
const INTERLACED = 2;
const BOTTOM_FIRST = 4;
}
}
#[derive(Debug, Clone)]
pub struct Dmabuf(pub(crate) Arc<DmabufInternal>);
#[derive(Debug, Clone)]
pub struct WeakDmabuf(pub(crate) Weak<DmabufInternal>);
impl PartialEq for Dmabuf {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl Eq for Dmabuf {}
impl PartialEq for WeakDmabuf {
fn eq(&self, other: &Self) -> bool {
Weak::ptr_eq(&self.0, &other.0)
}
}
impl Eq for WeakDmabuf {}
impl Hash for Dmabuf {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.0).hash(state)
}
}
impl Hash for WeakDmabuf {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_ptr().hash(state)
}
}
impl Buffer for Dmabuf {
fn size(&self) -> Size<i32, BufferCoords> {
self.0.size
}
fn format(&self) -> Format {
Format {
code: self.0.format,
modifier: self.0.planes[0].modifier,
}
}
}
#[derive(Debug)]
pub struct DmabufBuilder {
internal: DmabufInternal,
}
impl DmabufBuilder {
pub fn add_plane(&mut self, fd: RawFd, idx: u32, offset: u32, stride: u32, modifier: Modifier) -> bool {
if self.internal.planes.len() == MAX_PLANES {
return false;
}
self.internal.planes.push(Plane {
fd: Some(fd),
plane_idx: idx,
offset,
stride,
modifier,
});
true
}
pub fn build(mut self) -> Option<Dmabuf> {
if self.internal.planes.is_empty() {
return None;
}
self.internal.planes.sort_by_key(|plane| plane.plane_idx);
Some(Dmabuf(Arc::new(self.internal)))
}
}
impl Dmabuf {
pub fn builder_from_buffer(src: &impl Buffer, flags: DmabufFlags) -> DmabufBuilder {
DmabufBuilder {
internal: DmabufInternal {
planes: Vec::with_capacity(MAX_PLANES),
size: src.size(),
format: src.format().code,
flags,
},
}
}
pub fn builder(
size: impl Into<Size<i32, BufferCoords>>,
format: Fourcc,
flags: DmabufFlags,
) -> DmabufBuilder {
DmabufBuilder {
internal: DmabufInternal {
planes: Vec::with_capacity(MAX_PLANES),
size: size.into(),
format,
flags,
},
}
}
pub fn num_planes(&self) -> usize {
self.0.planes.len()
}
pub fn handles(&self) -> impl Iterator<Item = RawFd> + '_ {
self.0.planes.iter().map(|p| *p.fd.as_ref().unwrap())
}
pub fn offsets(&self) -> impl Iterator<Item = u32> + '_ {
self.0.planes.iter().map(|p| p.offset)
}
pub fn strides(&self) -> impl Iterator<Item = u32> + '_ {
self.0.planes.iter().map(|p| p.stride)
}
pub fn has_modifier(&self) -> bool {
self.0.planes[0].modifier != Modifier::Invalid && self.0.planes[0].modifier != Modifier::Linear
}
pub fn y_inverted(&self) -> bool {
self.0.flags.contains(DmabufFlags::Y_INVERT)
}
pub fn weak(&self) -> WeakDmabuf {
WeakDmabuf(Arc::downgrade(&self.0))
}
}
impl WeakDmabuf {
pub fn upgrade(&self) -> Option<Dmabuf> {
self.0.upgrade().map(Dmabuf)
}
}
pub trait AsDmabuf {
type Error;
fn export(&self) -> Result<Dmabuf, Self::Error>;
}
impl AsDmabuf for Dmabuf {
type Error = std::convert::Infallible;
fn export(&self) -> Result<Dmabuf, std::convert::Infallible> {
Ok(self.clone())
}
}