1 //! Provides types related to queuing buffers on a `Queue` object.
2 use super::{buffer::BufferInfo, Capture, Direction, Output};
3 use super::{BufferState, BufferStateFuse, BuffersAllocated, Queue};
4 use crate::ioctl::{self, QBufIoctlError, QBufResult};
5 use crate::memory::*;
6 use std::convert::Infallible;
7 use std::{
8     fmt::{self, Debug},
9     os::fd::RawFd,
10     sync::Arc,
11 };
12 
13 use nix::sys::time::{TimeVal, TimeValLike};
14 use thiserror::Error;
15 
16 pub mod get_free;
17 pub mod get_indexed;
18 
19 /// Error that can occur when queuing a buffer. It wraps a regular error and also
20 /// returns the plane handles back to the user.
21 #[derive(Error)]
22 #[error("{}", self.error)]
23 pub struct QueueError<P: BufferHandles> {
24     pub error: ioctl::QBufError<Infallible>,
25     pub plane_handles: P,
26 }
27 
28 impl<P: BufferHandles> Debug for QueueError<P> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result29     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30         Debug::fmt(&self.error, f)
31     }
32 }
33 
34 #[allow(type_alias_bounds)]
35 pub type QueueResult<R, P: BufferHandles> = std::result::Result<R, QueueError<P>>;
36 
37 /// A free buffer that has just been obtained from `Queue::get_buffer()` and
38 /// which is being prepared to the queued.
39 ///
40 /// The necessary setup depends on the kind of direction of the buffer:
41 ///
42 /// * Capture buffers are to be filled by the driver, so we just need to attach
43 ///   one memory handle per plane before submitting them (MMAP buffers don't
44 ///   need this step).
45 /// * Output buffers on the other hand are filled by us ; so on top of one valid
46 ///   memory handle per plane, we also need to specify how much data we have
47 ///   written in each of them, and possibly set a few flags on the buffer.
48 ///
49 /// This struct is specialized on both the direction and type of memory so
50 /// mandatory data is always specified, and irrelevant data is inaccessible.
51 ///
52 /// Once a buffer is ready, it can be queued using the queue() method. Failures
53 /// occur if the QBUF ioctl failed, or if the number of specified planes does
54 /// not match the number of planes in the format. A queued buffer remains
55 /// inaccessible for further queuing until it has been dequeued and dropped.
56 ///
57 /// If a QBuffer object is destroyed before being queued, its buffer returns
58 /// to the pool of available buffers and can be requested again with
59 /// `Queue::get_buffer()`.
60 ///
61 /// A QBuffer holds a strong reference to its queue, therefore the state of the
62 /// queue or device cannot be changed while it is being used. Contrary to
63 /// DQBuffer which can be freely duplicated and passed around, instances of this
64 /// struct are supposed to be short-lived.
65 pub struct QBuffer<'a, D: Direction, P: PrimitiveBufferHandles, Q: BufferHandles + From<P>> {
66     queue: &'a Queue<D, BuffersAllocated<Q>>,
67     index: usize,
68     num_planes: usize,
69     timestamp: TimeVal,
70     request: Option<RawFd>,
71     fuse: BufferStateFuse<Q>,
72     _p: std::marker::PhantomData<P>,
73 }
74 
75 impl<'a, D: Direction, P: PrimitiveBufferHandles, Q: BufferHandles + From<P>> QBuffer<'a, D, P, Q> {
new( queue: &'a Queue<D, BuffersAllocated<Q>>, buffer_info: &Arc<BufferInfo<Q>>, ) -> Self76     pub(super) fn new(
77         queue: &'a Queue<D, BuffersAllocated<Q>>,
78         buffer_info: &Arc<BufferInfo<Q>>,
79     ) -> Self {
80         let buffer = &buffer_info.features;
81         let fuse = BufferStateFuse::new(Arc::downgrade(buffer_info));
82 
83         QBuffer {
84             queue,
85             index: buffer.index,
86             num_planes: buffer.planes.len(),
87             timestamp: TimeVal::zero(),
88             request: None,
89             fuse,
90             _p: std::marker::PhantomData,
91         }
92     }
93 
94     /// Returns the V4L2 index of this buffer.
index(&self) -> usize95     pub fn index(&self) -> usize {
96         self.index
97     }
98 
99     /// Returns the number of handles/plane data expected to be specified for
100     /// this buffer.
num_expected_planes(&self) -> usize101     pub fn num_expected_planes(&self) -> usize {
102         self.num_planes
103     }
104 
set_timestamp(mut self, timestamp: TimeVal) -> Self105     pub fn set_timestamp(mut self, timestamp: TimeVal) -> Self {
106         self.timestamp = timestamp;
107         self
108     }
109 
set_request(mut self, fd: RawFd) -> Self110     pub fn set_request(mut self, fd: RawFd) -> Self {
111         self.request = Some(fd);
112         self
113     }
114 
115     // R is meant to mean "either P or Q".
116     // Caller is responsible for making sure that the number of planes and
117     // plane_handles is the same as the number of expected planes for this
118     // buffer.
queue_bound_planes<R: BufferHandles + Into<Q>>( mut self, planes: Vec<ioctl::QBufPlane>, plane_handles: R, ) -> QueueResult<(), R>119     fn queue_bound_planes<R: BufferHandles + Into<Q>>(
120         mut self,
121         planes: Vec<ioctl::QBufPlane>,
122         plane_handles: R,
123     ) -> QueueResult<(), R> {
124         let mut qbuffer =
125             ioctl::QBuffer::<P::HandleType>::new(self.queue.inner.type_, self.index as u32);
126         if let Some(request) = self.request {
127             qbuffer = qbuffer.set_request(request);
128         }
129         qbuffer.planes = planes;
130         qbuffer.timestamp = self.timestamp;
131 
132         match ioctl::qbuf(&self.queue.inner, qbuffer) {
133             Ok(()) => (),
134             Err(error) => {
135                 return Err(QueueError {
136                     error,
137                     plane_handles,
138                 })
139             }
140         };
141 
142         // We got this now.
143         self.fuse.disarm();
144 
145         self.queue
146             .state
147             .buffer_info
148             .get(self.index)
149             .expect("Inconsistent buffer state!")
150             .update_state(|state| {
151                 *state = BufferState::Queued(plane_handles.into());
152             });
153 
154         Ok(())
155     }
156 }
157 
158 impl<'a, P, Q> QBuffer<'a, Output, P, Q>
159 where
160     P: PrimitiveBufferHandles,
161     P::HandleType: Mappable,
162     Q: BufferHandles + From<P>,
163 {
get_plane_mapping(&self, plane: usize) -> Option<ioctl::PlaneMapping>164     pub fn get_plane_mapping(&self, plane: usize) -> Option<ioctl::PlaneMapping> {
165         let buffer_info = self.queue.state.buffer_info.get(self.index)?;
166         let plane_info = buffer_info.features.planes.get(plane)?;
167         P::HandleType::map(self.queue.inner.device.as_ref(), plane_info)
168     }
169 }
170 
171 /// Trait for queueable CAPTURE buffers. These buffers only require handles to
172 /// be queued.
173 pub trait CaptureQueueable<Q: BufferHandles> {
174     /// Queue the buffer after binding `handles`, consuming the object.
175     /// The number of handles must match the buffer's expected number of planes.
queue_with_handles(self, handles: Q) -> QueueResult<(), Q>176     fn queue_with_handles(self, handles: Q) -> QueueResult<(), Q>;
177 }
178 
179 /// Trait for queueable OUTPUT buffers. The number of bytes used must be
180 /// specified for each plane.
181 pub trait OutputQueueable<Q: BufferHandles> {
182     /// Queue the buffer after binding `handles`, consuming the object.
183     /// The number of handles must match the buffer's expected number of planes.
184     /// `bytes_used` must be a slice with as many slices as there are handles,
185     /// describing the amount of useful data in each of them.
queue_with_handles(self, handles: Q, bytes_used: &[usize]) -> QueueResult<(), Q>186     fn queue_with_handles(self, handles: Q, bytes_used: &[usize]) -> QueueResult<(), Q>;
187 }
188 
189 /// Trait for all objects that are capable of providing objects that can be
190 /// queued to the CAPTURE queue.
191 pub trait CaptureQueueableProvider<'a, Q: BufferHandles> {
192     type Queueable: 'a + CaptureQueueable<Q>;
193 }
194 
195 /// Trait for all objects that are capable of providing objects that can be
196 /// queued to the CAPTURE queue.
197 pub trait OutputQueueableProvider<'a, Q: BufferHandles> {
198     type Queueable: 'a + OutputQueueable<Q>;
199 }
200 
201 /// Any CAPTURE QBuffer implements CaptureQueueable.
202 impl<P: PrimitiveBufferHandles, Q: BufferHandles + From<P>> CaptureQueueable<Q>
203     for QBuffer<'_, Capture, P, Q>
204 {
queue_with_handles(self, handles: Q) -> QueueResult<(), Q>205     fn queue_with_handles(self, handles: Q) -> QueueResult<(), Q> {
206         if handles.len() != self.num_expected_planes() {
207             return Err(QueueError {
208                 error: QBufIoctlError::NumPlanesMismatch(handles.len(), self.num_expected_planes())
209                     .into(),
210                 plane_handles: handles,
211             });
212         }
213 
214         // TODO BufferHandles should have a method returning the actual MEMORY_TYPE implemented? So we can check
215         // that it matches with P.
216 
217         let planes: Vec<_> = (0..self.num_expected_planes())
218             .map(|i| {
219                 let mut plane = ioctl::QBufPlane::new(0);
220                 handles.fill_v4l2_plane(i, &mut plane.0);
221                 plane
222             })
223             .collect();
224 
225         self.queue_bound_planes(planes, handles)
226     }
227 }
228 
229 /// Any OUTPUT QBuffer implements OutputQueueable.
230 impl<P: PrimitiveBufferHandles, Q: BufferHandles + From<P>> OutputQueueable<Q>
231     for QBuffer<'_, Output, P, Q>
232 {
queue_with_handles(self, handles: Q, bytes_used: &[usize]) -> QueueResult<(), Q>233     fn queue_with_handles(self, handles: Q, bytes_used: &[usize]) -> QueueResult<(), Q> {
234         if handles.len() != self.num_expected_planes() {
235             return Err(QueueError {
236                 error: QBufIoctlError::NumPlanesMismatch(handles.len(), self.num_expected_planes())
237                     .into(),
238                 plane_handles: handles,
239             });
240         }
241 
242         // TODO make specific error for bytes_used?
243         if bytes_used.len() != self.num_expected_planes() {
244             return Err(QueueError {
245                 error: QBufIoctlError::NumPlanesMismatch(
246                     bytes_used.len(),
247                     self.num_expected_planes(),
248                 )
249                 .into(),
250                 plane_handles: handles,
251             });
252         }
253 
254         // TODO BufferHandles should have a method returning the actual MEMORY_TYPE implemented? So we can check
255         // that it matches with P.
256 
257         let planes: Vec<_> = bytes_used
258             .iter()
259             .enumerate()
260             .map(|(i, size)| {
261                 let mut plane = ioctl::QBufPlane::new(*size);
262                 handles.fill_v4l2_plane(i, &mut plane.0);
263                 plane
264             })
265             .collect();
266 
267         self.queue_bound_planes(planes, handles)
268     }
269 }
270 
271 /// Shortcut to quickly queue self-backed CAPTURE buffers without specifying
272 /// empty handles.
273 /// Since we don't receive plane handles, we also don't need to return any, so
274 /// the returned error can be simplified.
275 impl<P: PrimitiveBufferHandles + Default, Q: BufferHandles + From<P>> QBuffer<'_, Capture, P, Q>
276 where
277     <P::HandleType as PlaneHandle>::Memory: SelfBacked,
278 {
queue(self) -> QBufResult<(), Infallible>279     pub fn queue(self) -> QBufResult<(), Infallible> {
280         let planes: Vec<_> = (0..self.num_expected_planes())
281             .map(|_| ioctl::QBufPlane::new(0))
282             .collect();
283 
284         self.queue_bound_planes::<P>(planes, Default::default())
285             .map_err(|e| e.error)
286     }
287 }
288 
289 /// Shortcut to quickly queue self-backed OUTPUT buffers without specifying
290 /// empty handles.
291 /// Since we don't receive plane handles, we also don't need to return any, so
292 /// the returned error can be simplified.
293 impl<P: PrimitiveBufferHandles + Default, Q: BufferHandles + From<P>> QBuffer<'_, Output, P, Q>
294 where
295     <P::HandleType as PlaneHandle>::Memory: SelfBacked,
296 {
queue(self, bytes_used: &[usize]) -> QBufResult<(), Infallible>297     pub fn queue(self, bytes_used: &[usize]) -> QBufResult<(), Infallible> {
298         // TODO make specific error for bytes_used?
299         if bytes_used.len() != self.num_expected_planes() {
300             return Err(QBufIoctlError::NumPlanesMismatch(
301                 bytes_used.len(),
302                 self.num_expected_planes(),
303             )
304             .into());
305         }
306 
307         let planes: Vec<_> = bytes_used
308             .iter()
309             .map(|size| ioctl::QBufPlane::new(*size))
310             .collect();
311 
312         self.queue_bound_planes::<P>(planes, Default::default())
313             .map_err(|e| e.error)
314     }
315 }
316