linux-dmabuf: intercept udmabuf buffers
This commit is contained in:
parent
0570669af2
commit
410281b13e
5 changed files with 131 additions and 32 deletions
|
|
@ -54,8 +54,9 @@ impl ClientMem {
|
||||||
read_only: bool,
|
read_only: bool,
|
||||||
client: Option<&Client>,
|
client: Option<&Client>,
|
||||||
cpu: Option<&Rc<CpuWorker>>,
|
cpu: Option<&Rc<CpuWorker>>,
|
||||||
|
is_udmabuf: bool,
|
||||||
) -> Result<Self, ClientMemError> {
|
) -> Result<Self, ClientMemError> {
|
||||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_SHARED)
|
Self::new2(fd, len, read_only, client, cpu, c::MAP_SHARED, is_udmabuf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_private(
|
pub fn new_private(
|
||||||
|
|
@ -65,7 +66,7 @@ impl ClientMem {
|
||||||
client: Option<&Client>,
|
client: Option<&Client>,
|
||||||
cpu: Option<&Rc<CpuWorker>>,
|
cpu: Option<&Rc<CpuWorker>>,
|
||||||
) -> Result<Self, ClientMemError> {
|
) -> Result<Self, ClientMemError> {
|
||||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_PRIVATE)
|
Self::new2(fd, len, read_only, client, cpu, c::MAP_PRIVATE, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new2(
|
fn new2(
|
||||||
|
|
@ -75,10 +76,12 @@ impl ClientMem {
|
||||||
client: Option<&Client>,
|
client: Option<&Client>,
|
||||||
cpu: Option<&Rc<CpuWorker>>,
|
cpu: Option<&Rc<CpuWorker>>,
|
||||||
flags: c::c_int,
|
flags: c::c_int,
|
||||||
|
is_udmabuf: bool,
|
||||||
) -> Result<Self, ClientMemError> {
|
) -> Result<Self, ClientMemError> {
|
||||||
let mut sigbus_impossible = false;
|
let mut sigbus_impossible = is_udmabuf;
|
||||||
let mut real_size = None;
|
let mut real_size = None;
|
||||||
if let Ok(seals) = uapi::fcntl_get_seals(fd.raw())
|
if !sigbus_impossible
|
||||||
|
&& let Ok(seals) = uapi::fcntl_get_seals(fd.raw())
|
||||||
&& seals & c::F_SEAL_SHRINK != 0
|
&& seals & c::F_SEAL_SHRINK != 0
|
||||||
&& let Ok(stat) = uapi::fstat(fd.raw())
|
&& let Ok(stat) = uapi::fstat(fd.raw())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ impl WlBuffer {
|
||||||
stride: i32,
|
stride: i32,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
mem: &Rc<ClientMem>,
|
mem: &Rc<ClientMem>,
|
||||||
|
udmabuf: Option<(&Rc<OwnedFd>, usize)>,
|
||||||
) -> Result<Self, WlBufferError> {
|
) -> Result<Self, WlBufferError> {
|
||||||
let bytes = stride as u64 * height as u64;
|
let bytes = stride as u64 * height as u64;
|
||||||
let required = bytes + offset as u64;
|
let required = bytes + offset as u64;
|
||||||
|
|
@ -119,6 +120,26 @@ impl WlBuffer {
|
||||||
if (stride as u64) < min_row_size {
|
if (stride as u64) < min_row_size {
|
||||||
return Err(WlBufferError::StrideTooSmall);
|
return Err(WlBufferError::StrideTooSmall);
|
||||||
}
|
}
|
||||||
|
let dmabuf_buffer_params = match udmabuf {
|
||||||
|
None => DmabufBufferParams {
|
||||||
|
size: bytes as usize,
|
||||||
|
udmabuf: None,
|
||||||
|
udmabuf_offset: 0,
|
||||||
|
udmabuf_size: 0,
|
||||||
|
udmabuf_impossible: !mem.pool().is_sealed_memfd(),
|
||||||
|
host_buffer: None,
|
||||||
|
host_buffer_impossible: !mem.pool().is_sealed_memfd(),
|
||||||
|
},
|
||||||
|
Some((udmabuf, size)) => DmabufBufferParams {
|
||||||
|
size,
|
||||||
|
udmabuf: Some(udmabuf.clone()),
|
||||||
|
udmabuf_offset: offset,
|
||||||
|
udmabuf_size: size,
|
||||||
|
udmabuf_impossible: false,
|
||||||
|
host_buffer: None,
|
||||||
|
host_buffer_impossible: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id,
|
id,
|
||||||
destroyed: Cell::new(false),
|
destroyed: Cell::new(false),
|
||||||
|
|
@ -128,15 +149,7 @@ impl WlBuffer {
|
||||||
dmabuf: None,
|
dmabuf: None,
|
||||||
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
|
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
|
||||||
storage: RefCell::new(Some(WlBufferStorage::Shm {
|
storage: RefCell::new(Some(WlBufferStorage::Shm {
|
||||||
dmabuf_buffer_params: DmabufBufferParams {
|
dmabuf_buffer_params,
|
||||||
size: bytes as usize,
|
|
||||||
udmabuf: None,
|
|
||||||
udmabuf_offset: 0,
|
|
||||||
udmabuf_size: 0,
|
|
||||||
udmabuf_impossible: !mem.pool().is_sealed_memfd(),
|
|
||||||
host_buffer: None,
|
|
||||||
host_buffer_impossible: !mem.pool().is_sealed_memfd(),
|
|
||||||
},
|
|
||||||
mem,
|
mem,
|
||||||
stride,
|
stride,
|
||||||
})),
|
})),
|
||||||
|
|
@ -191,9 +204,9 @@ impl WlBuffer {
|
||||||
};
|
};
|
||||||
let had_texture = match s {
|
let had_texture = match s {
|
||||||
WlBufferStorage::Shm {
|
WlBufferStorage::Shm {
|
||||||
mem,
|
|
||||||
dmabuf_buffer_params:
|
dmabuf_buffer_params:
|
||||||
DmabufBufferParams {
|
DmabufBufferParams {
|
||||||
|
udmabuf_impossible,
|
||||||
host_buffer,
|
host_buffer,
|
||||||
host_buffer_impossible,
|
host_buffer_impossible,
|
||||||
..
|
..
|
||||||
|
|
@ -201,7 +214,7 @@ impl WlBuffer {
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
host_buffer.take();
|
host_buffer.take();
|
||||||
*host_buffer_impossible = !mem.pool().is_sealed_memfd();
|
*host_buffer_impossible = *udmabuf_impossible;
|
||||||
return match surface {
|
return match surface {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
s.shm_staging.take();
|
s.shm_staging.take();
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ impl WlShmPool {
|
||||||
false,
|
false,
|
||||||
Some(client),
|
Some(client),
|
||||||
Some(&client.state.cpu_worker),
|
Some(&client.state.cpu_worker),
|
||||||
|
false,
|
||||||
)?)),
|
)?)),
|
||||||
fd,
|
fd,
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
|
|
@ -68,6 +69,7 @@ impl WlShmPoolRequestHandler for WlShmPool {
|
||||||
req.stride,
|
req.stride,
|
||||||
format,
|
format,
|
||||||
&self.mem.get(),
|
&self.mem.get(),
|
||||||
|
None,
|
||||||
)?);
|
)?);
|
||||||
track!(self.client, buffer);
|
track!(self.client, buffer);
|
||||||
self.client.add_client_obj(&buffer)?;
|
self.client.add_client_obj(&buffer)?;
|
||||||
|
|
@ -92,6 +94,7 @@ impl WlShmPoolRequestHandler for WlShmPool {
|
||||||
false,
|
false,
|
||||||
Some(&self.client),
|
Some(&self.client),
|
||||||
Some(&self.client.state.cpu_worker),
|
Some(&self.client.state.cpu_worker),
|
||||||
|
false,
|
||||||
)?));
|
)?));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::ClientError,
|
client::ClientError,
|
||||||
|
clientmem::{ClientMem, ClientMemError},
|
||||||
gfx_api::GfxError,
|
gfx_api::GfxError,
|
||||||
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
|
ifs::{
|
||||||
|
wl_buffer::{WlBuffer, WlBufferError},
|
||||||
|
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
||||||
|
},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
||||||
|
|
@ -102,25 +106,52 @@ impl ZwpLinuxBufferParamsV1 {
|
||||||
fd: p.fd,
|
fd: p.fd,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let img = ctx.dmabuf_img(&dmabuf)?;
|
let get_id = || match buffer_id {
|
||||||
let (is_client_id, buffer_id) = match buffer_id {
|
None => self.parent.client.new_id(),
|
||||||
Some(i) => (true, i),
|
Some(i) => Ok(i),
|
||||||
None => (false, self.parent.client.new_id()?),
|
};
|
||||||
|
let buffer = if format.supports_shm
|
||||||
|
&& let Some(size) = dmabuf.udmabuf_size()
|
||||||
|
{
|
||||||
|
let p = &dmabuf.planes[0];
|
||||||
|
let client_mem = ClientMem::new(
|
||||||
|
&p.fd,
|
||||||
|
size,
|
||||||
|
true,
|
||||||
|
Some(&self.parent.client),
|
||||||
|
Some(&self.parent.client.state.cpu_worker),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map(Rc::new)
|
||||||
|
.map_err(ZwpLinuxBufferParamsV1Error::CreateClientMem)?;
|
||||||
|
Rc::new(WlBuffer::new_shm(
|
||||||
|
get_id()?,
|
||||||
|
&self.parent.client,
|
||||||
|
p.offset as usize,
|
||||||
|
dmabuf.width,
|
||||||
|
dmabuf.height,
|
||||||
|
p.stride as _,
|
||||||
|
format.format,
|
||||||
|
&client_mem,
|
||||||
|
Some((&p.fd, size)),
|
||||||
|
)?)
|
||||||
|
} else {
|
||||||
|
let img = ctx.dmabuf_img(&dmabuf)?;
|
||||||
|
Rc::new(WlBuffer::new_dmabuf(
|
||||||
|
get_id()?,
|
||||||
|
&self.parent.client,
|
||||||
|
format.format,
|
||||||
|
dmabuf,
|
||||||
|
&img,
|
||||||
|
))
|
||||||
};
|
};
|
||||||
let buffer = Rc::new(WlBuffer::new_dmabuf(
|
|
||||||
buffer_id,
|
|
||||||
&self.parent.client,
|
|
||||||
format.format,
|
|
||||||
dmabuf,
|
|
||||||
&img,
|
|
||||||
));
|
|
||||||
track!(self.parent.client, buffer);
|
track!(self.parent.client, buffer);
|
||||||
if is_client_id {
|
if buffer_id.is_some() {
|
||||||
self.parent.client.add_client_obj(&buffer)?;
|
self.parent.client.add_client_obj(&buffer)?;
|
||||||
} else {
|
} else {
|
||||||
self.parent.client.add_server_obj(&buffer);
|
self.parent.client.add_server_obj(&buffer);
|
||||||
}
|
}
|
||||||
Ok(buffer_id)
|
Ok(buffer.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,5 +249,10 @@ pub enum ZwpLinuxBufferParamsV1Error {
|
||||||
MissingPlane(usize),
|
MissingPlane(usize),
|
||||||
#[error("Could not import the buffer")]
|
#[error("Could not import the buffer")]
|
||||||
ImportError(#[from] GfxError),
|
ImportError(#[from] GfxError),
|
||||||
|
#[error("Could not create ClientMem")]
|
||||||
|
CreateClientMem(#[source] ClientMemError),
|
||||||
|
#[error(transparent)]
|
||||||
|
WlBufferError(Box<WlBufferError>),
|
||||||
}
|
}
|
||||||
efrom!(ZwpLinuxBufferParamsV1Error, ClientError);
|
efrom!(ZwpLinuxBufferParamsV1Error, ClientError);
|
||||||
|
efrom!(ZwpLinuxBufferParamsV1Error, WlBufferError);
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,15 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
format::Format,
|
format::Format,
|
||||||
utils::{compat::IoctlNumber, oserror::OsError},
|
utils::{compat::IoctlNumber, oserror::OsError},
|
||||||
video::Modifier,
|
video::{LINEAR_MODIFIER, Modifier},
|
||||||
},
|
},
|
||||||
arrayvec::ArrayVec,
|
arrayvec::ArrayVec,
|
||||||
std::rc::Rc,
|
std::{rc::Rc, sync::OnceLock},
|
||||||
uapi::{_IOW, _IOWR, OwnedFd, c::ioctl},
|
uapi::{
|
||||||
|
_IOW, _IOWR, OwnedFd,
|
||||||
|
c::{self, dev_t, ioctl},
|
||||||
|
format_ustr,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -53,6 +57,46 @@ impl DmaBuf {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn udmabuf_size(&self) -> Option<usize> {
|
||||||
|
if self.planes.len() != 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if self.modifier != LINEAR_MODIFIER {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let stat = match uapi::fstat(self.planes[0].fd.raw()) {
|
||||||
|
Ok(s) => s,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
static DMABUF_DEV: OnceLock<dev_t> = OnceLock::new();
|
||||||
|
match DMABUF_DEV.get() {
|
||||||
|
Some(d) => {
|
||||||
|
if stat.st_dev != *d {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if dma_buf_export_sync_file(&self.planes[0].fd, DMA_BUF_SYNC_READ).is_err() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let _ = DMABUF_DEV.set(stat.st_dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let path = format_ustr!("/sys/kernel/dmabuf/buffers/{}/exporter_name", stat.st_ino);
|
||||||
|
let Ok(file) = uapi::open(path, c::O_RDONLY, 0) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
const MARKER: &[u8] = b"udmabuf\n";
|
||||||
|
let mut buf = [0u8; MARKER.len()];
|
||||||
|
if uapi::read(file.raw(), &mut buf).is_err() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if buf != MARKER {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(stat.st_size as usize)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn import_sync_file(&self, flags: u32, sync_file: &OwnedFd) -> Result<(), OsError> {
|
pub fn import_sync_file(&self, flags: u32, sync_file: &OwnedFd) -> Result<(), OsError> {
|
||||||
for plane in &self.planes {
|
for plane in &self.planes {
|
||||||
dma_buf_import_sync_file(&plane.fd, flags, sync_file)?;
|
dma_buf_import_sync_file(&plane.fd, flags, sync_file)?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue