• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Abstracts the different kinds of backing memory (`MMAP`, `USERPTR`,
2 //! `DMABUF`) supported by V4L2.
3 //!
4 //! V4L2 allows to use either memory that is provided by the device itself
5 //! (MMAP) or memory imported via user allocation (USERPTR) or the dma-buf
6 //! subsystem (DMABUF). This results in 2 very different behaviors and 3 memory
7 //! types that we need to model.
8 //!
9 //! The `Memory` trait represents these memory types and is thus implemented
10 //! by exacly 3 types: `MMAP`, `UserPtr`, and `DMABuf`. These types do very
11 //! little apart from providing a constant with the corresponding V4L2 memory
12 //! type they model, and implement the `SelfBacked` (for MMAP) or `Imported`
13 //! (for `UserPtr` and `DMABuf`) traits to indicate where their memory comes
14 //! from.
15 //!
16 //! The `PlaneHandle` trait is used by types which can bind to one of these
17 //! memory types, i.e. a type that can represent a single memory plane of a
18 //! buffer. For `MMAP` memory this is a void type (since `MMAP` provides its
19 //! own memory). `UserPtr`, a `Vec<u8>` can adequately be used as backing
20 //! memory, and for `DMABuf` we will use a file descriptor. For handles that
21 //! can be mapped into the user address-space (and indeed for `MMAP` this is
22 //! the only way to access the memory), the `Mappable` trait can be implemented.
23 //!
24 //! The set of handles that make all the planes for a given buffer is
25 //! represented by the `BufferHandles` trait. This trait is more abstract since
26 //! we may want to decide at runtime the kind of memory we want to use ;
27 //! therefore this trait does not have any particular kind of memory attached to
28 //! it. `PrimitiveBufferHandles` is used to represent plane handles which memory
29 //! type is known at compilation time, and thus includes a reference to a
30 //! `PlaneHandle` type and by transition its `Memory` type.
31 mod dmabuf;
32 mod mmap;
33 mod userptr;
34 
35 pub use dmabuf::*;
36 pub use mmap::*;
37 pub use userptr::*;
38 
39 use crate::{
40     bindings::{self, v4l2_buffer__bindgen_ty_1, v4l2_plane__bindgen_ty_1},
41     ioctl::{PlaneMapping, QueryBufPlane},
42 };
43 use enumn::N;
44 use std::os::unix::io::AsFd;
45 use std::{fmt::Debug, ops::Deref};
46 
47 /// All the supported V4L2 memory types.
48 #[derive(Debug, Clone, Copy, PartialEq, Eq, N)]
49 #[repr(u32)]
50 pub enum MemoryType {
51     Mmap = bindings::v4l2_memory_V4L2_MEMORY_MMAP,
52     UserPtr = bindings::v4l2_memory_V4L2_MEMORY_USERPTR,
53     Overlay = bindings::v4l2_memory_V4L2_MEMORY_OVERLAY,
54     DmaBuf = bindings::v4l2_memory_V4L2_MEMORY_DMABUF,
55 }
56 
57 /// Trait describing a memory type that can be used to back V4L2 buffers.
58 pub trait Memory: 'static {
59     /// The memory type represented.
60     const MEMORY_TYPE: MemoryType;
61     /// The final type of the memory backing information in `struct v4l2_buffer` or `struct
62     /// v4l2_plane`.
63     type RawBacking;
64 
65     /// Returns a reference to the memory backing information for `m` that is relevant for this
66     /// memory type.
67     ///
68     /// # Safety
69     ///
70     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_plane_buffer_backing(m: &bindings::v4l2_plane__bindgen_ty_1) -> &Self::RawBacking71     unsafe fn get_plane_buffer_backing(m: &bindings::v4l2_plane__bindgen_ty_1)
72         -> &Self::RawBacking;
73 
74     /// Returns a reference to the memory backing information for `m` that is relevant for this memory type.
75     ///
76     /// # Safety
77     ///
78     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_single_planar_buffer_backing( m: &bindings::v4l2_buffer__bindgen_ty_1, ) -> &Self::RawBacking79     unsafe fn get_single_planar_buffer_backing(
80         m: &bindings::v4l2_buffer__bindgen_ty_1,
81     ) -> &Self::RawBacking;
82 
83     /// Returns a mutable reference to the memory backing information for `m` that is relevant for
84     /// this memory type.
85     ///
86     /// # Safety
87     ///
88     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_plane_buffer_backing_mut( m: &mut bindings::v4l2_plane__bindgen_ty_1, ) -> &mut Self::RawBacking89     unsafe fn get_plane_buffer_backing_mut(
90         m: &mut bindings::v4l2_plane__bindgen_ty_1,
91     ) -> &mut Self::RawBacking;
92 
93     /// Returns a mutable reference to the memory backing information for `m` that is relevant for
94     /// this memory type.
95     ///
96     /// # Safety
97     ///
98     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_single_planar_buffer_backing_mut( m: &mut bindings::v4l2_buffer__bindgen_ty_1, ) -> &mut Self::RawBacking99     unsafe fn get_single_planar_buffer_backing_mut(
100         m: &mut bindings::v4l2_buffer__bindgen_ty_1,
101     ) -> &mut Self::RawBacking;
102 }
103 
104 /// Trait for memory types that provide their own memory, i.e. MMAP.
105 pub trait SelfBacked: Memory + Default {}
106 
107 /// Trait for memory types to which external memory must be attached to, i.e. UserPtr and
108 /// DMABuf.
109 pub trait Imported: Memory {}
110 
111 /// Trait for a handle that represents actual data for a single place. A buffer
112 /// will have as many of these as it has planes.
113 pub trait PlaneHandle: Debug + Send + 'static {
114     /// The kind of memory the handle attaches to.
115     type Memory: Memory;
116 
117     /// Fill a plane of a multi-planar V4L2 buffer with the handle's information.
fill_v4l2_plane(&self, plane: &mut bindings::v4l2_plane)118     fn fill_v4l2_plane(&self, plane: &mut bindings::v4l2_plane);
119 }
120 
121 // Trait for plane handles that provide access to their content through a map()
122 // method (typically, MMAP buffers).
123 pub trait Mappable: PlaneHandle {
124     /// Return a `PlaneMapping` enabling access to the memory of this handle.
map<D: AsFd>(device: &D, plane_info: &QueryBufPlane) -> Option<PlaneMapping>125     fn map<D: AsFd>(device: &D, plane_info: &QueryBufPlane) -> Option<PlaneMapping>;
126 }
127 
128 /// Trait for structures providing all the handles of a single buffer.
129 pub trait BufferHandles: Send + Debug + 'static {
130     /// Enumeration of all the `MemoryType` supported by this type. Typically
131     /// a subset of `MemoryType` or `MemoryType` itself.
132     type SupportedMemoryType: Into<MemoryType> + Send + Clone + Copy;
133 
134     /// Number of planes.
len(&self) -> usize135     fn len(&self) -> usize;
136     /// Fill a plane of a multi-planar V4L2 buffer with the `index` handle's information.
fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane)137     fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane);
138 
139     /// Returns true if there are no handles here (unlikely).
is_empty(&self) -> bool140     fn is_empty(&self) -> bool {
141         self.len() == 0
142     }
143 }
144 
145 /// Implementation of `BufferHandles` for all indexables of `PlaneHandle` (e.g. [`std::vec::Vec`]).
146 ///
147 /// This is The simplest way to use primitive handles.
148 impl<P, Q> BufferHandles for Q
149 where
150     P: PlaneHandle,
151     Q: Send + Debug + 'static + Deref<Target = [P]>,
152 {
153     type SupportedMemoryType = MemoryType;
154 
len(&self) -> usize155     fn len(&self) -> usize {
156         self.deref().len()
157     }
158 
fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane)159     fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane) {
160         self.deref()[index].fill_v4l2_plane(plane);
161     }
162 }
163 
164 /// Trait for plane handles for which the final memory type is known at compile
165 /// time.
166 pub trait PrimitiveBufferHandles: BufferHandles {
167     type HandleType: PlaneHandle;
168     const MEMORY_TYPE: Self::SupportedMemoryType;
169 }
170 
171 /// Implementation of `PrimitiveBufferHandles` for all indexables of `PlaneHandle` (e.g.
172 /// [`std::vec::Vec`]).
173 impl<P, Q> PrimitiveBufferHandles for Q
174 where
175     P: PlaneHandle,
176     Q: Send + Debug + 'static + Deref<Target = [P]>,
177 {
178     type HandleType = P;
179     const MEMORY_TYPE: Self::SupportedMemoryType = P::Memory::MEMORY_TYPE;
180 }
181 
182 /// Conversion from `v4l2_buffer`'s backing information to `v4l2_plane`'s.
183 impl From<(&v4l2_buffer__bindgen_ty_1, MemoryType)> for v4l2_plane__bindgen_ty_1 {
from((m, memory): (&v4l2_buffer__bindgen_ty_1, MemoryType)) -> Self184     fn from((m, memory): (&v4l2_buffer__bindgen_ty_1, MemoryType)) -> Self {
185         match memory {
186             MemoryType::Mmap => v4l2_plane__bindgen_ty_1 {
187                 // Safe because the buffer type is determined to be MMAP.
188                 mem_offset: unsafe { m.offset },
189             },
190             MemoryType::UserPtr => v4l2_plane__bindgen_ty_1 {
191                 // Safe because the buffer type is determined to be USERPTR.
192                 userptr: unsafe { m.userptr },
193             },
194             MemoryType::DmaBuf => v4l2_plane__bindgen_ty_1 {
195                 // Safe because the buffer type is determined to be DMABUF.
196                 fd: unsafe { m.fd },
197             },
198             MemoryType::Overlay => Default::default(),
199         }
200     }
201 }
202 
203 /// Conversion from `v4l2_plane`'s backing information to `v4l2_buffer`'s.
204 impl From<(&v4l2_plane__bindgen_ty_1, MemoryType)> for v4l2_buffer__bindgen_ty_1 {
from((m, memory): (&v4l2_plane__bindgen_ty_1, MemoryType)) -> Self205     fn from((m, memory): (&v4l2_plane__bindgen_ty_1, MemoryType)) -> Self {
206         match memory {
207             MemoryType::Mmap => v4l2_buffer__bindgen_ty_1 {
208                 // Safe because the buffer type is determined to be MMAP.
209                 offset: unsafe { m.mem_offset },
210             },
211             MemoryType::UserPtr => v4l2_buffer__bindgen_ty_1 {
212                 // Safe because the buffer type is determined to be USERPTR.
213                 userptr: unsafe { m.userptr },
214             },
215             MemoryType::DmaBuf => v4l2_buffer__bindgen_ty_1 {
216                 // Safe because the buffer type is determined to be DMABUF.
217                 fd: unsafe { m.fd },
218             },
219             MemoryType::Overlay => Default::default(),
220         }
221     }
222 }
223 
224 #[cfg(test)]
225 mod tests {
226     use crate::bindings::v4l2_buffer__bindgen_ty_1;
227     use crate::bindings::v4l2_plane__bindgen_ty_1;
228     use crate::memory::MemoryType;
229 
230     #[test]
231     // Purpose of this test is dubious as the members are overlapping anyway.
plane_m_to_buffer_m()232     fn plane_m_to_buffer_m() {
233         let plane_m = v4l2_plane__bindgen_ty_1 {
234             mem_offset: 0xfeedc0fe,
235         };
236         assert_eq!(
237             unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::Mmap)).offset },
238             0xfeedc0fe
239         );
240 
241         let plane_m = v4l2_plane__bindgen_ty_1 {
242             userptr: 0xfeedc0fe,
243         };
244         assert_eq!(
245             unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::UserPtr)).userptr },
246             0xfeedc0fe
247         );
248 
249         let plane_m = v4l2_plane__bindgen_ty_1 { fd: 0x76543210 };
250         assert_eq!(
251             unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::DmaBuf)).fd },
252             0x76543210
253         );
254     }
255 
256     #[test]
257     // Purpose of this test is dubious as the members are overlapping anyway.
buffer_m_to_plane_m()258     fn buffer_m_to_plane_m() {
259         let buffer_m = v4l2_buffer__bindgen_ty_1 { offset: 0xfeedc0fe };
260         assert_eq!(
261             unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::Mmap)).mem_offset },
262             0xfeedc0fe
263         );
264 
265         let buffer_m = v4l2_buffer__bindgen_ty_1 {
266             userptr: 0xfeedc0fe,
267         };
268         assert_eq!(
269             unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::UserPtr)).userptr },
270             0xfeedc0fe
271         );
272 
273         let buffer_m = v4l2_buffer__bindgen_ty_1 { fd: 0x76543210 };
274         assert_eq!(
275             unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::DmaBuf)).fd },
276             0x76543210
277         );
278     }
279 }
280