udmabuf: move allocator implementation into workspace crate
This commit is contained in:
parent
81a718aa74
commit
1558666601
5 changed files with 356 additions and 324 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
|
@ -750,6 +750,7 @@ dependencies = [
|
|||
"jay-toml-config",
|
||||
"jay-tracy",
|
||||
"jay-tree-types",
|
||||
"jay-udmabuf",
|
||||
"jay-units",
|
||||
"jay-utils",
|
||||
"jay-video-types",
|
||||
|
|
@ -1054,6 +1055,19 @@ dependencies = [
|
|||
"linearize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-udmabuf"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"jay-allocator",
|
||||
"jay-formats",
|
||||
"jay-utils",
|
||||
"jay-video-types",
|
||||
"log",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-units"
|
||||
version = "0.1.0"
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ members = [
|
|||
"allocator",
|
||||
"output-schedule",
|
||||
"drm-feedback",
|
||||
"udmabuf",
|
||||
"pango",
|
||||
"libinput",
|
||||
"toml-config",
|
||||
|
|
@ -101,6 +102,7 @@ jay-clientmem = { version = "0.1.0", path = "clientmem" }
|
|||
jay-allocator = { version = "0.1.0", path = "allocator" }
|
||||
jay-output-schedule = { version = "0.1.0", path = "output-schedule" }
|
||||
jay-drm-feedback = { version = "0.1.0", path = "drm-feedback" }
|
||||
jay-udmabuf = { version = "0.1.0", path = "udmabuf" }
|
||||
jay-pango = { version = "0.1.0", path = "pango" }
|
||||
jay-libinput = { version = "0.1.0", path = "libinput" }
|
||||
|
||||
|
|
|
|||
325
src/udmabuf.rs
325
src/udmabuf.rs
|
|
@ -1,324 +1 @@
|
|||
use {
|
||||
crate::{
|
||||
allocator::{Allocator, AllocatorError, BufferObject, BufferUsage, MappedBuffer},
|
||||
format::Format,
|
||||
utils::{
|
||||
clonecell::CloneCell,
|
||||
compat::IoctlNumber,
|
||||
errorfmt::ErrorFmt,
|
||||
once::Once,
|
||||
oserror::{OsError, OsErrorExt, OsErrorExt2},
|
||||
page_size::page_size,
|
||||
},
|
||||
video::{
|
||||
LINEAR_MODIFIER, LINEAR_STRIDE_ALIGN, Modifier,
|
||||
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
|
||||
},
|
||||
},
|
||||
std::{ptr, rc::Rc},
|
||||
thiserror::Error,
|
||||
uapi::{
|
||||
_IOW, OwnedFd,
|
||||
c::{
|
||||
self, F_SEAL_SHRINK, MAP_SHARED, MFD_ALLOW_SEALING, O_RDONLY, PROT_READ, PROT_WRITE,
|
||||
ioctl, mmap, munmap,
|
||||
},
|
||||
map_err, open,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum UdmabufError {
|
||||
#[error("Could not open /dev/udmabuf")]
|
||||
Open(#[source] OsError),
|
||||
#[error("Only the linear modifier can be allocated")]
|
||||
Modifier,
|
||||
#[error("Could not create a memfd")]
|
||||
Memfd(#[source] OsError),
|
||||
#[error("Size calculation overflowed")]
|
||||
Overflow,
|
||||
#[error("Could not resize the memfd")]
|
||||
Truncate(#[source] OsError),
|
||||
#[error("Could not seal the memfd")]
|
||||
Seal(#[source] OsError),
|
||||
#[error("Could not create a dmabuf")]
|
||||
CreateDmabuf(#[source] OsError),
|
||||
#[error("Only a single plane is supported")]
|
||||
Planes,
|
||||
#[error("Stride is invalid")]
|
||||
Stride,
|
||||
#[error("Could not stat the dmabuf")]
|
||||
Stat(#[source] OsError),
|
||||
#[error("Dmabuf is too small for required size")]
|
||||
Size,
|
||||
#[error("Could not map dmabuf")]
|
||||
Map(#[source] OsError),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UdmabufHolder {
|
||||
logged: Once,
|
||||
udmabuf: CloneCell<Option<Option<Rc<Udmabuf>>>>,
|
||||
}
|
||||
|
||||
impl UdmabufHolder {
|
||||
pub fn get(&self) -> Option<Rc<Udmabuf>> {
|
||||
if let Some(u) = self.udmabuf.get() {
|
||||
return u;
|
||||
}
|
||||
match Udmabuf::new() {
|
||||
Ok(u) => {
|
||||
log::info!("Opened /dev/udmabuf");
|
||||
let u = Rc::new(u);
|
||||
self.udmabuf.set(Some(Some(u.clone())));
|
||||
Some(u)
|
||||
}
|
||||
Err(e) => {
|
||||
self.logged.exec(|| {
|
||||
log::warn!("Unable to open /dev/udmabuf: {}", ErrorFmt(&e));
|
||||
});
|
||||
if not_matches!(e, UdmabufError::Open(OsError(c::EPERM))) {
|
||||
self.udmabuf.set(Some(None));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Udmabuf {
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl Udmabuf {
|
||||
pub fn new() -> Result<Self, UdmabufError> {
|
||||
let fd = open("/dev/udmabuf", O_RDONLY, 0).map_os_err(UdmabufError::Open)?;
|
||||
Ok(Self { fd })
|
||||
}
|
||||
|
||||
pub fn create_dmabuf_from_memfd(
|
||||
&self,
|
||||
memfd: &OwnedFd,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> Result<OwnedFd, UdmabufError> {
|
||||
let mut cmd = udmabuf_create {
|
||||
memfd: memfd.raw() as u32,
|
||||
flags: UDMABUF_FLAGS_CLOEXEC,
|
||||
offset: offset as u64,
|
||||
size: size as u64,
|
||||
};
|
||||
let dmabuf = unsafe { ioctl(self.fd.raw(), UDMABUF_CREATE, &mut cmd) };
|
||||
let dmabuf = map_err!(dmabuf)
|
||||
.map(OwnedFd::new)
|
||||
.map_os_err(UdmabufError::CreateDmabuf)?;
|
||||
Ok(dmabuf)
|
||||
}
|
||||
|
||||
pub fn create_dmabuf(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
) -> Result<DmaBuf, UdmabufError> {
|
||||
Ok(self.create_bo(dma_buf_ids, width, height, format)?.buf)
|
||||
}
|
||||
|
||||
fn create_bo(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
) -> Result<UdmabufBo, UdmabufError> {
|
||||
let height = height as u64;
|
||||
let width = width as u64;
|
||||
if height > 1 << 16 || width > 1 << 16 {
|
||||
return Err(UdmabufError::Overflow);
|
||||
}
|
||||
let stride = (width * format.bpp as u64).next_multiple_of(LINEAR_STRIDE_ALIGN);
|
||||
let size_mask = page_size() as u64 - 1;
|
||||
let size = (height * stride + size_mask) & !size_mask;
|
||||
let memfd =
|
||||
uapi::memfd_create("udmabuf", MFD_ALLOW_SEALING).map_os_err(UdmabufError::Memfd)?;
|
||||
uapi::ftruncate(memfd.raw(), size as _).map_os_err(UdmabufError::Truncate)?;
|
||||
uapi::fcntl_add_seals(memfd.raw(), F_SEAL_SHRINK).map_os_err(UdmabufError::Seal)?;
|
||||
let dmabuf = self.create_dmabuf_from_memfd(&memfd, 0, size as _)?;
|
||||
let mut planes = PlaneVec::new();
|
||||
planes.push(DmaBufPlane {
|
||||
offset: 0,
|
||||
stride: stride as _,
|
||||
fd: Rc::new(dmabuf),
|
||||
});
|
||||
let dmabuf = DmaBuf {
|
||||
id: dma_buf_ids.next(),
|
||||
width: width as _,
|
||||
height: height as _,
|
||||
format,
|
||||
modifier: LINEAR_MODIFIER,
|
||||
planes,
|
||||
is_disjoint: Default::default(),
|
||||
};
|
||||
Ok(UdmabufBo {
|
||||
buf: dmabuf,
|
||||
size: size as _,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocator for Udmabuf {
|
||||
fn drm(&self) -> Option<&dyn crate::allocator::AllocatorDrm> {
|
||||
None
|
||||
}
|
||||
|
||||
fn create_bo(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
modifiers: &[Modifier],
|
||||
_usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError> {
|
||||
if !modifiers.contains(&LINEAR_MODIFIER) {
|
||||
return Err(UdmabufError::Modifier.into());
|
||||
}
|
||||
Ok(Rc::new(self.create_bo(
|
||||
dma_buf_ids,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
)?))
|
||||
}
|
||||
|
||||
fn import_dmabuf(
|
||||
&self,
|
||||
dmabuf: &DmaBuf,
|
||||
_usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError> {
|
||||
if dmabuf.planes.len() != 1 {
|
||||
return Err(UdmabufError::Planes.into());
|
||||
}
|
||||
if dmabuf.modifier != LINEAR_MODIFIER {
|
||||
return Err(UdmabufError::Modifier.into());
|
||||
}
|
||||
let plane = &dmabuf.planes[0];
|
||||
let height = dmabuf.height as u64;
|
||||
let width = dmabuf.width as u64;
|
||||
let stride = plane.stride as u64;
|
||||
let offset = plane.offset as u64;
|
||||
if height > 1 << 16 || width > 1 << 16 {
|
||||
return Err(UdmabufError::Overflow.into());
|
||||
}
|
||||
if stride < width * dmabuf.format.bpp as u64 {
|
||||
return Err(UdmabufError::Stride.into());
|
||||
}
|
||||
let size = offset + stride * height;
|
||||
if usize::try_from(size).is_err() {
|
||||
return Err(UdmabufError::Overflow.into());
|
||||
}
|
||||
let stat = uapi::fstat(plane.fd.raw()).map_os_err(UdmabufError::Stat)?;
|
||||
if (stat.st_size as u64) < size {
|
||||
return Err(UdmabufError::Size.into());
|
||||
}
|
||||
Ok(Rc::new(UdmabufBo {
|
||||
buf: dmabuf.clone(),
|
||||
size: size as usize,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
struct UdmabufBo {
|
||||
buf: DmaBuf,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl BufferObject for UdmabufBo {
|
||||
fn dmabuf(&self) -> &DmaBuf {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
fn map_read(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError> {
|
||||
self.map_write()
|
||||
}
|
||||
|
||||
fn map_write(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError> {
|
||||
let plane = &self.buf.planes[0];
|
||||
unsafe {
|
||||
let res = mmap(
|
||||
ptr::null_mut(),
|
||||
self.size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
plane.fd.raw(),
|
||||
0,
|
||||
);
|
||||
if res == c::MAP_FAILED {
|
||||
return Err(UdmabufError::Map(OsError::default()).into());
|
||||
}
|
||||
let offset = plane.offset as _;
|
||||
let data =
|
||||
std::slice::from_raw_parts_mut((res as *mut u8).add(offset), self.size - offset);
|
||||
Ok(Box::new(UdmabufMap {
|
||||
data,
|
||||
stride: plane.stride as _,
|
||||
ptr: res,
|
||||
len: self.size,
|
||||
_bo: self,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct UdmabufMap {
|
||||
_bo: Rc<UdmabufBo>,
|
||||
data: *mut [u8],
|
||||
stride: i32,
|
||||
ptr: *mut c::c_void,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Drop for UdmabufMap {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let res = munmap(self.ptr, self.len);
|
||||
if let Err(e) = map_err!(res).to_os_error() {
|
||||
log::error!("Could not unmap udmabuf: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MappedBuffer for UdmabufMap {
|
||||
unsafe fn data(&self) -> &[u8] {
|
||||
unsafe { &*self.data }
|
||||
}
|
||||
|
||||
fn data_ptr(&self) -> *mut u8 {
|
||||
self.data as _
|
||||
}
|
||||
|
||||
fn stride(&self) -> i32 {
|
||||
self.stride
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UdmabufError> for AllocatorError {
|
||||
fn from(value: UdmabufError) -> Self {
|
||||
Self(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct udmabuf_create {
|
||||
memfd: u32,
|
||||
flags: u32,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
const UDMABUF_FLAGS_CLOEXEC: u32 = 0x01;
|
||||
|
||||
const UDMABUF_CREATE: IoctlNumber = _IOW::<udmabuf_create>(b'u' as u64, 0x42) as IoctlNumber;
|
||||
pub use jay_udmabuf::*;
|
||||
|
|
|
|||
15
udmabuf/Cargo.toml
Normal file
15
udmabuf/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "jay-udmabuf"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
[dependencies]
|
||||
jay-allocator = { version = "0.1.0", path = "../allocator" }
|
||||
jay-formats = { version = "0.1.0", path = "../formats" }
|
||||
jay-utils = { version = "0.1.0", path = "../utils" }
|
||||
jay-video-types = { version = "0.1.0", path = "../video-types" }
|
||||
|
||||
log = "0.4.20"
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
324
udmabuf/src/lib.rs
Normal file
324
udmabuf/src/lib.rs
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
use {
|
||||
jay_allocator::{
|
||||
Allocator, AllocatorDrm, AllocatorError, BufferObject, BufferUsage, MappedBuffer,
|
||||
},
|
||||
jay_formats::Format,
|
||||
jay_utils::{
|
||||
clonecell::CloneCell,
|
||||
compat::IoctlNumber,
|
||||
errorfmt::ErrorFmt,
|
||||
once::Once,
|
||||
oserror::{OsError, OsErrorExt, OsErrorExt2},
|
||||
page_size::page_size,
|
||||
},
|
||||
jay_video_types::{
|
||||
LINEAR_MODIFIER, LINEAR_STRIDE_ALIGN, Modifier,
|
||||
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
|
||||
},
|
||||
std::{ptr, rc::Rc},
|
||||
thiserror::Error,
|
||||
uapi::{
|
||||
_IOW, OwnedFd,
|
||||
c::{
|
||||
self, F_SEAL_SHRINK, MAP_SHARED, MFD_ALLOW_SEALING, O_RDONLY, PROT_READ, PROT_WRITE,
|
||||
ioctl, mmap, munmap,
|
||||
},
|
||||
map_err, open,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum UdmabufError {
|
||||
#[error("Could not open /dev/udmabuf")]
|
||||
Open(#[source] OsError),
|
||||
#[error("Only the linear modifier can be allocated")]
|
||||
Modifier,
|
||||
#[error("Could not create a memfd")]
|
||||
Memfd(#[source] OsError),
|
||||
#[error("Size calculation overflowed")]
|
||||
Overflow,
|
||||
#[error("Could not resize the memfd")]
|
||||
Truncate(#[source] OsError),
|
||||
#[error("Could not seal the memfd")]
|
||||
Seal(#[source] OsError),
|
||||
#[error("Could not create a dmabuf")]
|
||||
CreateDmabuf(#[source] OsError),
|
||||
#[error("Only a single plane is supported")]
|
||||
Planes,
|
||||
#[error("Stride is invalid")]
|
||||
Stride,
|
||||
#[error("Could not stat the dmabuf")]
|
||||
Stat(#[source] OsError),
|
||||
#[error("Dmabuf is too small for required size")]
|
||||
Size,
|
||||
#[error("Could not map dmabuf")]
|
||||
Map(#[source] OsError),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UdmabufHolder {
|
||||
logged: Once,
|
||||
udmabuf: CloneCell<Option<Option<Rc<Udmabuf>>>>,
|
||||
}
|
||||
|
||||
impl UdmabufHolder {
|
||||
pub fn get(&self) -> Option<Rc<Udmabuf>> {
|
||||
if let Some(u) = self.udmabuf.get() {
|
||||
return u;
|
||||
}
|
||||
match Udmabuf::new() {
|
||||
Ok(u) => {
|
||||
log::info!("Opened /dev/udmabuf");
|
||||
let u = Rc::new(u);
|
||||
self.udmabuf.set(Some(Some(u.clone())));
|
||||
Some(u)
|
||||
}
|
||||
Err(e) => {
|
||||
self.logged.exec(|| {
|
||||
log::warn!("Unable to open /dev/udmabuf: {}", ErrorFmt(&e));
|
||||
});
|
||||
if !matches!(e, UdmabufError::Open(OsError(c::EPERM))) {
|
||||
self.udmabuf.set(Some(None));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Udmabuf {
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl Udmabuf {
|
||||
pub fn new() -> Result<Self, UdmabufError> {
|
||||
let fd = open("/dev/udmabuf", O_RDONLY, 0).map_os_err(UdmabufError::Open)?;
|
||||
Ok(Self { fd })
|
||||
}
|
||||
|
||||
pub fn create_dmabuf_from_memfd(
|
||||
&self,
|
||||
memfd: &OwnedFd,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> Result<OwnedFd, UdmabufError> {
|
||||
let mut cmd = udmabuf_create {
|
||||
memfd: memfd.raw() as u32,
|
||||
flags: UDMABUF_FLAGS_CLOEXEC,
|
||||
offset: offset as u64,
|
||||
size: size as u64,
|
||||
};
|
||||
let dmabuf = unsafe { ioctl(self.fd.raw(), UDMABUF_CREATE, &mut cmd) };
|
||||
let dmabuf = map_err!(dmabuf)
|
||||
.map(OwnedFd::new)
|
||||
.map_os_err(UdmabufError::CreateDmabuf)?;
|
||||
Ok(dmabuf)
|
||||
}
|
||||
|
||||
pub fn create_dmabuf(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
) -> Result<DmaBuf, UdmabufError> {
|
||||
Ok(self.create_bo(dma_buf_ids, width, height, format)?.buf)
|
||||
}
|
||||
|
||||
fn create_bo(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
) -> Result<UdmabufBo, UdmabufError> {
|
||||
let height = height as u64;
|
||||
let width = width as u64;
|
||||
if height > 1 << 16 || width > 1 << 16 {
|
||||
return Err(UdmabufError::Overflow);
|
||||
}
|
||||
let stride = (width * format.bpp as u64).next_multiple_of(LINEAR_STRIDE_ALIGN);
|
||||
let size_mask = page_size() as u64 - 1;
|
||||
let size = (height * stride + size_mask) & !size_mask;
|
||||
let memfd =
|
||||
uapi::memfd_create("udmabuf", MFD_ALLOW_SEALING).map_os_err(UdmabufError::Memfd)?;
|
||||
uapi::ftruncate(memfd.raw(), size as _).map_os_err(UdmabufError::Truncate)?;
|
||||
uapi::fcntl_add_seals(memfd.raw(), F_SEAL_SHRINK).map_os_err(UdmabufError::Seal)?;
|
||||
let dmabuf = self.create_dmabuf_from_memfd(&memfd, 0, size as _)?;
|
||||
let mut planes = PlaneVec::new();
|
||||
planes.push(DmaBufPlane {
|
||||
offset: 0,
|
||||
stride: stride as _,
|
||||
fd: Rc::new(dmabuf),
|
||||
});
|
||||
let dmabuf = DmaBuf {
|
||||
id: dma_buf_ids.next(),
|
||||
width: width as _,
|
||||
height: height as _,
|
||||
format,
|
||||
modifier: LINEAR_MODIFIER,
|
||||
planes,
|
||||
is_disjoint: Default::default(),
|
||||
};
|
||||
Ok(UdmabufBo {
|
||||
buf: dmabuf,
|
||||
size: size as _,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocator for Udmabuf {
|
||||
fn drm(&self) -> Option<&dyn AllocatorDrm> {
|
||||
None
|
||||
}
|
||||
|
||||
fn create_bo(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
modifiers: &[Modifier],
|
||||
_usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError> {
|
||||
if !modifiers.contains(&LINEAR_MODIFIER) {
|
||||
return Err(UdmabufError::Modifier.into());
|
||||
}
|
||||
Ok(Rc::new(self.create_bo(
|
||||
dma_buf_ids,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
)?))
|
||||
}
|
||||
|
||||
fn import_dmabuf(
|
||||
&self,
|
||||
dmabuf: &DmaBuf,
|
||||
_usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError> {
|
||||
if dmabuf.planes.len() != 1 {
|
||||
return Err(UdmabufError::Planes.into());
|
||||
}
|
||||
if dmabuf.modifier != LINEAR_MODIFIER {
|
||||
return Err(UdmabufError::Modifier.into());
|
||||
}
|
||||
let plane = &dmabuf.planes[0];
|
||||
let height = dmabuf.height as u64;
|
||||
let width = dmabuf.width as u64;
|
||||
let stride = plane.stride as u64;
|
||||
let offset = plane.offset as u64;
|
||||
if height > 1 << 16 || width > 1 << 16 {
|
||||
return Err(UdmabufError::Overflow.into());
|
||||
}
|
||||
if stride < width * dmabuf.format.bpp as u64 {
|
||||
return Err(UdmabufError::Stride.into());
|
||||
}
|
||||
let size = offset + stride * height;
|
||||
if usize::try_from(size).is_err() {
|
||||
return Err(UdmabufError::Overflow.into());
|
||||
}
|
||||
let stat = uapi::fstat(plane.fd.raw()).map_os_err(UdmabufError::Stat)?;
|
||||
if (stat.st_size as u64) < size {
|
||||
return Err(UdmabufError::Size.into());
|
||||
}
|
||||
Ok(Rc::new(UdmabufBo {
|
||||
buf: dmabuf.clone(),
|
||||
size: size as usize,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
struct UdmabufBo {
|
||||
buf: DmaBuf,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl BufferObject for UdmabufBo {
|
||||
fn dmabuf(&self) -> &DmaBuf {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
fn map_read(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError> {
|
||||
self.map_write()
|
||||
}
|
||||
|
||||
fn map_write(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError> {
|
||||
let plane = &self.buf.planes[0];
|
||||
unsafe {
|
||||
let res = mmap(
|
||||
ptr::null_mut(),
|
||||
self.size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
plane.fd.raw(),
|
||||
0,
|
||||
);
|
||||
if res == c::MAP_FAILED {
|
||||
return Err(UdmabufError::Map(OsError::default()).into());
|
||||
}
|
||||
let offset = plane.offset as _;
|
||||
let data =
|
||||
std::slice::from_raw_parts_mut((res as *mut u8).add(offset), self.size - offset);
|
||||
Ok(Box::new(UdmabufMap {
|
||||
data,
|
||||
stride: plane.stride as _,
|
||||
ptr: res,
|
||||
len: self.size,
|
||||
_bo: self,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct UdmabufMap {
|
||||
_bo: Rc<UdmabufBo>,
|
||||
data: *mut [u8],
|
||||
stride: i32,
|
||||
ptr: *mut c::c_void,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Drop for UdmabufMap {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let res = munmap(self.ptr, self.len);
|
||||
if let Err(e) = map_err!(res).to_os_error() {
|
||||
log::error!("Could not unmap udmabuf: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MappedBuffer for UdmabufMap {
|
||||
unsafe fn data(&self) -> &[u8] {
|
||||
unsafe { &*self.data }
|
||||
}
|
||||
|
||||
fn data_ptr(&self) -> *mut u8 {
|
||||
self.data as _
|
||||
}
|
||||
|
||||
fn stride(&self) -> i32 {
|
||||
self.stride
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UdmabufError> for AllocatorError {
|
||||
fn from(value: UdmabufError) -> Self {
|
||||
Self(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct udmabuf_create {
|
||||
memfd: u32,
|
||||
flags: u32,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
const UDMABUF_FLAGS_CLOEXEC: u32 = 0x01;
|
||||
|
||||
const UDMABUF_CREATE: IoctlNumber = _IOW::<udmabuf_create>(b'u' as u64, 0x42) as IoctlNumber;
|
||||
Loading…
Add table
Add a link
Reference in a new issue