dmabuf: Unify types of `wayland::dmabuf` and `allocator::dmabuf`
This commit is contained in:
parent
b6822becf6
commit
a38592bc92
|
@ -10,21 +10,67 @@
|
|||
//! 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.
|
||||
|
||||
use super::{Buffer, Format, Modifier};
|
||||
use std::os::unix::io::RawFd;
|
||||
use super::{Buffer, Format, Fourcc, Modifier};
|
||||
use std::os::unix::io::{IntoRawFd, RawFd};
|
||||
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)]
|
||||
pub(crate) struct DmabufInternal {
|
||||
pub num_planes: usize,
|
||||
pub offsets: [u32; MAX_PLANES],
|
||||
pub strides: [u32; MAX_PLANES],
|
||||
pub fds: [RawFd; MAX_PLANES],
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub format: Format,
|
||||
/// 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: 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)]
|
||||
|
@ -42,109 +88,138 @@ impl PartialEq 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 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if let Some(dmabuf) = self.upgrade() {
|
||||
return &dmabuf == other;
|
||||
}
|
||||
false
|
||||
Weak::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
fn width(&self) -> u32 {
|
||||
self.0.width
|
||||
self.0.width as u32
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.0.height
|
||||
self.0.height as u32
|
||||
}
|
||||
|
||||
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 {
|
||||
/// 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.
|
||||
// The contents are determined by the provided file descriptors, which
|
||||
// do not need to refer to the same buffer `src` does.
|
||||
pub(crate) fn new(
|
||||
src: &impl Buffer,
|
||||
planes: usize,
|
||||
offsets: &[u32],
|
||||
strides: &[u32],
|
||||
fds: &[RawFd],
|
||||
) -> Option<Dmabuf> {
|
||||
if offsets.len() < planes
|
||||
|| strides.len() < planes
|
||||
|| fds.len() < planes
|
||||
|| planes == 0
|
||||
|| planes > MAX_PLANES
|
||||
{
|
||||
return None;
|
||||
pub fn new_from_buffer(src: &impl Buffer, flags: DmabufFlags) -> DmabufBuilder {
|
||||
DmabufBuilder {
|
||||
internal: DmabufInternal {
|
||||
planes: Vec::with_capacity(MAX_PLANES),
|
||||
width: src.width() as i32,
|
||||
height: src.height() as i32,
|
||||
format: src.format().code,
|
||||
flags,
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
pub fn handles(&self) -> &[RawFd] {
|
||||
self.0.fds.split_at(self.0.num_planes).0
|
||||
/// Create a new Dmabuf
|
||||
pub fn new(width: u32, height: u32, format: Fourcc, flags: DmabufFlags) -> DmabufBuilder {
|
||||
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
|
||||
pub fn offsets(&self) -> &[u32] {
|
||||
self.0.offsets.split_at(self.0.num_planes).0
|
||||
/// The amount of planes this Dmabuf has
|
||||
pub fn num_planes(&self) -> usize {
|
||||
self.0.planes.len()
|
||||
}
|
||||
|
||||
/// Return strides for the planes of this buffer
|
||||
pub fn strides(&self) -> &[u32] {
|
||||
self.0.strides.split_at(self.0.num_planes).0
|
||||
/// Returns raw handles of the planes of this buffer
|
||||
pub fn handles<'a>(&'a self) -> impl Iterator<Item = RawFd> + 'a {
|
||||
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 {
|
||||
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
|
||||
|
@ -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
|
||||
pub trait AsDmabuf {
|
||||
/// Error type returned, if exporting fails
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! conversions to and from [dmabufs](super::dmabuf).
|
||||
|
||||
use super::{
|
||||
dmabuf::{AsDmabuf, Dmabuf},
|
||||
dmabuf::{AsDmabuf, Dmabuf, DmabufFlags, MAX_PLANES},
|
||||
Allocator, Buffer, Format, Fourcc, Modifier,
|
||||
};
|
||||
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
|
||||
}
|
||||
|
||||
let fds = [self.fd()?, 0, 0, 0];
|
||||
//if fds.iter().any(|fd| fd == 0) {
|
||||
if fds[0] < 0 {
|
||||
if self.fd()? == 0 {
|
||||
return Err(GbmConvertError::InvalidFD);
|
||||
}
|
||||
|
||||
let offsets = (0i32..planes)
|
||||
.map(|i| self.offset(i))
|
||||
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
||||
let strides = (0i32..planes)
|
||||
.map(|i| self.stride_for_plane(i))
|
||||
.collect::<Result<Vec<u32>, gbm::DeviceDestroyedError>>()?;
|
||||
|
||||
Ok(Dmabuf::new(self, planes as usize, &offsets, &strides, &fds).unwrap())
|
||||
let mut builder = Dmabuf::new_from_buffer(self, DmabufFlags::empty());
|
||||
for idx in 0..planes {
|
||||
builder.add_plane(
|
||||
self.fd()?,
|
||||
idx as u32,
|
||||
self.offset(idx)?,
|
||||
self.stride_for_plane(idx)?,
|
||||
self.modifier()?,
|
||||
);
|
||||
}
|
||||
Ok(builder.build().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,27 +120,39 @@ impl Dmabuf {
|
|||
gbm: &GbmDevice<A>,
|
||||
usage: GbmBufferFlags,
|
||||
) -> std::io::Result<GbmBuffer<T>> {
|
||||
let buf = &*self.0;
|
||||
if self.has_modifier() || buf.num_planes > 1 || buf.offsets[0] != 0 {
|
||||
let mut handles = [0; MAX_PLANES];
|
||||
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(
|
||||
buf.num_planes as u32,
|
||||
buf.fds,
|
||||
buf.width,
|
||||
buf.height,
|
||||
buf.format.code,
|
||||
self.num_planes() as u32,
|
||||
handles,
|
||||
self.width(),
|
||||
self.height(),
|
||||
self.format().code,
|
||||
usage,
|
||||
unsafe { std::mem::transmute::<[u32; 4], [i32; 4]>(buf.strides) },
|
||||
unsafe { std::mem::transmute::<[u32; 4], [i32; 4]>(buf.offsets) },
|
||||
buf.format.modifier,
|
||||
strides,
|
||||
offsets,
|
||||
self.format().modifier,
|
||||
)
|
||||
} else {
|
||||
gbm.import_buffer_object_from_dma_buf(
|
||||
buf.fds[0],
|
||||
buf.width,
|
||||
buf.height,
|
||||
buf.strides[0],
|
||||
buf.format.code,
|
||||
if buf.format.modifier == Modifier::Linear {
|
||||
handles[0],
|
||||
self.width(),
|
||||
self.height(),
|
||||
strides[0] as u32,
|
||||
self.format().code,
|
||||
if self.format().modifier == Modifier::Linear {
|
||||
usage | GbmBufferFlags::LINEAR
|
||||
} else {
|
||||
usage
|
||||
|
|
|
@ -19,10 +19,10 @@ use crate::backend::egl::{
|
|||
ffi,
|
||||
ffi::egl::types::EGLImage,
|
||||
native::EGLNativeDisplay,
|
||||
wrap_egl_call, EGLError, Error, Format,
|
||||
wrap_egl_call, EGLError, Error,
|
||||
};
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
use crate::backend::egl::{BufferAccessError, EGLBuffer};
|
||||
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
|
||||
use crate::backend::egl::{BufferAccessError, EGLBuffer, Format};
|
||||
|
||||
/// Wrapper around [`ffi::EGLDisplay`](ffi::egl::types::EGLDisplay) to ensure display is only destroyed
|
||||
/// once all resources bound to it have been dropped.
|
||||
|
@ -473,18 +473,17 @@ impl EGLDisplay {
|
|||
|
||||
for (i, ((fd, offset), stride)) in dmabuf
|
||||
.handles()
|
||||
.iter()
|
||||
.zip(dmabuf.offsets())
|
||||
.zip(dmabuf.strides())
|
||||
.enumerate()
|
||||
{
|
||||
out.extend(&[
|
||||
names[i][0] as i32,
|
||||
*fd,
|
||||
fd,
|
||||
names[i][1] as i32,
|
||||
*offset as i32,
|
||||
offset as i32,
|
||||
names[i][2] as i32,
|
||||
*stride as i32,
|
||||
stride as i32,
|
||||
]);
|
||||
if dmabuf.has_modifier() {
|
||||
out.extend(&[
|
||||
|
@ -510,7 +509,6 @@ impl EGLDisplay {
|
|||
if image == ffi::egl::NO_IMAGE_KHR {
|
||||
Err(Error::EGLImageCreationFailed)
|
||||
} else {
|
||||
// TODO check for external
|
||||
Ok(image)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ mod version;
|
|||
use super::{Bind, Frame, Renderer, Texture, Transform, Unbind};
|
||||
use crate::backend::allocator::{
|
||||
dmabuf::{Dmabuf, WeakDmabuf},
|
||||
Format,
|
||||
Buffer, Format,
|
||||
};
|
||||
use crate::backend::egl::{
|
||||
ffi::egl::{self as ffi_egl, types::EGLImage},
|
||||
EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
|
||||
EGLContext, EGLSurface, MakeCurrentError,
|
||||
};
|
||||
use crate::backend::SwapBuffersError;
|
||||
|
||||
|
@ -34,11 +34,11 @@ use crate::{
|
|||
wayland::compositor::SurfaceAttributes,
|
||||
};
|
||||
#[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")]
|
||||
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
use super::ImportShm;
|
||||
use super::{ImportShm, ImportDma};
|
||||
#[cfg(all(feature = "wayland_frontend", feature = "use_system_lib"))]
|
||||
use super::ImportEgl;
|
||||
|
||||
|
@ -76,8 +76,6 @@ struct Gles2TextureInternal {
|
|||
y_inverted: bool,
|
||||
width: u32,
|
||||
height: u32,
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
buffer: Option<wl_buffer::WlBuffer>,
|
||||
egl_images: Option<Vec<EGLImage>>,
|
||||
destruction_callback_sender: Sender<CleanupResource>,
|
||||
}
|
||||
|
@ -155,7 +153,7 @@ pub struct Gles2Renderer {
|
|||
extensions: Vec<String>,
|
||||
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
dmabuf_cache: HashMap<BufferEntry, Gles2Texture>,
|
||||
dmabuf_cache: HashMap<WeakDmabuf, Gles2Texture>,
|
||||
egl: EGLContext,
|
||||
gl: ffi::Gles2,
|
||||
destruction_callback: Receiver<CleanupResource>,
|
||||
|
@ -483,7 +481,7 @@ impl Gles2Renderer {
|
|||
self.make_current()?;
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
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() {
|
||||
match resource {
|
||||
CleanupResource::Texture(texture) => unsafe {
|
||||
|
@ -550,7 +548,6 @@ impl ImportShm for Gles2Renderer {
|
|||
y_inverted: false,
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
buffer: Some(buffer.clone()),
|
||||
egl_images: None,
|
||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||
});
|
||||
|
@ -657,7 +654,6 @@ impl ImportEgl for Gles2Renderer {
|
|||
y_inverted: egl.y_inverted,
|
||||
width: egl.width,
|
||||
height: egl.height,
|
||||
buffer: Some(buffer.clone()),
|
||||
egl_images: Some(egl.into_images()),
|
||||
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")]
|
||||
impl Gles2Renderer {
|
||||
fn existing_dmabuf_texture(
|
||||
&self,
|
||||
buffer: &wl_buffer::WlBuffer,
|
||||
buffer: &Dmabuf,
|
||||
) -> Result<Option<Gles2Texture>, Gles2Error> {
|
||||
let existing_texture = self
|
||||
.dmabuf_cache
|
||||
.iter()
|
||||
.find(|(old_buffer, _)| &old_buffer.buffer == buffer)
|
||||
.find(|(weak, _)| weak.upgrade().map(|entry| &entry == buffer).unwrap_or(false))
|
||||
.map(|(_, tex)| tex.clone());
|
||||
|
||||
if let Some(texture) = existing_texture {
|
||||
|
@ -928,7 +964,6 @@ impl Renderer for Gles2Renderer {
|
|||
y_inverted: false,
|
||||
width: image.width(),
|
||||
height: image.height(),
|
||||
buffer: None,
|
||||
egl_images: None,
|
||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||
}));
|
||||
|
|
|
@ -18,6 +18,8 @@ use wayland_server::protocol::{wl_buffer, wl_shm};
|
|||
|
||||
#[cfg(feature = "renderer_gl")]
|
||||
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"))]
|
||||
use crate::backend::egl::display::EGLBufferReader;
|
||||
|
||||
|
@ -289,6 +291,54 @@ pub trait ImportEgl: Renderer {
|
|||
) -> 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.
|
||||
// pub type ImportAll = Renderer + ImportShm + ImportEgl;
|
||||
|
||||
|
@ -352,7 +402,14 @@ pub fn buffer_type(
|
|||
buffer: &wl_buffer::WlBuffer,
|
||||
egl_buffer_reader: Option<&EGLBufferReader>,
|
||||
) -> 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()
|
||||
.and_then(|x| x.egl_buffer_dimensions(&buffer))
|
||||
.is_some()
|
||||
|
@ -371,9 +428,14 @@ pub fn buffer_type(
|
|||
/// 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"))))]
|
||||
pub fn buffer_type(buffer: &wl_buffer::WlBuffer) -> Option<BufferType> {
|
||||
use crate::backend::allocator::Buffer;
|
||||
|
||||
if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok()
|
||||
if buffer
|
||||
.as_ref()
|
||||
.user_data()
|
||||
.get::<Dmabuf>()
|
||||
.is_some()
|
||||
{
|
||||
Some(BufferType::Dma)
|
||||
} else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok()
|
||||
{
|
||||
Some(BufferType::Shm)
|
||||
} else {
|
||||
|
@ -389,7 +451,11 @@ pub fn buffer_dimensions(
|
|||
buffer: &wl_buffer::WlBuffer,
|
||||
egl_buffer_reader: Option<&EGLBufferReader>,
|
||||
) -> 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()
|
||||
.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)> {
|
||||
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))
|
||||
{
|
||||
Some((w, h))
|
||||
|
|
|
@ -16,7 +16,6 @@ use crate::backend::{
|
|||
};
|
||||
use std::{cell::RefCell, rc::Rc, time::Instant};
|
||||
use wayland_egl as wegl;
|
||||
use wayland_server::Display;
|
||||
use winit::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
|
||||
event::{
|
||||
|
@ -29,6 +28,8 @@ use winit::{
|
|||
window::{Window as WinitWindow, WindowBuilder},
|
||||
};
|
||||
|
||||
#[cfg(feature = "use_system_lib")]
|
||||
use wayland_server::Display;
|
||||
#[cfg(feature = "use_system_lib")]
|
||||
use crate::backend::egl::display::EGLBufferReader;
|
||||
|
||||
|
|
|
@ -4,52 +4,25 @@
|
|||
//! 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.
|
||||
//!
|
||||
//! This module is only available if the `backend_drm` cargo feature is enabled.
|
||||
//!
|
||||
//! ## 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
|
||||
//! - 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)
|
||||
//! 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 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.
|
||||
//! The list of supported format is just a `Vec<Format>`, where you will enter all the (code, modifier)
|
||||
//! couples you support. You can typically receive a list of supported formats for one renderer by calling
|
||||
//! [`crate::backend::renderer::Renderer::dmabuf_formats`].
|
||||
//!
|
||||
//! ```
|
||||
//! # 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 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:
|
||||
//! use smithay::{
|
||||
//! backend::allocator::dmabuf::Dmabuf,
|
||||
//! reexports::{wayland_server::protocol::wl_buffer::WlBuffer},
|
||||
//! wayland::dmabuf::init_dmabuf_global,
|
||||
//! };
|
||||
//!
|
||||
//! # let mut display = wayland_server::Display::new();
|
||||
//! // define your supported formats
|
||||
|
@ -59,12 +32,21 @@
|
|||
//! let dmabuf_global = init_dmabuf_global(
|
||||
//! &mut display,
|
||||
//! 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
|
||||
//! );
|
||||
//! ```
|
||||
|
||||
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;
|
||||
use wayland_protocols::unstable::linux_dmabuf::v1::server::{
|
||||
|
@ -73,124 +55,34 @@ use wayland_protocols::unstable::linux_dmabuf::v1::server::{
|
|||
},
|
||||
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};
|
||||
|
||||
/// Representation of a Dmabuf format, as advertized to the client
|
||||
#[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,
|
||||
}
|
||||
use crate::backend::allocator::{
|
||||
dmabuf::{Dmabuf, DmabufFlags, Plane},
|
||||
Format, Fourcc, Modifier,
|
||||
};
|
||||
|
||||
/// Handler trait for dmabuf validation
|
||||
///
|
||||
/// You need to provide an implementation of this trait that will validate the parameters provided by the
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
/// You need to provide an implementation of this trait
|
||||
|
||||
|
||||
/// Initialize a dmabuf global.
|
||||
///
|
||||
/// You need to provide a vector of the supported formats, as well as an implementation fo the `DmabufHandler`
|
||||
/// trait, which will receive the buffer creation requests from the clients.
|
||||
pub fn init_dmabuf_global<H, L>(
|
||||
/// You need to provide a vector of the supported formats, as well as a closure,
|
||||
/// that will validate the parameters provided by the client and tests the import as a dmabuf.
|
||||
pub fn init_dmabuf_global<F, L>(
|
||||
display: &mut Display,
|
||||
formats: Vec<Format>,
|
||||
handler: H,
|
||||
handler: F,
|
||||
logger: L,
|
||||
) -> Global<zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1>
|
||||
where
|
||||
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 max_planes = formats.iter().map(|f| f.plane_count).max().unwrap_or(0);
|
||||
let formats = Rc::<[Format]>::from(formats);
|
||||
let handler = Rc::new(RefCell::new(handler));
|
||||
|
||||
|
@ -211,13 +103,13 @@ where
|
|||
if let zwp_linux_dmabuf_v1::Request::CreateParams { params_id } = req {
|
||||
let mut handler = ParamsHandler {
|
||||
pending_planes: Vec::new(),
|
||||
max_planes,
|
||||
max_planes: 4,
|
||||
used: false,
|
||||
formats: dma_formats.clone(),
|
||||
handler: dma_handler.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 {
|
||||
fd,
|
||||
plane_idx,
|
||||
|
@ -238,14 +130,14 @@ where
|
|||
height,
|
||||
format,
|
||||
flags,
|
||||
} => handler.create(&*params, width, height, format, flags),
|
||||
} => handler.create(&*params, width, height, format, flags, ddata),
|
||||
ParamsRequest::CreateImmed {
|
||||
buffer_id,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
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
|
||||
for f in &*formats {
|
||||
dmabuf.format(f.format as u32);
|
||||
dmabuf.format(f.code as u32);
|
||||
if version >= 3 {
|
||||
dmabuf.modifier(
|
||||
f.format as u32,
|
||||
f.code as u32,
|
||||
(Into::<u64>::into(f.modifier) >> 32) 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>,
|
||||
max_planes: u32,
|
||||
used: bool,
|
||||
|
@ -276,7 +168,10 @@ struct ParamsHandler<H: DmabufHandler> {
|
|||
log: ::slog::Logger,
|
||||
}
|
||||
|
||||
impl<H: DmabufHandler> ParamsHandler<H> {
|
||||
impl<H> ParamsHandler<H>
|
||||
where
|
||||
H: for<'a> FnMut(&Dmabuf, DispatchData<'a>) -> bool + 'static
|
||||
{
|
||||
fn add(
|
||||
&mut self,
|
||||
params: &BufferParams,
|
||||
|
@ -314,15 +209,15 @@ impl<H: DmabufHandler> ParamsHandler<H> {
|
|||
}
|
||||
// all checks passed, store the plane
|
||||
self.pending_planes.push(Plane {
|
||||
fd,
|
||||
fd: Some(fd),
|
||||
plane_idx,
|
||||
offset,
|
||||
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:
|
||||
if self.used {
|
||||
params.as_ref().post_error(
|
||||
|
@ -332,6 +227,18 @@ impl<H: DmabufHandler> ParamsHandler<H> {
|
|||
return;
|
||||
}
|
||||
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(
|
||||
&self.formats,
|
||||
&self.pending_planes,
|
||||
|
@ -343,23 +250,46 @@ impl<H: DmabufHandler> ParamsHandler<H> {
|
|||
trace!(self.log, "Killing client providing bogus dmabuf buffer params.");
|
||||
return;
|
||||
}
|
||||
let info = BufferInfo {
|
||||
planes: ::std::mem::replace(&mut self.pending_planes, Vec::new()),
|
||||
width,
|
||||
height,
|
||||
|
||||
let mut buf = Dmabuf::new(
|
||||
width as u32,
|
||||
height as u32,
|
||||
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();
|
||||
if let Ok(data) = handler.validate_dmabuf(info) {
|
||||
if handler(&dmabuf, ddata) {
|
||||
if let Some(buffer) = params
|
||||
.as_ref()
|
||||
.client()
|
||||
.and_then(|c| c.create_resource::<wl_buffer::WlBuffer>(1))
|
||||
{
|
||||
let buffer = handler.create_buffer(data, buffer);
|
||||
trace!(self.log, "Creating a new validated dma wl_buffer.");
|
||||
buffer.as_ref().user_data().set_threadsafe(|| dmabuf);
|
||||
buffer.quick_assign(|_, _, _| {});
|
||||
|
||||
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 {
|
||||
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,
|
||||
params: &BufferParams,
|
||||
buffer_id: Main<wl_buffer::WlBuffer>,
|
||||
buffer: Main<wl_buffer::WlBuffer>,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: u32,
|
||||
flags: u32,
|
||||
ddata: DispatchData<'a>,
|
||||
) {
|
||||
// Cannot reuse a params:
|
||||
if self.used {
|
||||
|
@ -385,6 +316,18 @@ impl<H: DmabufHandler> ParamsHandler<H> {
|
|||
return;
|
||||
}
|
||||
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(
|
||||
&self.formats,
|
||||
&self.pending_planes,
|
||||
|
@ -396,17 +339,36 @@ impl<H: DmabufHandler> ParamsHandler<H> {
|
|||
trace!(self.log, "Killing client providing bogus dmabuf buffer params.");
|
||||
return;
|
||||
}
|
||||
let info = BufferInfo {
|
||||
planes: ::std::mem::replace(&mut self.pending_planes, Vec::new()),
|
||||
width,
|
||||
height,
|
||||
|
||||
let mut buf = Dmabuf::new(
|
||||
width as u32,
|
||||
height as u32,
|
||||
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();
|
||||
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);
|
||||
if handler(&dmabuf, ddata) {
|
||||
buffer.as_ref().user_data().set_threadsafe(|| dmabuf);
|
||||
buffer.quick_assign(|_, _, _| {});
|
||||
trace!(self.log, "Created a new validated dma wl_buffer.");
|
||||
} else {
|
||||
trace!(
|
||||
self.log,
|
||||
|
@ -417,6 +379,8 @@ impl<H: DmabufHandler> ParamsHandler<H> {
|
|||
"create_immed resulted in an invalid buffer.".into(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,34 +388,22 @@ fn buffer_basic_checks(
|
|||
formats: &[Format],
|
||||
pending_planes: &[Plane],
|
||||
params: &BufferParams,
|
||||
format: u32,
|
||||
format: Fourcc,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> bool {
|
||||
// protocol_checks:
|
||||
// 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,
|
||||
None => {
|
||||
params.as_ref().post_error(
|
||||
ParamError::InvalidFormat as u32,
|
||||
format!("Format {:x} is not supported.", format),
|
||||
format!("Format {:?}/{:x} is not supported.", format, format as u32),
|
||||
);
|
||||
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
|
||||
if width < 1 || height < 1 {
|
||||
params.as_ref().post_error(
|
||||
|
@ -477,9 +429,9 @@ fn buffer_basic_checks(
|
|||
}
|
||||
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
|
||||
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 {
|
||||
params.as_ref().post_error(
|
||||
ParamError::OutOfBounds as u32,
|
||||
|
|
|
@ -16,7 +16,6 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||
|
||||
pub mod compositor;
|
||||
pub mod data_device;
|
||||
#[cfg(feature = "backend_drm")]
|
||||
pub mod dmabuf;
|
||||
pub mod explicit_synchronization;
|
||||
pub mod output;
|
||||
|
|
Loading…
Reference in New Issue