use std::os::fd::OwnedFd;
use cros_libva::{DrmPrimeSurfaceDescriptor, Surface, SurfaceMemoryDescriptor};
use mediaway_common::{DmaBufDescriptor, DmaBufPlane, GpuBufferHandle, NativeHandle};
use crate::DecodeError;
pub(crate) struct DmaBufFds {
#[allow(
dead_code,
reason = "RAII-only in production code; read by dmabuf_tests.rs"
)]
pub(crate) fd0: OwnedFd,
#[allow(
dead_code,
reason = "RAII-only in production code; read by dmabuf_tests.rs"
)]
pub(crate) fd1: Option<OwnedFd>,
}
pub(crate) fn build_handle<D: SurfaceMemoryDescriptor>(
surface: &Surface<D>,
) -> Result<(GpuBufferHandle, DmaBufFds), DecodeError> {
let desc = surface.export_prime().map_err(|_| DecodeError::Backend)?;
build_from_prime(desc)
}
fn build_from_prime(
mut desc: DrmPrimeSurfaceDescriptor,
) -> Result<(GpuBufferHandle, DmaBufFds), DecodeError> {
if desc.objects.is_empty() || desc.objects.len() > 2 {
return Err(DecodeError::Backend);
}
if desc.layers.len() != 1 {
return Err(DecodeError::Backend);
}
let layer = &desc.layers[0];
let plane_count = u8::try_from(layer.num_planes).map_err(|_| DecodeError::Backend)?;
if plane_count == 0 || plane_count > 2 {
return Err(DecodeError::Backend);
}
let mut planes = [DmaBufPlane {
object_index: 0,
offset: 0,
pitch: 0,
}; 2];
for (plane, i) in planes.iter_mut().zip(0..usize::from(plane_count)) {
*plane = DmaBufPlane {
object_index: layer.object_index[i],
offset: layer.offset[i],
pitch: layer.pitch[i],
};
}
let object0 = desc.objects.remove(0);
let modifier = object0.drm_format_modifier;
let fd0 = native_handle_from_fd(&object0.fd)?;
let (fd1, owned1) = if desc.objects.is_empty() {
(None, None)
} else {
let object1 = desc.objects.remove(0);
let handle = native_handle_from_fd(&object1.fd)?;
(Some(handle), Some(object1.fd))
};
let descriptor = DmaBufDescriptor {
fd0,
fd1,
fourcc: desc.fourcc,
modifier,
width: desc.width,
height: desc.height,
planes,
plane_count,
};
Ok((
GpuBufferHandle::DmaBuf(Box::new(descriptor)),
DmaBufFds {
fd0: object0.fd,
fd1: owned1,
},
))
}
fn native_handle_from_fd(fd: &OwnedFd) -> Result<NativeHandle, DecodeError> {
use std::os::fd::AsRawFd;
let raw = fd.as_raw_fd();
let bits = usize::try_from(raw)
.ok()
.and_then(|b| b.checked_add(1))
.ok_or(DecodeError::Backend)?;
NativeHandle::new(bits).ok_or(DecodeError::Backend)
}
#[cfg(test)]
#[path = "dmabuf_tests.rs"]
mod tests;