Inital support for allocating dmabufs

This commit is contained in:
Ian Douglas Scott 2023-11-08 15:51:12 -08:00
parent c567cb30d3
commit f585cbc32f
3 changed files with 114 additions and 18 deletions

1
Cargo.lock generated
View file

@ -734,6 +734,7 @@ dependencies = [
"futures-channel",
"gbm",
"libcosmic",
"memmap2 0.9.0",
"tokio",
"wayland-protocols 0.31.0",
"zbus",

View file

@ -10,6 +10,7 @@ env_logger = "0.10.0"
futures-channel = "0.3.25"
gbm = "0.13.0"
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["tokio", "wayland"] }
memmap2 = "0.9.0"
tokio = "1.23.0"
wayland-protocols = "0.31.0"
zbus = { version = "3.7.0", default-features = false, features = ["tokio"] }

View file

@ -8,31 +8,30 @@ use cctk::{
},
};
use cosmic::iced::widget::image;
use std::os::fd::{AsFd, OwnedFd};
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_buffer_params_v1;
use super::AppData;
enum BufferBacking {
Shm(RawPool),
Dmabuf(OwnedFd),
}
pub struct Buffer {
pub pool: RawPool,
backing: BufferBacking,
pub buffer: wl_buffer::WlBuffer,
pub buffer_info: BufferInfo,
}
impl AppData {
pub fn create_buffer(&self, buffer_infos: &[BufferInfo]) -> Buffer {
// XXX Handle other formats?
let format = wl_shm::Format::Abgr8888.into();
let buffer_info = buffer_infos
.iter()
.find(|x| x.type_ == WEnum::Value(BufferType::WlShm) && x.format == format)
.unwrap();
// Assume format is already known to be valid
fn create_shm_backing(&self, buffer_info: &BufferInfo) -> (BufferBacking, wl_buffer::WlBuffer) {
let mut pool = RawPool::new(
(buffer_info.stride * buffer_info.height) as usize,
&self.shm_state,
)
.unwrap();
let format = wl_shm::Format::try_from(buffer_info.format).unwrap();
let buffer = pool.create_buffer(
0,
@ -43,8 +42,85 @@ impl AppData {
(),
&self.qh,
);
(BufferBacking::Shm(pool), buffer)
}
#[allow(dead_code)]
fn create_gbm_backing(
&self,
buffer_info: &BufferInfo,
needs_linear: bool,
) -> Option<(BufferBacking, wl_buffer::WlBuffer)> {
// TODO Handle errors in some way
let gbm = self.gbm.as_ref()?;
let feedback = self.dmabuf_feedback.as_ref()?;
let formats = feedback.format_table();
let format_info = feedback
.tranches()
.iter()
.flat_map(|x| &x.formats)
.filter_map(|x| formats.get(*x as usize))
.find(|x| {
x.format == buffer_info.format
&& (!needs_linear || x.modifier == u64::from(gbm::Modifier::Linear))
})?;
let format = gbm::Format::try_from(buffer_info.format).ok()?;
let modifier = gbm::Modifier::try_from(format_info.modifier).ok()?;
let bo = gbm
.create_buffer_object_with_modifiers::<()>(
buffer_info.width,
buffer_info.height,
format,
[modifier].into_iter(),
)
.ok()?;
let fd = bo.fd().ok()?;
let stride = bo.stride().ok()?;
let params = self.dmabuf_state.create_params(&self.qh).ok()?;
params.add(fd.as_fd(), 0, 0, stride, modifier.into());
let buffer = params
.create_immed(
buffer_info.width as i32,
buffer_info.height as i32,
buffer_info.format,
zwp_linux_buffer_params_v1::Flags::empty(),
&self.qh,
)
.0;
Some((BufferBacking::Dmabuf(fd), buffer))
}
pub fn create_buffer(&self, buffer_infos: &[BufferInfo]) -> Buffer {
// XXX Handle other formats?
let format = wl_shm::Format::Abgr8888.into();
/*
if let Some(buffer_info) = buffer_infos
.iter()
.find(|x| x.type_ == WEnum::Value(BufferType::Dmabuf) && x.format == format)
{
if let Some((backing, buffer)) = self.create_gbm_backing(buffer_info, true) {
return Buffer {
backing,
buffer,
buffer_info: buffer_info.clone(),
};
}
}
*/
// Fallback to shm buffer
// Assume format is already known to be valid
let buffer_info = buffer_infos
.iter()
.find(|x| x.type_ == WEnum::Value(BufferType::WlShm) && x.format == format)
.unwrap();
let (backing, buffer) = self.create_shm_backing(buffer_info);
Buffer {
pool,
backing,
buffer,
buffer_info: buffer_info.clone(),
}
@ -53,14 +129,32 @@ impl AppData {
impl Buffer {
// Buffer must be released by server for safety
// XXX is this at all a performance issue?
#[allow(clippy::wrong_self_convention)]
pub unsafe fn to_image(&mut self) -> image::Handle {
// XXX is this at all a performance issue?
image::Handle::from_pixels(
self.buffer_info.width,
self.buffer_info.height,
self.pool.mmap().to_vec(),
)
let pixels = match &mut self.backing {
BufferBacking::Shm(pool) => pool.mmap().to_vec(),
// NOTE: Only will work with linear modifier
BufferBacking::Dmabuf(fd) => {
// XXX Error handling?
let mmap = memmap2::Mmap::map(&*fd).unwrap();
if self.buffer_info.stride == self.buffer_info.width * 4 {
mmap.to_vec()
} else {
let width = self.buffer_info.width as usize;
let height = self.buffer_info.height as usize;
let stride = self.buffer_info.stride as usize;
let output_stride = width * 4;
let mut pixels = vec![0; height * output_stride];
for y in 0..height {
pixels[y * output_stride..y * output_stride + output_stride]
.copy_from_slice(&mmap[y * stride..y * stride + output_stride]);
}
pixels
}
}
};
image::Handle::from_pixels(self.buffer_info.width, self.buffer_info.height, pixels)
}
}