vulkan: import wl_shm buffers as udmabuf
This commit is contained in:
parent
47e15c6083
commit
a3d3a62af3
14 changed files with 545 additions and 99 deletions
|
|
@ -101,7 +101,7 @@ impl ExtImageCopyCaptureFrameV1 {
|
|||
let mut shm_bridge = self.session.shm_bridge.take();
|
||||
let mut shm_staging = self.session.shm_staging.take();
|
||||
match storage {
|
||||
WlBufferStorage::Shm { mem, stride } => {
|
||||
WlBufferStorage::Shm { mem, stride, .. } => {
|
||||
if let Some(b) = &shm_bridge
|
||||
&& (b.physical_size() != buffer.rect.size()
|
||||
|| b.format() != buffer.format
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ use {
|
|||
client::{Client, ClientError},
|
||||
clientmem::{ClientMem, ClientMemError, ClientMemOffset},
|
||||
format::{ARGB8888, Format},
|
||||
gfx_api::{GfxError, GfxFramebuffer, GfxImage, GfxTexture},
|
||||
gfx_api::{GfxBuffer, GfxContext, GfxError, GfxFramebuffer, GfxImage, GfxTexture},
|
||||
ifs::wl_surface::WlSurface,
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
rect::{Rect, Region},
|
||||
utils::errorfmt::ErrorFmt,
|
||||
utils::{errorfmt::ErrorFmt, page_size::page_size},
|
||||
video::dmabuf::DmaBuf,
|
||||
wire::{WlBufferId, wl_buffer::*},
|
||||
},
|
||||
|
|
@ -17,12 +17,14 @@ use {
|
|||
rc::Rc,
|
||||
},
|
||||
thiserror::Error,
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
|
||||
pub enum WlBufferStorage {
|
||||
Shm {
|
||||
mem: Rc<ClientMemOffset>,
|
||||
stride: i32,
|
||||
dmabuf_buffer_params: DmabufBufferParams,
|
||||
},
|
||||
Dmabuf {
|
||||
img: Rc<dyn GfxImage>,
|
||||
|
|
@ -31,6 +33,16 @@ pub enum WlBufferStorage {
|
|||
},
|
||||
}
|
||||
|
||||
pub struct DmabufBufferParams {
|
||||
size: usize,
|
||||
udmabuf: Option<Rc<OwnedFd>>,
|
||||
udmabuf_offset: usize,
|
||||
udmabuf_size: usize,
|
||||
udmabuf_impossible: bool,
|
||||
host_buffer: Option<Rc<dyn GfxBuffer>>,
|
||||
host_buffer_impossible: bool,
|
||||
}
|
||||
|
||||
pub struct WlBuffer {
|
||||
pub id: WlBufferId,
|
||||
destroyed: Cell<bool>,
|
||||
|
|
@ -118,7 +130,19 @@ impl WlBuffer {
|
|||
format,
|
||||
dmabuf: None,
|
||||
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
|
||||
storage: RefCell::new(Some(WlBufferStorage::Shm { mem, stride })),
|
||||
storage: RefCell::new(Some(WlBufferStorage::Shm {
|
||||
dmabuf_buffer_params: 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(),
|
||||
},
|
||||
mem,
|
||||
stride,
|
||||
})),
|
||||
shm: true,
|
||||
width,
|
||||
height,
|
||||
|
|
@ -169,7 +193,18 @@ impl WlBuffer {
|
|||
return false;
|
||||
};
|
||||
let had_texture = match s {
|
||||
WlBufferStorage::Shm { .. } => {
|
||||
WlBufferStorage::Shm {
|
||||
mem,
|
||||
dmabuf_buffer_params:
|
||||
DmabufBufferParams {
|
||||
host_buffer,
|
||||
host_buffer_impossible,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
host_buffer.take();
|
||||
*host_buffer_impossible = !mem.pool().is_sealed_memfd();
|
||||
return match surface {
|
||||
Some(s) => {
|
||||
s.shm_staging.take();
|
||||
|
|
@ -224,6 +259,69 @@ impl WlBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_gfx_buffer(
|
||||
self: &Rc<Self>,
|
||||
ctx: &Rc<dyn GfxContext>,
|
||||
mem: &Rc<ClientMemOffset>,
|
||||
dmabuf_buffer_params: &mut DmabufBufferParams,
|
||||
) -> Result<Option<Rc<dyn GfxBuffer>>, GfxError> {
|
||||
let DmabufBufferParams {
|
||||
size,
|
||||
udmabuf,
|
||||
udmabuf_offset,
|
||||
udmabuf_size,
|
||||
udmabuf_impossible,
|
||||
host_buffer,
|
||||
host_buffer_impossible,
|
||||
} = dmabuf_buffer_params;
|
||||
if let Some(hb) = host_buffer {
|
||||
return Ok(Some(hb.clone()));
|
||||
}
|
||||
if *host_buffer_impossible {
|
||||
return Ok(None);
|
||||
}
|
||||
let udmabuf = 'udmabuf: {
|
||||
if let Some(b) = udmabuf {
|
||||
break 'udmabuf b.clone();
|
||||
}
|
||||
if *udmabuf_impossible {
|
||||
return Ok(None);
|
||||
}
|
||||
let Some(dev) = self.client.state.udmabuf() else {
|
||||
return Ok(None);
|
||||
};
|
||||
let mask = page_size() - 1;
|
||||
let offset = mem.offset() & mask;
|
||||
let base = mem.offset() & !mask;
|
||||
let end = (mem.offset() + *size + mask) & !mask;
|
||||
let len = end - base;
|
||||
match dev.create_dmabuf_from_memfd(mem.pool().fd(), base, len) {
|
||||
Ok(b) => {
|
||||
let b = Rc::new(b);
|
||||
*udmabuf_offset = offset;
|
||||
*udmabuf_size = len;
|
||||
*udmabuf = Some(b.clone());
|
||||
b
|
||||
}
|
||||
Err(e) => {
|
||||
*udmabuf_impossible = true;
|
||||
log::debug!("Could not create udmabuf: {}", ErrorFmt(e));
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
};
|
||||
let hb = match ctx.create_dmabuf_buffer(&udmabuf, *udmabuf_offset, *udmabuf_size) {
|
||||
Ok(hb) => hb,
|
||||
Err(e) => {
|
||||
*host_buffer_impossible = true;
|
||||
log::debug!("Could not create gfx host buffer: {}", ErrorFmt(e));
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
*host_buffer = Some(hb.clone());
|
||||
Ok(Some(hb))
|
||||
}
|
||||
|
||||
fn update_texture(&self, surface: &WlSurface, sync_shm: bool) -> Result<(), WlBufferError> {
|
||||
let storage = &mut *self.storage.borrow_mut();
|
||||
let storage = match storage {
|
||||
|
|
@ -231,7 +329,7 @@ impl WlBuffer {
|
|||
_ => return Ok(()),
|
||||
};
|
||||
match storage {
|
||||
WlBufferStorage::Shm { mem, stride } => {
|
||||
WlBufferStorage::Shm { mem, stride, .. } => {
|
||||
if sync_shm && let Some(ctx) = self.client.state.render_ctx.get() {
|
||||
let tex = ctx.async_shmem_texture(
|
||||
self.format,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use {
|
|||
utils::{
|
||||
clonecell::CloneCell,
|
||||
copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt,
|
||||
hash_map_ext::HashMapExt,
|
||||
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
||||
numcell::NumCell,
|
||||
|
|
@ -599,7 +600,12 @@ fn schedule_async_upload(
|
|||
let Some(Some(buf)) = &pending.buffer else {
|
||||
return Ok(None);
|
||||
};
|
||||
let Some(WlBufferStorage::Shm { mem, stride, .. }) = &*buf.storage.borrow() else {
|
||||
let Some(WlBufferStorage::Shm {
|
||||
mem,
|
||||
stride,
|
||||
dmabuf_buffer_params,
|
||||
}) = &mut *buf.storage.borrow_mut()
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let back = surface.shm_textures.back();
|
||||
|
|
@ -613,6 +619,11 @@ fn schedule_async_upload(
|
|||
back.damage.clear();
|
||||
back.damage.damage(slice::from_ref(&buf.rect));
|
||||
};
|
||||
let state = &surface.client.state;
|
||||
let ctx = state
|
||||
.render_ctx
|
||||
.get()
|
||||
.ok_or(WlSurfaceError::NoRenderContext)?;
|
||||
let back_tex = match back_tex_opt {
|
||||
Some(b) => {
|
||||
if pending.damage_full || pending.surface_damage.is_not_empty() {
|
||||
|
|
@ -624,12 +635,8 @@ fn schedule_async_upload(
|
|||
}
|
||||
None => {
|
||||
damage_full();
|
||||
let state = &surface.client.state;
|
||||
let ctx = state
|
||||
.render_ctx
|
||||
.get()
|
||||
.ok_or(WlSurfaceError::NoRenderContext)?;
|
||||
let back_tex = ctx
|
||||
.clone()
|
||||
.async_shmem_texture(
|
||||
buf.format,
|
||||
buf.rect.width(),
|
||||
|
|
@ -642,6 +649,20 @@ fn schedule_async_upload(
|
|||
back_tex
|
||||
}
|
||||
};
|
||||
match buf.get_gfx_buffer(&ctx, mem, dmabuf_buffer_params) {
|
||||
Ok(Some(hb)) => {
|
||||
return back_tex
|
||||
.async_upload_from_buffer(&hb, node_ref.clone(), back.damage.get())
|
||||
.map_err(WlSurfaceError::PrepareAsyncUpload);
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Could not create GPU mapping of host buffer: {}",
|
||||
ErrorFmt(e),
|
||||
);
|
||||
}
|
||||
}
|
||||
let mut staging_opt = surface.shm_staging.get();
|
||||
if let Some(staging) = &staging_opt
|
||||
&& staging.size() != back_tex.staging_size()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue