1
0
Fork 0
forked from wry/wry

vulkan: import wl_shm buffers as udmabuf

This commit is contained in:
Julian Orth 2025-09-30 18:52:57 +02:00
parent 47e15c6083
commit a3d3a62af3
14 changed files with 545 additions and 99 deletions

View file

@ -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

View file

@ -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,

View file

@ -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()