dmabuf: Unify types of `wayland::dmabuf` and `allocator::dmabuf`

This commit is contained in:
Victor Brekenfeld 2021-06-06 15:24:48 +02:00 committed by Victor Berger
parent b6822becf6
commit a38592bc92
8 changed files with 468 additions and 337 deletions

View File

@ -10,21 +10,67 @@
//! This can be especially useful in resources where other parts of the stack should decide upon //! This can be especially useful in resources where other parts of the stack should decide upon
//! the lifetime of the buffer. E.g. when you are only caching associated resources for a dmabuf. //! the lifetime of the buffer. E.g. when you are only caching associated resources for a dmabuf.
use super::{Buffer, Format, Modifier}; use super::{Buffer, Format, Fourcc, Modifier};
use std::os::unix::io::RawFd; use std::os::unix::io::{IntoRawFd, RawFd};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::hash::{Hash, Hasher};
const MAX_PLANES: usize = 4; /// Maximum amount of planes this implementation supports
pub const MAX_PLANES: usize = 4;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct DmabufInternal { pub(crate) struct DmabufInternal {
pub num_planes: usize, /// The submitted planes
pub offsets: [u32; MAX_PLANES], pub planes: Vec<Plane>,
pub strides: [u32; MAX_PLANES], /// The width of this buffer
pub fds: [RawFd; MAX_PLANES], pub width: i32,
pub width: u32, /// The height of this buffer
pub height: u32, pub height: i32,
pub format: Format, /// The format in use
pub format: Fourcc,
/// The flags applied to it
///
/// This is a bitflag, to be compared with the `Flags` enum re-exported by this module.
pub flags: DmabufFlags,
}
#[derive(Debug)]
pub(crate) struct Plane {
pub fd: Option<RawFd>,
/// The plane index
pub plane_idx: u32,
/// Offset from the start of the Fd
pub offset: u32,
/// Stride for this plane
pub stride: u32,
/// Modifier for this plane
pub modifier: Modifier,
}
impl IntoRawFd for Plane {
fn into_raw_fd(mut self) -> RawFd {
self.fd.take().unwrap()
}
}
impl Drop for Plane {
fn drop(&mut self) {
if let Some(fd) = self.fd.take() {
let _ = nix::unistd::close(fd);
}
}
}
bitflags! {
/// Possible flags for a DMA buffer
pub struct DmabufFlags: u32 {
/// The buffer content is Y-inverted
const Y_INVERT = 1;
/// The buffer content is interlaced
const INTERLACED = 2;
/// The buffer content if interlaced is bottom-field first
const BOTTOM_FIRST = 4;
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -42,109 +88,138 @@ impl PartialEq for Dmabuf {
} }
impl Eq for Dmabuf {} impl Eq for Dmabuf {}
impl PartialEq<WeakDmabuf> for Dmabuf {
fn eq(&self, other: &WeakDmabuf) -> bool {
if let Some(dmabuf) = other.upgrade() {
return Arc::ptr_eq(&self.0, &dmabuf.0);
}
false
}
}
impl PartialEq for WeakDmabuf { impl PartialEq for WeakDmabuf {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if let Some(dmabuf) = self.upgrade() { Weak::ptr_eq(&self.0, &other.0)
return &dmabuf == other; }
} }
false impl Eq for WeakDmabuf {}
impl Hash for Dmabuf {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.0).hash(state)
}
}
impl Hash for WeakDmabuf {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_ptr().hash(state)
} }
} }
impl Buffer for Dmabuf { impl Buffer for Dmabuf {
fn width(&self) -> u32 { fn width(&self) -> u32 {
self.0.width self.0.width as u32
} }
fn height(&self) -> u32 { fn height(&self) -> u32 {
self.0.height self.0.height as u32
} }
fn format(&self) -> Format { fn format(&self) -> Format {
self.0.format Format {
code: self.0.format,
modifier: self.0.planes[0].modifier,
}
}
}
/// Builder for Dmabufs
pub struct DmabufBuilder {
internal: DmabufInternal,
}
impl DmabufBuilder {
/// Add a plane to the construted Dmabuf
///
/// *Note*: Each Dmabuf needs atleast one plane.
/// MAX_PLANES notes the maximum amount of planes any format may use with this implementation.
pub fn add_plane(&mut self, fd: RawFd, idx: u32, offset: u32, stride: u32, modifier: Modifier) -> bool {
if self.internal.planes.len() == MAX_PLANES {
return false;
}
self.internal.planes.push(Plane {
fd: Some(fd),
plane_idx: idx,
offset,
stride,
modifier,
});
true
}
/// Build a `Dmabuf` out of the provided parameters and planes
///
/// Returns `None` if the builder has no planes attached.
pub fn build(mut self) -> Option<Dmabuf> {
if self.internal.planes.len() == 0 {
return None;
}
self.internal.planes.sort_by_key(|plane| plane.plane_idx);
Some(Dmabuf(Arc::new(self.internal)))
} }
} }
impl Dmabuf { impl Dmabuf {
/// Create a new Dmabuf by intializing with values from an existing buffer
///
// Note: the `src` Buffer is only used a reference for size and format. // Note: the `src` Buffer is only used a reference for size and format.
// The contents are determined by the provided file descriptors, which // The contents are determined by the provided file descriptors, which
// do not need to refer to the same buffer `src` does. // do not need to refer to the same buffer `src` does.
pub(crate) fn new( pub fn new_from_buffer(src: &impl Buffer, flags: DmabufFlags) -> DmabufBuilder {
src: &impl Buffer, DmabufBuilder {
planes: usize, internal: DmabufInternal {
offsets: &[u32], planes: Vec::with_capacity(MAX_PLANES),
strides: &[u32], width: src.width() as i32,
fds: &[RawFd], height: src.height() as i32,
) -> Option<Dmabuf> { format: src.format().code,
if offsets.len() < planes flags,
|| strides.len() < planes },
|| fds.len() < planes
|| planes == 0
|| planes > MAX_PLANES
{
return None;
} }
let end = [0u32, 0, 0];
let end_fds = [0i32, 0, 0];
let mut offsets = offsets.iter().take(planes).chain(end.iter());
let mut strides = strides.iter().take(planes).chain(end.iter());
let mut fds = fds.iter().take(planes).chain(end_fds.iter());
Some(Dmabuf(Arc::new(DmabufInternal {
num_planes: planes,
offsets: [
*offsets.next().unwrap(),
*offsets.next().unwrap(),
*offsets.next().unwrap(),
*offsets.next().unwrap(),
],
strides: [
*strides.next().unwrap(),
*strides.next().unwrap(),
*strides.next().unwrap(),
*strides.next().unwrap(),
],
fds: [
*fds.next().unwrap(),
*fds.next().unwrap(),
*fds.next().unwrap(),
*fds.next().unwrap(),
],
width: src.width(),
height: src.height(),
format: src.format(),
})))
} }
/// Return raw handles of the planes of this buffer /// Create a new Dmabuf
pub fn handles(&self) -> &[RawFd] { pub fn new(width: u32, height: u32, format: Fourcc, flags: DmabufFlags) -> DmabufBuilder {
self.0.fds.split_at(self.0.num_planes).0 DmabufBuilder {
internal: DmabufInternal {
planes: Vec::with_capacity(MAX_PLANES),
width: width as i32,
height: height as i32,
format,
flags,
},
}
} }
/// Return offsets for the planes of this buffer /// The amount of planes this Dmabuf has
pub fn offsets(&self) -> &[u32] { pub fn num_planes(&self) -> usize {
self.0.offsets.split_at(self.0.num_planes).0 self.0.planes.len()
} }
/// Return strides for the planes of this buffer /// Returns raw handles of the planes of this buffer
pub fn strides(&self) -> &[u32] { pub fn handles<'a>(&'a self) -> impl Iterator<Item = RawFd> + 'a {
self.0.strides.split_at(self.0.num_planes).0 self.0.planes.iter().map(|p| *p.fd.as_ref().unwrap())
} }
/// Check if this buffer format has any vendor-specific modifiers set or is implicit/linear /// Returns offsets for the planes of this buffer
pub fn offsets<'a>(&'a self) -> impl Iterator<Item = u32> + 'a {
self.0.planes.iter().map(|p| p.offset)
}
/// Returns strides for the planes of this buffer
pub fn strides<'a>(&'a self) -> impl Iterator<Item = u32> + 'a {
self.0.planes.iter().map(|p| p.stride)
}
/// Returns if this buffer format has any vendor-specific modifiers set or is implicit/linear
pub fn has_modifier(&self) -> bool { pub fn has_modifier(&self) -> bool {
self.0.format.modifier != Modifier::Invalid && self.0.format.modifier != Modifier::Linear self.0.planes[0].modifier != Modifier::Invalid && self.0.planes[0].modifier != Modifier::Linear
}
/// Returns if the buffer is stored inverted on the y-axis
pub fn y_inverted(&self) -> bool {
self.0.flags.contains(DmabufFlags::Y_INVERT)
} }
/// Create a weak reference to this dmabuf /// Create a weak reference to this dmabuf
@ -162,16 +237,6 @@ impl WeakDmabuf {
} }
} }
impl Drop for DmabufInternal {
fn drop(&mut self) {
for fd in self.fds.iter() {
if *fd != 0 {
let _ = nix::unistd::close(*fd);
}
}
}
}
/// Buffer that can be exported as Dmabufs /// Buffer that can be exported as Dmabufs
pub trait AsDmabuf { pub trait AsDmabuf {
/// Error type returned, if exporting fails /// Error type returned, if exporting fails

View File

@ -5,7 +5,7 @@
//! conversions to and from [dmabufs](super::dmabuf). //! conversions to and from [dmabufs](super::dmabuf).
use super::{ use super::{
dmabuf::{AsDmabuf, Dmabuf}, dmabuf::{AsDmabuf, Dmabuf, DmabufFlags, MAX_PLANES},
Allocator, Buffer, Format, Fourcc, Modifier, Allocator, Buffer, Format, Fourcc, Modifier,
}; };
pub use gbm::{BufferObject as GbmBuffer, BufferObjectFlags as GbmBufferFlags, Device as GbmDevice}; pub use gbm::{BufferObject as GbmBuffer, BufferObjectFlags as GbmBufferFlags, Device as GbmDevice};
@ -95,20 +95,21 @@ impl<T> AsDmabuf for GbmBuffer<T> {
return Err(GbmConvertError::UnsupportedBuffer); //TODO return Err(GbmConvertError::UnsupportedBuffer); //TODO
} }
let fds = [self.fd()?, 0, 0, 0]; if self.fd()? == 0 {
//if fds.iter().any(|fd| fd == 0) {
if fds[0] < 0 {
return Err(GbmConvertError::InvalidFD); return Err(GbmConvertError::InvalidFD);
} }
let offsets = (0i32..planes) let mut builder = Dmabuf::new_from_buffer(self, DmabufFlags::empty());
.map(|i| self.offset(i)) for idx in 0..planes {
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?; builder.add_plane(
let strides = (0i32..planes) self.fd()?,
.map(|i| self.stride_for_plane(i)) idx as u32,
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?; self.offset(idx)?,
self.stride_for_plane(idx)?,
Ok(Dmabuf::new(self, planes as usize, &offsets, &strides, &fds).unwrap()) self.modifier()?,
);
}
Ok(builder.build().unwrap())
} }
} }
@ -119,27 +120,39 @@ impl Dmabuf {
gbm: &GbmDevice<A>, gbm: &GbmDevice<A>,
usage: GbmBufferFlags, usage: GbmBufferFlags,
) -> std::io::Result<GbmBuffer<T>> { ) -> std::io::Result<GbmBuffer<T>> {
let buf = &*self.0; let mut handles = [0; MAX_PLANES];
if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 { for (i, handle) in self.handles().take(MAX_PLANES).enumerate() {
handles[i] = handle;
}
let mut strides = [0i32; MAX_PLANES];
for (i, stride) in self.strides().take(MAX_PLANES).enumerate() {
strides[i] = stride as i32;
}
let mut offsets = [0i32; MAX_PLANES];
for (i, offset) in self.offsets().take(MAX_PLANES).enumerate() {
offsets[i] = offset as i32;
}
if self.has_modifier() || self.num_planes() > 1 || self.offsets().next().unwrap() != 0 {
gbm.import_buffer_object_from_dma_buf_with_modifiers( gbm.import_buffer_object_from_dma_buf_with_modifiers(
buf.num_planes as u32, self.num_planes() as u32,
buf.fds, handles,
buf.width, self.width(),
buf.height, self.height(),
buf.format.code, self.format().code,
usage, usage,
unsafe { std::mem::transmute::<[u32; 4], [i32; 4]>(buf.strides) }, strides,
unsafe { std::mem::transmute::<[u32; 4], [i32; 4]>(buf.offsets) }, offsets,
buf.format.modifier, self.format().modifier,
) )
} else { } else {
gbm.import_buffer_object_from_dma_buf( gbm.import_buffer_object_from_dma_buf(
buf.fds[0], handles[0],
buf.width, self.width(),
buf.height, self.height(),
buf.strides[0], strides[0] as u32,
buf.format.code, self.format().code,
if buf.format.modifier == Modifier::Linear { if self.format().modifier == Modifier::Linear {
usage | GbmBufferFlags::LINEAR usage | GbmBufferFlags::LINEAR
} else { } else {
usage usage

View File

@ -19,10 +19,10 @@ use crate::backend::egl::{
ffi, ffi,
ffi::egl::types::EGLImage, ffi::egl::types::EGLImage,
native::EGLNativeDisplay, native::EGLNativeDisplay,
wrap_egl_call, EGLError, Error, Format, wrap_egl_call, EGLError, Error,
}; };
#[cfg(feature = "wayland_frontend")] #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
use crate::backend::egl::{BufferAccessError, EGLBuffer}; use crate::backend::egl::{BufferAccessError, EGLBuffer, Format};
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed /// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
/// once all resources bound to it have been dropped. /// once all resources bound to it have been dropped.
@ -473,18 +473,17 @@ impl EGLDisplay {
for (i, ((fd, offset), stride)) in dmabuf for (i, ((fd, offset), stride)) in dmabuf
.handles() .handles()
.iter()
.zip(dmabuf.offsets()) .zip(dmabuf.offsets())
.zip(dmabuf.strides()) .zip(dmabuf.strides())
.enumerate() .enumerate()
{ {
out.extend(&[ out.extend(&[
names[i][0] as i32, names[i][0] as i32,
*fd, fd,
names[i][1] as i32, names[i][1] as i32,
*offset as i32, offset as i32,
names[i][2] as i32, names[i][2] as i32,
*stride as i32, stride as i32,
]); ]);
if dmabuf.has_modifier() { if dmabuf.has_modifier() {
out.extend(&[ out.extend(&[
@ -510,7 +509,6 @@ impl EGLDisplay {
if image == ffi::egl::NO_IMAGE_KHR { if image == ffi::egl::NO_IMAGE_KHR {
Err(Error::EGLImageCreationFailed) Err(Error::EGLImageCreationFailed)
} else { } else {
// TODO check for external
Ok(image) Ok(image)
} }
} }

View File

@ -20,11 +20,11 @@ mod version;
use super::{Bind, Frame, Renderer, Texture, Transform, Unbind}; use super::{Bind, Frame, Renderer, Texture, Transform, Unbind};
use crate::backend::allocator::{ use crate::backend::allocator::{
dmabuf::{Dmabuf, WeakDmabuf}, dmabuf::{Dmabuf, WeakDmabuf},
Format, Buffer, Format,
}; };
use crate::backend::egl::{ use crate::backend::egl::{
ffi::egl::{self as ffi_egl, types::EGLImage}, ffi::egl::{self as ffi_egl, types::EGLImage},
EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError, EGLContext, EGLSurface, MakeCurrentError,
}; };
use crate::backend::SwapBuffersError; use crate::backend::SwapBuffersError;
@ -34,11 +34,11 @@ use crate::{
wayland::compositor::SurfaceAttributes, wayland::compositor::SurfaceAttributes,
}; };
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
use crate::backend::egl::display::EGLBufferReader; use crate::backend::egl::{display::EGLBufferReader, Format as EGLFormat};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_buffer, wl_shm}; use wayland_server::protocol::{wl_buffer, wl_shm};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use super::ImportShm; use super::{ImportShm, ImportDma};
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))] #[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
use super::ImportEgl; use super::ImportEgl;
@ -76,8 +76,6 @@ struct Gles2TextureInternal {
y_inverted: bool, y_inverted: bool,
width: u32, width: u32,
height: u32, height: u32,
#[cfg(feature = "wayland_frontend")]
buffer: Option<wl_buffer::WlBuffer>,
egl_images: Option<Vec<EGLImage>>, egl_images: Option<Vec<EGLImage>>,
destruction_callback_sender: Sender<CleanupResource>, destruction_callback_sender: Sender<CleanupResource>,
} }
@ -155,7 +153,7 @@ pub struct Gles2Renderer {
extensions: Vec<String>, extensions: Vec<String>,
programs: [Gles2Program; shaders::FRAGMENT_COUNT], programs: [Gles2Program; shaders::FRAGMENT_COUNT],
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
dmabuf_cache: HashMap<BufferEntry, Gles2Texture>, dmabuf_cache: HashMap<WeakDmabuf, Gles2Texture>,
egl: EGLContext, egl: EGLContext,
gl: ffi::Gles2, gl: ffi::Gles2,
destruction_callback: Receiver<CleanupResource>, destruction_callback: Receiver<CleanupResource>,
@ -483,7 +481,7 @@ impl Gles2Renderer {
self.make_current()?; self.make_current()?;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
self.dmabuf_cache self.dmabuf_cache
.retain(|entry, _tex| entry.buffer.as_ref().is_alive()); .retain(|entry, _tex| entry.upgrade().is_some());
for resource in self.destruction_callback.try_iter() { for resource in self.destruction_callback.try_iter() {
match resource { match resource {
CleanupResource::Texture(texture) => unsafe { CleanupResource::Texture(texture) => unsafe {
@ -550,7 +548,6 @@ impl ImportShm for Gles2Renderer {
y_inverted: false, y_inverted: false,
width: width as u32, width: width as u32,
height: height as u32, height: height as u32,
buffer: Some(buffer.clone()),
egl_images: None, egl_images: None,
destruction_callback_sender: self.destruction_callback_sender.clone(), destruction_callback_sender: self.destruction_callback_sender.clone(),
}); });
@ -657,7 +654,6 @@ impl ImportEgl for Gles2Renderer {
y_inverted: egl.y_inverted, y_inverted: egl.y_inverted,
width: egl.width, width: egl.width,
height: egl.height, height: egl.height,
buffer: Some(buffer.clone()),
egl_images: Some(egl.into_images()), egl_images: Some(egl.into_images()),
destruction_callback_sender: self.destruction_callback_sender.clone(), destruction_callback_sender: self.destruction_callback_sender.clone(),
})); }));
@ -666,16 +662,56 @@ impl ImportEgl for Gles2Renderer {
} }
} }
#[cfg(feature = "wayland_frontend")]
impl ImportDma for Gles2Renderer {
fn import_dmabuf(
&mut self,
buffer: &Dmabuf,
) -> Result<Gles2Texture, Gles2Error> {
if !self.extensions.iter().any(|ext| ext == "GL_OES_EGL_image") {
return Err(Gles2Error::GLExtensionNotSupported(&["GL_OES_EGL_image"]));
}
self.existing_dmabuf_texture(&buffer)?.map(Ok).unwrap_or_else(|| {
let is_external = !self.egl.dmabuf_render_formats().contains(&buffer.format());
self.make_current()?;
let image = self.egl.display.create_image_from_dmabuf(&buffer)
.map_err(Gles2Error::BindBufferEGLError)?;
let tex = self.import_egl_image(image, is_external, None)?;
let texture = Gles2Texture(Rc::new(Gles2TextureInternal {
texture: tex,
texture_kind: if is_external { 2 } else { 0 },
is_external,
y_inverted: buffer.y_inverted(),
width: buffer.width(),
height: buffer.height(),
egl_images: Some(vec![image]),
destruction_callback_sender: self.destruction_callback_sender.clone(),
}));
self.egl.unbind()?;
self.dmabuf_cache.insert(buffer.weak(), texture.clone());
Ok(texture)
})
}
#[cfg(feature = "wayland_frontend")]
fn dmabuf_formats<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Format> + 'a> {
Box::new(self.egl.dmabuf_texture_formats().iter())
}
}
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
impl Gles2Renderer { impl Gles2Renderer {
fn existing_dmabuf_texture( fn existing_dmabuf_texture(
&self, &self,
buffer: &wl_buffer::WlBuffer, buffer: &Dmabuf,
) -> Result<Option<Gles2Texture>, Gles2Error> { ) -> Result<Option<Gles2Texture>, Gles2Error> {
let existing_texture = self let existing_texture = self
.dmabuf_cache .dmabuf_cache
.iter() .iter()
.find(|(old_buffer, _)| &old_buffer.buffer == buffer) .find(|(weak, _)| weak.upgrade().map(|entry| &entry == buffer).unwrap_or(false))
.map(|(_, tex)| tex.clone()); .map(|(_, tex)| tex.clone());
if let Some(texture) = existing_texture { if let Some(texture) = existing_texture {
@ -928,7 +964,6 @@ impl Renderer for Gles2Renderer {
y_inverted: false, y_inverted: false,
width: image.width(), width: image.width(),
height: image.height(), height: image.height(),
buffer: None,
egl_images: None, egl_images: None,
destruction_callback_sender: self.destruction_callback_sender.clone(), destruction_callback_sender: self.destruction_callback_sender.clone(),
})); }));

View File

@ -18,6 +18,8 @@ use wayland_server::protocol::{wl_buffer, wl_shm};
#[cfg(feature = "renderer_gl")] #[cfg(feature = "renderer_gl")]
pub mod gles2; pub mod gles2;
#[cfg(feature = "wayland_frontend")]
use crate::backend::allocator::{dmabuf::Dmabuf, Format};
#[cfg(all(feature = "wayland_frontend", feature = "backend_egl", feature = "use_system_lib"))] #[cfg(all(feature = "wayland_frontend", feature = "backend_egl", feature = "use_system_lib"))]
use crate::backend::egl::display::EGLBufferReader; use crate::backend::egl::display::EGLBufferReader;
@ -289,6 +291,54 @@ pub trait ImportEgl: Renderer {
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error>; ) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error>;
} }
#[cfg(feature = "wayland_frontend")]
/// Trait for Renderers supporting importing dmabuf-based buffers.
pub trait ImportDma: Renderer {
/// Returns supported formats for dmabufs.
fn dmabuf_formats<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Format> + 'a> {
Box::new([].iter())
}
/// Import a given dmabuf-based buffer into the renderer (see [`buffer_type`]).
///
/// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`])
/// or implementation-specific functions.
///
/// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
///
/// This operation needs no bound or default rendering target.
///
/// The implementation defines, if the id keeps being valid, if the buffer is released,
/// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again.
fn import_dma_buffer(
&mut self,
buffer: &wl_buffer::WlBuffer,
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error> {
let dmabuf = buffer
.as_ref()
.user_data()
.get::<Dmabuf>()
.expect("import_dma_buffer without checking buffer type?");
self.import_dmabuf(dmabuf)
}
/// Import a given raw dmabuf into the renderer.
///
/// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`])
/// or implementation-specific functions.
///
/// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
///
/// This operation needs no bound or default rendering target.
///
/// The implementation defines, if the id keeps being valid, if the buffer is released,
/// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again.
fn import_dmabuf(
&mut self,
dmabuf: &Dmabuf,
) -> Result<<Self as Renderer>::TextureId, <Self as Renderer>::Error>;
}
// TODO: Replace this with a trait_alias, once that is stabilized. // TODO: Replace this with a trait_alias, once that is stabilized.
// pub type ImportAll = Renderer + ImportShm + ImportEgl; // pub type ImportAll = Renderer + ImportShm + ImportEgl;
@ -352,7 +402,14 @@ pub fn buffer_type(
buffer: &wl_buffer::WlBuffer, buffer: &wl_buffer::WlBuffer,
egl_buffer_reader: Option<&EGLBufferReader>, egl_buffer_reader: Option<&EGLBufferReader>,
) -> Option<BufferType> { ) -> Option<BufferType> {
if egl_buffer_reader if buffer
.as_ref()
.user_data()
.get::<Dmabuf>()
.is_some()
{
Some(BufferType::Dma)
} else if egl_buffer_reader
.as_ref() .as_ref()
.and_then(|x| x.egl_buffer_dimensions(&buffer)) .and_then(|x| x.egl_buffer_dimensions(&buffer))
.is_some() .is_some()
@ -371,9 +428,14 @@ pub fn buffer_type(
/// Returns `None` if the type is not recognized by smithay or otherwise not supported. /// Returns `None` if the type is not recognized by smithay or otherwise not supported.
#[cfg(all(feature = "wayland_frontend", not(all(feature = "backend_egl", feature = "use_system_lib"))))] #[cfg(all(feature = "wayland_frontend", not(all(feature = "backend_egl", feature = "use_system_lib"))))]
pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option<BufferType> { pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option<BufferType> {
use crate::backend::allocator::Buffer; if buffer
.as_ref()
if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() .user_data()
.get::<Dmabuf>()
.is_some()
{
Some(BufferType::Dma)
} else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok()
{ {
Some(BufferType::Shm) Some(BufferType::Shm)
} else { } else {
@ -389,7 +451,11 @@ pub fn buffer_dimensions(
buffer: &wl_buffer::WlBuffer, buffer: &wl_buffer::WlBuffer,
egl_buffer_reader: Option<&EGLBufferReader>, egl_buffer_reader: Option<&EGLBufferReader>,
) -> Option<(i32, i32)> { ) -> Option<(i32, i32)> {
if let Some((w, h)) = egl_buffer_reader use crate::backend::allocator::Buffer;
if let Some(buf) = buffer.as_ref().user_data().get::<Dmabuf>() {
Some((buf.width() as i32, buf.height() as i32))
} else if let Some((w, h)) = egl_buffer_reader
.as_ref() .as_ref()
.and_then(|x| x.egl_buffer_dimensions(&buffer)) .and_then(|x| x.egl_buffer_dimensions(&buffer))
{ {
@ -410,7 +476,9 @@ pub fn buffer_dimensions(
pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option<(i32, i32)> { pub fn buffer_dimensions(buffer: &wl_buffer::WlBuffer) -> Option<(i32, i32)> {
use crate::backend::allocator::Buffer; use crate::backend::allocator::Buffer;
if let Ok((w, h)) = if let Some(buf) = buffer.as_ref().user_data().get::<Dmabuf>() {
Some((buf.width() as i32, buf.height() as i32))
} else if let Ok((w, h)) =
crate::wayland::shm::with_buffer_contents(&buffer, |_, data| (data.width, data.height)) crate::wayland::shm::with_buffer_contents(&buffer, |_, data| (data.width, data.height))
{ {
Some((w, h)) Some((w, h))

View File

@ -16,7 +16,6 @@ use crate::backend::{
}; };
use std::{cell::RefCell, rc::Rc, time::Instant}; use std::{cell::RefCell, rc::Rc, time::Instant};
use wayland_egl as wegl; use wayland_egl as wegl;
use wayland_server::Display;
use winit::{ use winit::{
dpi::{LogicalPosition, LogicalSize, PhysicalSize}, dpi::{LogicalPosition, LogicalSize, PhysicalSize},
event::{ event::{
@ -29,6 +28,8 @@ use winit::{
window::{Window as WinitWindow, WindowBuilder}, window::{Window as WinitWindow, WindowBuilder},
}; };
#[cfg(feature = "use_system_lib")]
use wayland_server::Display;
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use crate::backend::egl::display::EGLBufferReader; use crate::backend::egl::display::EGLBufferReader;

View File

@ -4,52 +4,25 @@
//! contents as dmabuf file descriptors. These handlers automate the aggregation of the metadata associated //! 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. //! with a dma buffer, and do some basic checking of the sanity of what the client sends.
//! //!
//! This module is only available if the `backend_drm` cargo feature is enabled.
//!
//! ## How to use //! ## How to use
//! //!
//! To setup the dmabuf global, you will need to provide 2 things: //! To setup the dmabuf global, you will need to provide 2 things:
//! //!
//! - a list of the dmabuf formats you wish to support //! - a list of the dmabuf formats you wish to support
//! - an implementation of the `DmabufHandler` trait //! - a closure to test if a dmabuf buffer can be imported by your renderer
//! //!
//! The list of supported format is just a `Vec<Format>`, where you will enter all the (format, modifier) //! The list of supported format is just a `Vec<Format>`, where you will enter all the (code, modifier)
//! couples you support. //! couples you support. You can typically receive a list of supported formats for one renderer by calling
//! //! [`crate::backend::renderer::Renderer::dmabuf_formats`].
//! 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 client's submission as a `BufferInfo` struct,
//! and you need to validate it and maybe import it into your renderer. The `BufferData` associated type
//! allows you to store any metadata or 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 wayland_server;
//! # extern crate smithay; //! # extern crate smithay;
//! use smithay::wayland::dmabuf::{DmabufHandler, BufferInfo, init_dmabuf_global}; //! use smithay::{
//! //! backend::allocator::dmabuf::Dmabuf,
//! struct MyDmabufHandler; //! reexports::{wayland_server::protocol::wl_buffer::WlBuffer},
//! //! wayland::dmabuf::init_dmabuf_global,
//! 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 resources 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:
//! //!
//! # let mut display = wayland_server::Display::new(); //! # let mut display = wayland_server::Display::new();
//! // define your supported formats //! // define your supported formats
@ -59,12 +32,21 @@
//! let dmabuf_global = init_dmabuf_global( //! let dmabuf_global = init_dmabuf_global(
//! &mut display, //! &mut display,
//! formats, //! formats,
//! MyDmabufHandler, //! |buffer, _| {
//! /* validate the dmabuf and import it into your renderer state */
//! let dmabuf = buffer.as_ref().user_data().get::<Dmabuf>().expect("dmabuf global sets this for us");
//! true
//! },
//! None // we don't provide a logger in this example //! None // we don't provide a logger in this example
//! ); //! );
//! ``` //! ```
use std::{cell::RefCell, os::unix::io::RawFd, rc::Rc}; use std::{
cell::RefCell,
convert::TryFrom,
os::unix::io::{IntoRawFd, 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;
use wayland_protocols::unstable::linux_dmabuf::v1::server::{ use wayland_protocols::unstable::linux_dmabuf::v1::server::{
@ -73,124 +55,34 @@ use wayland_protocols::unstable::linux_dmabuf::v1::server::{
}, },
zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1,
}; };
use wayland_server::{protocol::wl_buffer, Display, Filter, Global, Main}; use wayland_server::{protocol::wl_buffer, DispatchData, Display, Filter, Global, Main};
use crate::backend::allocator::{Fourcc, Modifier}; use crate::backend::allocator::{
dmabuf::{Dmabuf, DmabufFlags, Plane},
/// Representation of a Dmabuf format, as advertized to the client Format, Fourcc, Modifier,
#[derive(Debug)] };
pub struct Format {
/// The format identifier.
pub format: Fourcc,
/// The supported dmabuf layout modifier.
///
/// This is an opaque token. Drivers use this token to express tiling, compression, etc. driver-specific
/// modifications to the base format defined by the DRM fourcc code.
pub modifier: Modifier,
/// Number of planes used by this format
pub plane_count: u32,
}
/// A plane send by the client
#[derive(Debug)]
pub struct Plane {
/// The file descriptor
pub fd: RawFd,
/// The plane index
pub plane_idx: u32,
/// Offset from the start of the Fd
pub offset: u32,
/// Stride for this plane
pub stride: u32,
/// Modifier for this plane
pub modifier: u64,
}
bitflags! {
/// Possible flags for a DMA buffer
pub struct BufferFlags: u32 {
/// The buffer content is Y-inverted
const Y_INVERT = 1;
/// The buffer content is interlaced
const INTERLACED = 2;
/// The buffer content if interlaced is bottom-field first
const BOTTOM_FIRST = 4;
}
}
/// The complete information provided by the client to create a dmabuf buffer
#[derive(Debug)]
pub struct BufferInfo {
/// The submitted planes
pub planes: Vec<Plane>,
/// The width of this buffer
pub width: i32,
/// The height of this buffer
pub height: i32,
/// The format in use
pub format: u32,
/// The flags applied to it
///
/// This is a bitflag, to be compared with the `Flags` enum reexported by this module.
pub flags: BufferFlags,
}
/// Handler trait for dmabuf validation /// Handler trait for dmabuf validation
/// ///
/// You need to provide an implementation of this trait that will validate the parameters provided by the /// You need to provide an implementation of this trait
/// client and import it as a dmabuf.
pub trait DmabufHandler {
/// The data of a successfully imported 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;
/// Validate a dmabuf
///
/// From the information provided by the client, you need to validate and/or import the buffer.
///
/// You can then store any information your compositor will need to handle it later, when the client has
/// submitted the buffer by returning `Ok(BufferData)` where `BufferData` is the associated type of this,
/// trait, a type of your choosing.
///
/// If the buffer could not be imported, whatever the reason, return `Err(())`.
fn validate_dmabuf(&mut self, info: BufferInfo) -> Result<Self::BufferData, ()>;
/// Create a buffer from validated buffer data.
///
/// This method is pre-implemented for you by storing the provided `BufferData` as the `user_data` of the
/// provided `WlBuffer`. By default it assumes that your `BufferData` is not threadsafe.
///
/// You can override it if you need your `BufferData` to be threadsafe, or which to register a destructor
/// for the `WlBuffer` for example.
fn create_buffer(
&mut self,
data: Self::BufferData,
buffer: Main<wl_buffer::WlBuffer>,
) -> wl_buffer::WlBuffer {
buffer.quick_assign(|_, _, _| {});
buffer.as_ref().user_data().set(|| data);
(*buffer).clone()
}
}
/// Initialize a dmabuf global. /// Initialize a dmabuf global.
/// ///
/// You need to provide a vector of the supported formats, as well as an implementation fo the `DmabufHandler` /// You need to provide a vector of the supported formats, as well as a closure,
/// trait, which will receive the buffer creation requests from the clients. /// that will validate the parameters provided by the client and tests the import as a dmabuf.
pub fn init_dmabuf_global<H, L>( pub fn init_dmabuf_global<F, L>(
display: &mut Display, display: &mut Display,
formats: Vec<Format>, formats: Vec<Format>,
handler: H, handler: F,
logger: L, logger: L,
) -> Global<zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1> ) -> Global<zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
H: DmabufHandler + 'static, F: for<'a> FnMut(&Dmabuf, DispatchData<'a>) -> bool + 'static,
{ {
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "dmabuf_handler")); let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "dmabuf_handler"));
let max_planes = formats.iter().map(|f| f.plane_count).max().unwrap_or(0);
let formats = Rc::<[Format]>::from(formats); let formats = Rc::<[Format]>::from(formats);
let handler = Rc::new(RefCell::new(handler)); let handler = Rc::new(RefCell::new(handler));
@ -211,13 +103,13 @@ where
if let zwp_linux_dmabuf_v1::Request::CreateParams { params_id } = req { if let zwp_linux_dmabuf_v1::Request::CreateParams { params_id } = req {
let mut handler = ParamsHandler { let mut handler = ParamsHandler {
pending_planes: Vec::new(), pending_planes: Vec::new(),
max_planes, max_planes: 4,
used: false, used: false,
formats: dma_formats.clone(), formats: dma_formats.clone(),
handler: dma_handler.clone(), handler: dma_handler.clone(),
log: dma_log.clone(), log: dma_log.clone(),
}; };
params_id.quick_assign(move |params, req, _| match req { params_id.quick_assign(move |params, req, ddata| match req {
ParamsRequest::Add { ParamsRequest::Add {
fd, fd,
plane_idx, plane_idx,
@ -238,14 +130,14 @@ where
height, height,
format, format,
flags, flags,
} => handler.create(&*params, width, height, format, flags), } => handler.create(&*params, width, height, format, flags, ddata),
ParamsRequest::CreateImmed { ParamsRequest::CreateImmed {
buffer_id, buffer_id,
width, width,
height, height,
format, format,
flags, flags,
} => handler.create_immed(&*params, buffer_id, width, height, format, flags), } => handler.create_immed(&*params, buffer_id, width, height, format, flags, ddata),
_ => {} _ => {}
}); });
} }
@ -253,10 +145,10 @@ where
// send the supported formats // send the supported formats
for f in &*formats { for f in &*formats {
dmabuf.format(f.format as u32); dmabuf.format(f.code as u32);
if version >= 3 { if version >= 3 {
dmabuf.modifier( dmabuf.modifier(
f.format as u32, f.code as u32,
(Into::<u64>::into(f.modifier) >> 32) as u32, (Into::<u64>::into(f.modifier) >> 32) as u32,
Into::<u64>::into(f.modifier) as u32, Into::<u64>::into(f.modifier) as u32,
); );
@ -267,7 +159,7 @@ where
) )
} }
struct ParamsHandler<H: DmabufHandler> { struct ParamsHandler<H: for<'a> FnMut(&Dmabuf, DispatchData<'a>) -> bool + 'static> {
pending_planes: Vec<Plane>, pending_planes: Vec<Plane>,
max_planes: u32, max_planes: u32,
used: bool, used: bool,
@ -276,7 +168,10 @@ struct ParamsHandler<H: DmabufHandler> {
log: ::slog::Logger, log: ::slog::Logger,
} }
impl<H: DmabufHandler> ParamsHandler<H> { impl<H> ParamsHandler<H>
where
H: for<'a> FnMut(&Dmabuf, DispatchData<'a>) -> bool + 'static
{
fn add( fn add(
&mut self, &mut self,
params: &BufferParams, params: &BufferParams,
@ -314,15 +209,15 @@ impl<H: DmabufHandler> ParamsHandler<H> {
} }
// all checks passed, store the plane // all checks passed, store the plane
self.pending_planes.push(Plane { self.pending_planes.push(Plane {
fd, fd: Some(fd),
plane_idx, plane_idx,
offset, offset,
stride, stride,
modifier, modifier: Modifier::from(modifier),
}); });
} }
fn create(&mut self, params: &BufferParams, width: i32, height: i32, format: u32, flags: u32) { fn create<'a>(&mut self, params: &BufferParams, width: i32, height: i32, format: u32, flags: u32, ddata: DispatchData<'a>) {
// Cannot reuse a params: // Cannot reuse a params:
if self.used { if self.used {
params.as_ref().post_error( params.as_ref().post_error(
@ -332,6 +227,18 @@ impl<H: DmabufHandler> ParamsHandler<H> {
return; return;
} }
self.used = true; self.used = true;
let format = match Fourcc::try_from(format) {
Ok(format) => format,
Err(_) => {
params.as_ref().post_error(
ParamError::InvalidFormat as u32,
format!("Format {:x} is not supported", format),
);
return;
}
};
if !buffer_basic_checks( if !buffer_basic_checks(
&self.formats, &self.formats,
&self.pending_planes, &self.pending_planes,
@ -343,23 +250,46 @@ impl<H: DmabufHandler> ParamsHandler<H> {
trace!(self.log, "Killing client providing bogus dmabuf buffer params."); trace!(self.log, "Killing client providing bogus dmabuf buffer params.");
return; return;
} }
let info = BufferInfo {
planes: ::std::mem::replace(&mut self.pending_planes, Vec::new()), let mut buf = Dmabuf::new(
width, width as u32,
height, height as u32,
format, format,
flags: BufferFlags::from_bits_truncate(flags), DmabufFlags::from_bits_truncate(flags),
);
let planes = ::std::mem::replace(&mut self.pending_planes, Vec::new());
for (i, plane) in planes.into_iter().enumerate() {
let offset = plane.offset;
let stride = plane.stride;
let modi = plane.modifier;
buf.add_plane(plane.into_raw_fd(), i as u32, offset, stride, modi);
}
let dmabuf = match buf.build() {
Some(buf) => buf,
None => {
params.as_ref().post_error(
ParamError::Incomplete as u32,
format!("Provided buffer is incomplete, it has zero planes"),
);
return;
}
}; };
let mut handler = self.handler.borrow_mut(); let mut handler = self.handler.borrow_mut();
if let Ok(data) = handler.validate_dmabuf(info) { if handler(&dmabuf, ddata) {
if let Some(buffer) = params if let Some(buffer) = params
.as_ref() .as_ref()
.client() .client()
.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); buffer.as_ref().user_data().set_threadsafe(|| dmabuf);
trace!(self.log, "Creating a new validated dma wl_buffer."); buffer.quick_assign(|_, _, _| {});
params.created(&buffer);
trace!(self.log, "Created a new validated dma wl_buffer.");
params.created(&buffer);
} else {
trace!(self.log, "Failed to create a wl_buffer");
params.failed();
} }
} else { } else {
trace!(self.log, "Refusing creation of an invalid dma wl_buffer."); trace!(self.log, "Refusing creation of an invalid dma wl_buffer.");
@ -367,14 +297,15 @@ impl<H: DmabufHandler> ParamsHandler<H> {
} }
} }
fn create_immed( fn create_immed<'a>(
&mut self, &mut self,
params: &BufferParams, params: &BufferParams,
buffer_id: Main<wl_buffer::WlBuffer>, buffer: Main<wl_buffer::WlBuffer>,
width: i32, width: i32,
height: i32, height: i32,
format: u32, format: u32,
flags: u32, flags: u32,
ddata: DispatchData<'a>,
) { ) {
// Cannot reuse a params: // Cannot reuse a params:
if self.used { if self.used {
@ -385,6 +316,18 @@ impl<H: DmabufHandler> ParamsHandler<H> {
return; return;
} }
self.used = true; self.used = true;
let format = match Fourcc::try_from(format) {
Ok(format) => format,
Err(_) => {
params.as_ref().post_error(
ParamError::InvalidFormat as u32,
format!("Format {:x} is not supported", format),
);
return;
}
};
if !buffer_basic_checks( if !buffer_basic_checks(
&self.formats, &self.formats,
&self.pending_planes, &self.pending_planes,
@ -396,17 +339,36 @@ impl<H: DmabufHandler> ParamsHandler<H> {
trace!(self.log, "Killing client providing bogus dmabuf buffer params."); trace!(self.log, "Killing client providing bogus dmabuf buffer params.");
return; return;
} }
let info = BufferInfo {
planes: ::std::mem::replace(&mut self.pending_planes, Vec::new()), let mut buf = Dmabuf::new(
width, width as u32,
height, height as u32,
format, format,
flags: BufferFlags::from_bits_truncate(flags), DmabufFlags::from_bits_truncate(flags),
);
let planes = ::std::mem::replace(&mut self.pending_planes, Vec::new());
for (i, plane) in planes.into_iter().enumerate() {
let offset = plane.offset;
let stride = plane.stride;
let modi = plane.modifier;
buf.add_plane(plane.into_raw_fd(), i as u32, offset, stride, modi);
}
let dmabuf = match buf.build() {
Some(buf) => buf,
None => {
params.as_ref().post_error(
ParamError::Incomplete as u32,
format!("Provided buffer is incomplete, it has zero planes"),
);
return;
}
}; };
let mut handler = self.handler.borrow_mut(); let mut handler = self.handler.borrow_mut();
if let Ok(data) = handler.validate_dmabuf(info) { if handler(&dmabuf, ddata) {
trace!(self.log, "Creating a new validated immediate dma wl_buffer."); buffer.as_ref().user_data().set_threadsafe(|| dmabuf);
handler.create_buffer(data, buffer_id); buffer.quick_assign(|_, _, _| {});
trace!(self.log, "Created a new validated dma wl_buffer.");
} else { } else {
trace!( trace!(
self.log, self.log,
@ -417,6 +379,8 @@ impl<H: DmabufHandler> ParamsHandler<H> {
"create_immed resulted in an invalid buffer.".into(), "create_immed resulted in an invalid buffer.".into(),
); );
} }
} }
} }
@ -424,34 +388,22 @@ fn buffer_basic_checks(
formats: &[Format], formats: &[Format],
pending_planes: &[Plane], pending_planes: &[Plane],
params: &BufferParams, params: &BufferParams,
format: u32, format: Fourcc,
width: i32, width: i32,
height: i32, height: i32,
) -> bool { ) -> bool {
// protocol_checks: // protocol_checks:
// This must be a known format // This must be a known format
let format = match formats.iter().find(|f| f.format as u32 == format) { let _format = match formats.iter().find(|f| f.code == format) {
Some(f) => f, Some(f) => f,
None => { None => {
params.as_ref().post_error( params.as_ref().post_error(
ParamError::InvalidFormat as u32, ParamError::InvalidFormat as u32,
format!("Format {:x} is not supported.", format), format!("Format {:?}/{:x} is not supported.", format, format as u32),
); );
return false; return false;
} }
}; };
// The number of planes set must match what the format expects
let max_plane_set = pending_planes.iter().map(|d| d.plane_idx + 1).max().unwrap_or(0);
if max_plane_set != format.plane_count || pending_planes.len() < format.plane_count as usize {
params.as_ref().post_error(
ParamError::Incomplete as u32,
format!(
"Format {:?} requires {} planes but got {}.",
format.format, format.plane_count, max_plane_set
),
);
return false;
}
// Width and height must be positivie // Width and height must be positivie
if width < 1 || height < 1 { if width < 1 || height < 1 {
params.as_ref().post_error( params.as_ref().post_error(
@ -477,9 +429,9 @@ fn buffer_basic_checks(
} }
Some(e) => e, Some(e) => e,
}; };
if let Ok(size) = ::nix::unistd::lseek(plane.fd, 0, ::nix::unistd::Whence::SeekEnd) { if let Ok(size) = ::nix::unistd::lseek(plane.fd.unwrap(), 0, ::nix::unistd::Whence::SeekEnd) {
// reset the seek point // reset the seek point
let _ = ::nix::unistd::lseek(plane.fd, 0, ::nix::unistd::Whence::SeekSet); let _ = ::nix::unistd::lseek(plane.fd.unwrap(), 0, ::nix::unistd::Whence::SeekSet);
if plane.offset as i64 > size { if plane.offset as i64 > size {
params.as_ref().post_error( params.as_ref().post_error(
ParamError::OutOfBounds as u32, ParamError::OutOfBounds as u32,

View File

@ -16,7 +16,6 @@ use std::sync::atomic::{AtomicUsize, Ordering};
pub mod compositor; pub mod compositor;
pub mod data_device; pub mod data_device;
#[cfg(feature = "backend_drm")]
pub mod dmabuf; pub mod dmabuf;
pub mod explicit_synchronization; pub mod explicit_synchronization;
pub mod output; pub mod output;