wayland.dmabuf: module docs & some logging
This commit is contained in:
parent
e11c0278dd
commit
c1f759aa00
|
@ -1,3 +1,70 @@
|
||||||
|
//! Linux DMABUF protocol
|
||||||
|
//!
|
||||||
|
//! This module provides helper to handle the linux-dmabuf protocol, which allows clients to submit their
|
||||||
|
//! contents as dmabuf file descriptors. These handlers automate the aggregation of the metadata associated
|
||||||
|
//! with a dma buffer, and do some basic checking of the sanity of what the client sends.
|
||||||
|
//!
|
||||||
|
//! ## How to use
|
||||||
|
//!
|
||||||
|
//! To setup the dmabuf global, you will need to provide 2 things:
|
||||||
|
//!
|
||||||
|
//! - a list of the dmabuf formats you wish to support
|
||||||
|
//! - an implementation of the `DmabufHandler` trait
|
||||||
|
//!
|
||||||
|
//! The list of supported format is just a `Vec<Format>`, where you will enter all the (format, modifier)
|
||||||
|
//! couples you support.
|
||||||
|
//!
|
||||||
|
//! The implementation of the `DmabufHandler` trait will be called whenever a client has finished setting up
|
||||||
|
//! a dma buffer. You will be handled the full details of the sclient's submission as a `BufferInfo` struct,
|
||||||
|
//! and you need to validate it and maybe import it into your rendered. The `BufferData` associated type
|
||||||
|
//! allows you to store any metadata of handle to the resource you need into the created `wl_buffer`,
|
||||||
|
//! user data, to then retrieve it when it is attached to a surface to re-identify the dmabuf.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # extern crate wayland_server;
|
||||||
|
//! # extern crate smithay;
|
||||||
|
//! use smithay::wayland::dmabuf::{DmabufHandler, BufferInfo, init_dmabuf_global};
|
||||||
|
//!
|
||||||
|
//! struct MyDmabufHandler;
|
||||||
|
//!
|
||||||
|
//! struct MyBufferData {
|
||||||
|
//! /* ... */
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl Drop for MyBufferData {
|
||||||
|
//! fn drop(&mut self) {
|
||||||
|
//! // This is called when all handles to this buffer have been dropped,
|
||||||
|
//! // both client-side and server side.
|
||||||
|
//! // You can now free the associated resource in your renderer.
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl DmabufHandler for MyDmabufHandler {
|
||||||
|
//! type BufferData = MyBufferData;
|
||||||
|
//! fn validate_dmabuf(&mut self, info: BufferInfo) -> Result<Self::BufferData, ()> {
|
||||||
|
//! /* validate the dmabuf and import it into your renderer state */
|
||||||
|
//! Ok(MyBufferData { /* ... */ })
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // Once this is defined, you can in your setup initialize the dmabuf global:
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap();
|
||||||
|
//! # let mut display = wayland_server::Display::new(event_loop.handle());
|
||||||
|
//! // define your supported formats
|
||||||
|
//! let formats = vec![
|
||||||
|
//! /* ... */
|
||||||
|
//! ];
|
||||||
|
//! let dmabuf_global = init_dmabuf_global(
|
||||||
|
//! &mut display,
|
||||||
|
//! formats,
|
||||||
|
//! MyDmabufHandler,
|
||||||
|
//! None // we don't provide a logger in this example
|
||||||
|
//! );
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
use std::{cell::RefCell, os::unix::io::RawFd, rc::Rc};
|
use std::{cell::RefCell, os::unix::io::RawFd, rc::Rc};
|
||||||
|
|
||||||
pub use wayland_protocols::unstable::linux_dmabuf::v1::server::zwp_linux_buffer_params_v1::Flags;
|
pub use wayland_protocols::unstable::linux_dmabuf::v1::server::zwp_linux_buffer_params_v1::Flags;
|
||||||
|
@ -11,12 +78,16 @@ use wayland_server::{protocol::wl_buffer, Display, Global, NewResource};
|
||||||
|
|
||||||
/// Representation of a Dmabuf format, as advertized to the client
|
/// Representation of a Dmabuf format, as advertized to the client
|
||||||
pub struct Format {
|
pub struct Format {
|
||||||
/// The format identifier
|
/// The format identifier.
|
||||||
|
///
|
||||||
|
/// It must be a `DRM_FORMAT` code, as defined by the libdrm's drm_fourcc.h. The Linux kernel's DRM
|
||||||
|
/// sub-system is the authoritative source on how the format codes should work.
|
||||||
pub format: u32,
|
pub format: u32,
|
||||||
/// High part of the supported modifiers
|
/// The supported dmabuf layout modifier.
|
||||||
pub modifier_hi: u32,
|
///
|
||||||
/// Low part of the supported modifiers
|
/// This is an opaque token. Drivers use this token to express tiling, compression, etc. driver-specific
|
||||||
pub modifier_lo: u32,
|
/// modifications to the base format defined by the DRM fourcc code.
|
||||||
|
pub modifier: u64,
|
||||||
/// Number of planes used by this format
|
/// Number of planes used by this format
|
||||||
pub plane_count: u32,
|
pub plane_count: u32,
|
||||||
}
|
}
|
||||||
|
@ -31,10 +102,8 @@ pub struct Plane {
|
||||||
pub offset: u32,
|
pub offset: u32,
|
||||||
/// Stride for this plane
|
/// Stride for this plane
|
||||||
pub stride: u32,
|
pub stride: u32,
|
||||||
/// High part of the modifiers for this plane
|
/// Modifier for this plane
|
||||||
pub modifier_hi: u32,
|
pub modifier: u64,
|
||||||
/// Low part of the modifiers for this plane
|
|
||||||
pub modifier_lo: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The complete information provided by the client to create a dmabuf buffer
|
/// The complete information provided by the client to create a dmabuf buffer
|
||||||
|
@ -60,7 +129,9 @@ pub struct BufferInfo {
|
||||||
pub trait DmabufHandler {
|
pub trait DmabufHandler {
|
||||||
/// The data of a successfully imported dmabuf.
|
/// The data of a successfully imported dmabuf.
|
||||||
///
|
///
|
||||||
/// This will be stored as the `user_data` of the `WlBuffer` associated with this dmabuf.
|
/// This will be stored as the `user_data` of the `WlBuffer` associated with this dmabuf. If it has a
|
||||||
|
/// destructor, it will be run when the client has destroyed the buffer and your compositor has dropped
|
||||||
|
/// all of its `WlBuffer` handles to it.
|
||||||
type BufferData: 'static;
|
type BufferData: 'static;
|
||||||
/// Validate a dmabuf
|
/// Validate a dmabuf
|
||||||
///
|
///
|
||||||
|
@ -102,15 +173,22 @@ where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
H: DmabufHandler + 'static,
|
H: DmabufHandler + 'static,
|
||||||
{
|
{
|
||||||
let log = crate::slog_or_stdlog(logger);
|
let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "dmabuf_handler"));
|
||||||
|
|
||||||
let max_planes = formats.iter().map(|f| f.plane_count).max().unwrap_or(0);
|
let max_planes = formats.iter().map(|f| f.plane_count).max().unwrap_or(0);
|
||||||
let formats = Rc::new(formats);
|
let formats = Rc::new(formats);
|
||||||
let handler = Rc::new(RefCell::new(handler));
|
let handler = Rc::new(RefCell::new(handler));
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
log,
|
||||||
|
"Initializing DMABUF handler with {} supported formats",
|
||||||
|
formats.len()
|
||||||
|
);
|
||||||
|
|
||||||
display.create_global(3, move |new_dmabuf, version| {
|
display.create_global(3, move |new_dmabuf, version| {
|
||||||
let dma_formats = formats.clone();
|
let dma_formats = formats.clone();
|
||||||
let dma_handler = handler.clone();
|
let dma_handler = handler.clone();
|
||||||
|
let dma_log = log.clone();
|
||||||
let dmabuf: zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1 = new_dmabuf.implement_closure(
|
let dmabuf: zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1 = new_dmabuf.implement_closure(
|
||||||
move |req, _| match req {
|
move |req, _| match req {
|
||||||
zwp_linux_dmabuf_v1::Request::CreateParams { params_id } => {
|
zwp_linux_dmabuf_v1::Request::CreateParams { params_id } => {
|
||||||
|
@ -121,6 +199,7 @@ where
|
||||||
used: false,
|
used: false,
|
||||||
formats: dma_formats.clone(),
|
formats: dma_formats.clone(),
|
||||||
handler: dma_handler.clone(),
|
handler: dma_handler.clone(),
|
||||||
|
log: dma_log.clone(),
|
||||||
},
|
},
|
||||||
None::<fn(_)>,
|
None::<fn(_)>,
|
||||||
(),
|
(),
|
||||||
|
@ -136,7 +215,7 @@ where
|
||||||
for f in &*formats {
|
for f in &*formats {
|
||||||
dmabuf.format(f.format);
|
dmabuf.format(f.format);
|
||||||
if version >= 3 {
|
if version >= 3 {
|
||||||
dmabuf.modifier(f.format, f.modifier_hi, f.modifier_lo);
|
dmabuf.modifier(f.format, (f.modifier >> 32) as u32, f.modifier as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -148,6 +227,7 @@ struct ParamsHandler<H: DmabufHandler> {
|
||||||
used: bool,
|
used: bool,
|
||||||
formats: Rc<Vec<Format>>,
|
formats: Rc<Vec<Format>>,
|
||||||
handler: Rc<RefCell<H>>,
|
handler: Rc<RefCell<H>>,
|
||||||
|
log: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: DmabufHandler> ParamRequestHandler for ParamsHandler<H> {
|
impl<H: DmabufHandler> ParamRequestHandler for ParamsHandler<H> {
|
||||||
|
@ -193,8 +273,7 @@ impl<H: DmabufHandler> ParamRequestHandler for ParamsHandler<H> {
|
||||||
plane_idx,
|
plane_idx,
|
||||||
offset,
|
offset,
|
||||||
stride,
|
stride,
|
||||||
modifier_hi,
|
modifier: ((modifier_hi as u64) << 32) + (modifier_lo as u64),
|
||||||
modifier_lo,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +295,7 @@ impl<H: DmabufHandler> ParamRequestHandler for ParamsHandler<H> {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
) {
|
) {
|
||||||
|
trace!(self.log, "Killing client providing bogus dmabuf buffer params.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let info = BufferInfo {
|
let info = BufferInfo {
|
||||||
|
@ -233,9 +313,11 @@ impl<H: DmabufHandler> ParamRequestHandler for ParamsHandler<H> {
|
||||||
.and_then(|c| c.create_resource::<wl_buffer::WlBuffer>(1))
|
.and_then(|c| c.create_resource::<wl_buffer::WlBuffer>(1))
|
||||||
{
|
{
|
||||||
let buffer = handler.create_buffer(data, buffer);
|
let buffer = handler.create_buffer(data, buffer);
|
||||||
|
trace!(self.log, "Creating a new validated dma wl_buffer.");
|
||||||
params.created(&buffer);
|
params.created(&buffer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
trace!(self.log, "Refusing creation of an invalid dma wl_buffer.");
|
||||||
params.failed();
|
params.failed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,6 +348,7 @@ impl<H: DmabufHandler> ParamRequestHandler for ParamsHandler<H> {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
) {
|
) {
|
||||||
|
trace!(self.log, "Killing client providing bogus dmabuf buffer params.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let info = BufferInfo {
|
let info = BufferInfo {
|
||||||
|
@ -277,8 +360,13 @@ impl<H: DmabufHandler> ParamRequestHandler for ParamsHandler<H> {
|
||||||
};
|
};
|
||||||
let mut handler = self.handler.borrow_mut();
|
let mut handler = self.handler.borrow_mut();
|
||||||
if let Ok(data) = handler.validate_dmabuf(info) {
|
if let Ok(data) = handler.validate_dmabuf(info) {
|
||||||
|
trace!(self.log, "Creating a new validated immediate dma wl_buffer.");
|
||||||
handler.create_buffer(data, buffer_id);
|
handler.create_buffer(data, buffer_id);
|
||||||
} else {
|
} else {
|
||||||
|
trace!(
|
||||||
|
self.log,
|
||||||
|
"Refusing creation of an invalid immediate dma wl_buffer, killing client."
|
||||||
|
);
|
||||||
params.as_ref().post_error(
|
params.as_ref().post_error(
|
||||||
ParamError::InvalidWlBuffer as u32,
|
ParamError::InvalidWlBuffer as u32,
|
||||||
"create_immed resulted in an invalid buffer.".into(),
|
"create_immed resulted in an invalid buffer.".into(),
|
||||||
|
|
Loading…
Reference in New Issue