• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 pub mod buffer;
2 pub mod direction;
3 pub mod dqbuf;
4 pub mod generic;
5 pub mod handles_provider;
6 pub mod qbuf;
7 
8 use super::{AllocatedQueue, Device, FreeBuffersResult, Stream, TryDequeue};
9 use crate::ioctl::{DqBufResult, QueryBufError, V4l2BufferFromError};
10 use crate::{bindings, memory::*};
11 use crate::{
12     ioctl::{
13         self, GFmtError, QueryBuffer, ReqbufsError, SFmtError, SelectionTarget, SelectionType,
14         StreamOffError, StreamOnError, TryFmtError,
15     },
16     PlaneLayout, Rect,
17 };
18 use crate::{Format, PixelFormat, QueueType};
19 use buffer::*;
20 use direction::*;
21 use dqbuf::*;
22 use log::debug;
23 use qbuf::*;
24 
25 use std::convert::{Infallible, TryFrom};
26 use std::os::unix::io::{AsRawFd, RawFd};
27 use std::sync::{Arc, Weak};
28 use thiserror::Error;
29 
30 /// Base values of a queue, that are always value no matter the state the queue
31 /// is in. This base object remains alive as long as the queue is borrowed from
32 /// the `Device`.
33 struct QueueBase {
34     // Reference to the device, so we can perform operations on its `fd` and to let us mark the
35     // queue as free again upon destruction.
36     device: Arc<Device>,
37     type_: QueueType,
38     capabilities: ioctl::BufferCapabilities,
39 }
40 
41 impl AsRawFd for QueueBase {
as_raw_fd(&self) -> RawFd42     fn as_raw_fd(&self) -> RawFd {
43         self.device.as_raw_fd()
44     }
45 }
46 
47 impl Drop for QueueBase {
48     /// Make the queue available again.
drop(&mut self)49     fn drop(&mut self) {
50         assert!(self.device.used_queues.lock().unwrap().remove(&self.type_));
51     }
52 }
53 
54 /// Trait for the different states a queue can be in. This allows us to limit
55 /// the available queue methods to the one that make sense at a given point of
56 /// the queue's lifecycle.
57 pub trait QueueState {}
58 
59 /// V4L2 queue object. Specialized according to its configuration state so that
60 /// only valid methods can be called from a given point.
61 pub struct Queue<D, S>
62 where
63     D: Direction,
64     S: QueueState,
65 {
66     inner: QueueBase,
67     _d: std::marker::PhantomData<D>,
68     state: S,
69 }
70 
71 /// Methods of `Queue` that are available no matter the state.
72 impl<D, S> Queue<D, S>
73 where
74     D: Direction,
75     S: QueueState,
76 {
get_capabilities(&self) -> ioctl::BufferCapabilities77     pub fn get_capabilities(&self) -> ioctl::BufferCapabilities {
78         self.inner.capabilities
79     }
80 
get_type(&self) -> QueueType81     pub fn get_type(&self) -> QueueType {
82         self.inner.type_
83     }
84 
get_format<T: TryFrom<bindings::v4l2_format>>(&self) -> Result<T, GFmtError>85     pub fn get_format<T: TryFrom<bindings::v4l2_format>>(&self) -> Result<T, GFmtError> {
86         ioctl::g_fmt(&self.inner, self.inner.type_)
87     }
88 
89     /// This method can invalidate any current format iterator, hence it requires
90     /// the queue to be mutable. This way of doing is not perfect though, as setting
91     /// the format on one queue can change the options available on another.
set_format(&mut self, format: Format) -> Result<Format, SFmtError>92     pub fn set_format(&mut self, format: Format) -> Result<Format, SFmtError> {
93         let type_ = self.inner.type_;
94         ioctl::s_fmt(&mut self.inner, (type_, &format))
95     }
96 
97     /// Performs exactly as `set_format`, but does not actually apply `format`.
98     /// Useful to check what modifications need to be done to a format before it
99     /// can be used.
try_format(&self, format: Format) -> Result<Format, TryFmtError>100     pub fn try_format(&self, format: Format) -> Result<Format, TryFmtError> {
101         ioctl::try_fmt(&self.inner, (self.inner.type_, &format))
102     }
103 
104     /// Returns a `FormatBuilder` which is set to the currently active format
105     /// and can be modified and eventually applied. The `FormatBuilder` holds
106     /// a mutable reference to this `Queue`.
change_format(&mut self) -> Result<FormatBuilder, GFmtError>107     pub fn change_format(&mut self) -> Result<FormatBuilder, GFmtError> {
108         FormatBuilder::new(&mut self.inner)
109     }
110 
111     /// Returns an iterator over all the formats currently supported by this queue.
format_iter(&self) -> ioctl::FormatIterator<Device>112     pub fn format_iter(&self) -> ioctl::FormatIterator<Device> {
113         ioctl::FormatIterator::new(self.inner.device.as_ref(), self.inner.type_)
114     }
115 
get_selection(&self, target: SelectionTarget) -> Result<Rect, ioctl::GSelectionError>116     pub fn get_selection(&self, target: SelectionTarget) -> Result<Rect, ioctl::GSelectionError> {
117         let selection = match self.get_type() {
118             QueueType::VideoCapture | QueueType::VideoCaptureMplane => SelectionType::Capture,
119             QueueType::VideoOutput | QueueType::VideoOutputMplane => SelectionType::Output,
120             _ => return Err(ioctl::GSelectionError::Invalid),
121         };
122 
123         ioctl::g_selection(&self.inner, selection, target)
124     }
125 }
126 
127 /// Builder for a V4L2 format. This takes a mutable reference on the queue, so
128 /// it is supposed to be short-lived: get one, adjust the format, and apply.
129 pub struct FormatBuilder<'a> {
130     queue: &'a mut QueueBase,
131     format: Format,
132 }
133 
134 impl<'a> FormatBuilder<'a> {
new(queue: &'a mut QueueBase) -> Result<Self, GFmtError>135     fn new(queue: &'a mut QueueBase) -> Result<Self, GFmtError> {
136         let format = ioctl::g_fmt(queue, queue.type_)?;
137         Ok(Self { queue, format })
138     }
139 
140     /// Get a reference to the format built so far. Useful for checking the
141     /// currently set format after getting a builder, or the actual settings
142     /// that will be applied by the kernel after a `try_apply()`.
format(&self) -> &Format143     pub fn format(&self) -> &Format {
144         &self.format
145     }
146 
set_size(mut self, width: usize, height: usize) -> Self147     pub fn set_size(mut self, width: usize, height: usize) -> Self {
148         self.format.width = width as u32;
149         self.format.height = height as u32;
150         self
151     }
152 
set_pixelformat(mut self, pixel_format: impl Into<PixelFormat>) -> Self153     pub fn set_pixelformat(mut self, pixel_format: impl Into<PixelFormat>) -> Self {
154         self.format.pixelformat = pixel_format.into();
155         self
156     }
157 
set_planes_layout<P: IntoIterator<Item = PlaneLayout>>(mut self, planes: P) -> Self158     pub fn set_planes_layout<P: IntoIterator<Item = PlaneLayout>>(mut self, planes: P) -> Self {
159         self.format.plane_fmt = planes.into_iter().collect();
160         self
161     }
162 
163     /// Apply the format built so far. The kernel will adjust the format to fit
164     /// the driver's capabilities if needed, and the format actually applied will
165     /// be returned.
apply<O: TryFrom<bindings::v4l2_format>>(self) -> Result<O, SFmtError>166     pub fn apply<O: TryFrom<bindings::v4l2_format>>(self) -> Result<O, SFmtError> {
167         ioctl::s_fmt(self.queue, (self.queue.type_, &self.format))
168     }
169 
170     /// Try to apply the format built so far. The kernel will adjust the format
171     /// to fit the driver's capabilities if needed, so make sure to check important
172     /// parameters upon return.
173     ///
174     /// Calling `apply()` right after this method is guaranteed to successfully
175     /// apply the format without further change.
try_apply(&mut self) -> Result<(), TryFmtError>176     pub fn try_apply(&mut self) -> Result<(), TryFmtError> {
177         let new_format = ioctl::try_fmt(self.queue, (self.queue.type_, &self.format))?;
178 
179         self.format = new_format;
180         Ok(())
181     }
182 }
183 
184 /// Initial state of the queue when created. Streaming and queuing are not
185 /// supported since buffers have not been allocated yet.
186 /// Allocating buffers makes the queue switch to the `BuffersAllocated` state.
187 pub struct QueueInit;
188 impl QueueState for QueueInit {}
189 
190 #[derive(Debug, Error)]
191 pub enum CreateQueueError {
192     #[error("queue is already in use")]
193     AlreadyBorrowed,
194     #[error("error while querying queue capabilities")]
195     ReqbufsError(#[from] ioctl::ReqbufsError),
196 }
197 
198 #[derive(Debug, Error)]
199 pub enum RequestBuffersError {
200     #[error("error while requesting buffers")]
201     ReqbufsError(#[from] ioctl::ReqbufsError),
202     #[error("error while querying buffer")]
203     QueryBufferError(#[from] QueryBufError<Infallible>),
204 }
205 
206 impl<D: Direction> Queue<D, QueueInit> {
207     /// Create a queue for type `queue_type` on `device`. A queue of a specific type
208     /// can be requested only once.
209     ///
210     /// Not all devices support all kinds of queue. To test whether the queue is supported,
211     /// a REQBUFS(0) is issued on the device. If it is not successful, the device is
212     /// deemed to not support this kind of queue and this method will fail.
create( device: Arc<Device>, queue_type: QueueType, ) -> Result<Queue<D, QueueInit>, CreateQueueError>213     fn create(
214         device: Arc<Device>,
215         queue_type: QueueType,
216     ) -> Result<Queue<D, QueueInit>, CreateQueueError> {
217         let mut used_queues = device.used_queues.lock().unwrap();
218 
219         if used_queues.contains(&queue_type) {
220             return Err(CreateQueueError::AlreadyBorrowed);
221         }
222 
223         // Check that the queue is valid for this device by doing a dummy REQBUFS.
224         // Obtain its capacities while we are at it.
225         let capabilities: ioctl::BufferCapabilities =
226             ioctl::reqbufs(&*device, queue_type, MemoryType::Mmap, 0)
227                 // In the unlikely case that MMAP buffers are not supported, try DMABUF.
228                 .or_else(|e| match e {
229                     ReqbufsError::InvalidBufferType(_, _) => {
230                         ioctl::reqbufs(&*device, queue_type, MemoryType::DmaBuf, 0)
231                     }
232                     _ => Err(e),
233                 })?;
234 
235         used_queues.insert(queue_type);
236 
237         drop(used_queues);
238 
239         Ok(Queue::<D, QueueInit> {
240             inner: QueueBase {
241                 device,
242                 type_: queue_type,
243                 capabilities,
244             },
245             _d: std::marker::PhantomData,
246             state: QueueInit {},
247         })
248     }
249 
request_buffers_generic<P: BufferHandles>( self, memory_type: P::SupportedMemoryType, count: u32, ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError>250     pub fn request_buffers_generic<P: BufferHandles>(
251         self,
252         memory_type: P::SupportedMemoryType,
253         count: u32,
254     ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError> {
255         let type_ = self.inner.type_;
256         let num_buffers: usize = ioctl::reqbufs(&self.inner, type_, memory_type.into(), count)?;
257 
258         debug!(
259             "Requested {} buffers on {} queue, obtained {}",
260             count, type_, num_buffers
261         );
262 
263         // The buffers have been allocated, now let's get their features.
264         // We cannot use functional programming here because we need to return
265         // the error from ioctl::querybuf(), if any.
266         let mut buffer_features = Vec::new();
267         for i in 0..num_buffers {
268             buffer_features.push(ioctl::querybuf(&self.inner, self.inner.type_, i)?);
269         }
270 
271         let buffer_stats = Arc::new(BufferStats::new());
272 
273         let buffer_info = buffer_features
274             .into_iter()
275             .map(|features: QueryBuffer| {
276                 Arc::new(BufferInfo::new(features, Arc::clone(&buffer_stats)))
277             })
278             .collect();
279 
280         Ok(Queue {
281             inner: self.inner,
282             _d: std::marker::PhantomData,
283             state: BuffersAllocated {
284                 memory_type,
285                 buffer_info,
286                 buffer_stats,
287             },
288         })
289     }
290 
291     /// Allocate `count` buffers for this queue and make it transition to the
292     /// `BuffersAllocated` state.
request_buffers<P: PrimitiveBufferHandles>( self, count: u32, ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError>293     pub fn request_buffers<P: PrimitiveBufferHandles>(
294         self,
295         count: u32,
296     ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError> {
297         self.request_buffers_generic(P::MEMORY_TYPE, count)
298     }
299 }
300 
301 impl Queue<Output, QueueInit> {
302     /// Acquires the OUTPUT queue from `device`.
303     ///
304     /// This method will fail if the queue has already been obtained and has not
305     /// yet been released.
get_output_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>306     pub fn get_output_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
307         Queue::<Output, QueueInit>::create(device, QueueType::VideoOutput)
308     }
309 
310     /// Acquires the OUTPUT_MPLANE queue from `device`.
311     ///
312     /// This method will fail if the queue has already been obtained and has not
313     /// yet been released.
get_output_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>314     pub fn get_output_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
315         Queue::<Output, QueueInit>::create(device, QueueType::VideoOutputMplane)
316     }
317 }
318 
319 impl Queue<Capture, QueueInit> {
320     /// Acquires the CAPTURE queue from `device`.
321     ///
322     /// This method will fail if the queue has already been obtained and has not
323     /// yet been released.
get_capture_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>324     pub fn get_capture_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
325         Queue::<Capture, QueueInit>::create(device, QueueType::VideoCapture)
326     }
327 
328     /// Acquires the CAPTURE_MPLANE queue from `device`.
329     ///
330     /// This method will fail if the queue has already been obtained and has not
331     /// yet been released.
get_capture_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>332     pub fn get_capture_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
333         Queue::<Capture, QueueInit>::create(device, QueueType::VideoCaptureMplane)
334     }
335 }
336 
337 /// Allocated state for a queue. A queue with its buffers allocated can be
338 /// streamed on and off, and buffers can be queued and dequeued.
339 pub struct BuffersAllocated<P: BufferHandles> {
340     memory_type: P::SupportedMemoryType,
341     /// Keep one `Arc` per buffer. This allows us to invalidate this buffer only in case it gets
342     /// deallocated alone (V4L2 currently does not allow this, but might in the future).
343     buffer_info: Vec<Arc<BufferInfo<P>>>,
344     buffer_stats: Arc<BufferStats>,
345 }
346 impl<P: BufferHandles> QueueState for BuffersAllocated<P> {}
347 
348 impl<D: Direction, P: BufferHandles> Queue<D, BuffersAllocated<P>> {
349     /// Return all the currently queued buffers as CanceledBuffers. This can
350     /// be called after a explicit or implicit streamoff to inform the client
351     /// of which buffers have been canceled and return their handles.
cancel_queued_buffers(&self) -> Vec<CanceledBuffer<P>>352     fn cancel_queued_buffers(&self) -> Vec<CanceledBuffer<P>> {
353         let canceled_buffers: Vec<_> = self
354             .state
355             .buffer_info
356             .iter()
357             .filter_map(|buffer_info| {
358                 // Take the handles of queued entries and make them free again.
359                 // Skip entries in any other state.
360                 let plane_handles = buffer_info.update_state(|state| {
361                     match *state {
362                         // Set queued entry to `Free` state and steal its handles.
363                         BufferState::Queued(_) => {
364                             // We just matched the state but need to do it again in order to take
365                             // the handles since `state` is a reference...
366                             match std::mem::replace(state, BufferState::Free) {
367                                 BufferState::Queued(handles) => Some(handles),
368                                 _ => unreachable!(),
369                             }
370                         }
371                         // Filter out entries not in queued state.
372                         _ => None,
373                     }
374                 })?;
375 
376                 Some(CanceledBuffer {
377                     index: buffer_info.features.index as u32,
378                     plane_handles,
379                 })
380             })
381             .collect();
382 
383         debug!(
384             "{} buffers canceled on {} queue",
385             canceled_buffers.len(),
386             self.get_type()
387         );
388 
389         assert_eq!(self.state.buffer_stats.num_queued(), 0);
390 
391         canceled_buffers
392     }
393 
394     /// Try to obtain a buffer to pass to userspace so it can be queued. `index` must be the index
395     /// of a buffer in the `Free` state, otherwise an `AlreadyUsed` error is returned.
try_obtain_buffer(&self, index: usize) -> Result<&Arc<BufferInfo<P>>, TryGetBufferError>396     fn try_obtain_buffer(&self, index: usize) -> Result<&Arc<BufferInfo<P>>, TryGetBufferError> {
397         let buffer_info = self
398             .state
399             .buffer_info
400             .get(index)
401             .ok_or(TryGetBufferError::InvalidIndex(index))?;
402 
403         buffer_info.update_state(|state| match *state {
404             BufferState::Free => {
405                 *state = BufferState::PreQueue;
406                 Ok(())
407             }
408             _ => Err(TryGetBufferError::AlreadyUsed),
409         })?;
410 
411         Ok(buffer_info)
412     }
413 }
414 
415 impl<'a, D: Direction, P: BufferHandles + 'a> AllocatedQueue<'a, D>
416     for Queue<D, BuffersAllocated<P>>
417 {
num_buffers(&self) -> usize418     fn num_buffers(&self) -> usize {
419         self.state.buffer_info.len()
420     }
421 
num_queued_buffers(&self) -> usize422     fn num_queued_buffers(&self) -> usize {
423         self.state.buffer_stats.num_queued()
424     }
425 
num_free_buffers(&self) -> usize426     fn num_free_buffers(&self) -> usize {
427         self.state.buffer_stats.num_free()
428     }
429 
free_buffers(self) -> Result<FreeBuffersResult<D, Self>, ioctl::ReqbufsError>430     fn free_buffers(self) -> Result<FreeBuffersResult<D, Self>, ioctl::ReqbufsError> {
431         let type_ = self.inner.type_;
432         ioctl::reqbufs::<()>(&self.inner, type_, self.state.memory_type.into(), 0)?;
433 
434         debug!("Freed all buffers on {} queue", type_);
435 
436         // reqbufs also performs an implicit streamoff, so return the cancelled
437         // buffers.
438         let canceled_buffers = self.cancel_queued_buffers();
439 
440         Ok(FreeBuffersResult {
441             queue: Queue {
442                 inner: self.inner,
443                 _d: std::marker::PhantomData,
444                 state: QueueInit {},
445             },
446             canceled_buffers,
447         })
448     }
449 }
450 
451 /// Represents a queued buffer which has not been processed due to `streamoff`
452 /// being called on a queue.
453 pub struct CanceledBuffer<P: BufferHandles> {
454     /// Index of the buffer,
455     pub index: u32,
456     /// Plane handles that were passed when the buffer has been queued.
457     pub plane_handles: P,
458 }
459 
460 impl<D: Direction, P: BufferHandles> Stream for Queue<D, BuffersAllocated<P>> {
461     type Canceled = CanceledBuffer<P>;
462 
stream_on(&self) -> Result<(), StreamOnError>463     fn stream_on(&self) -> Result<(), StreamOnError> {
464         debug!("{} queue streaming on", self.get_type());
465         let type_ = self.inner.type_;
466         ioctl::streamon(&self.inner, type_)
467     }
468 
stream_off(&self) -> Result<Vec<Self::Canceled>, StreamOffError>469     fn stream_off(&self) -> Result<Vec<Self::Canceled>, StreamOffError> {
470         debug!("{} queue streaming off", self.get_type());
471         let type_ = self.inner.type_;
472         ioctl::streamoff(&self.inner, type_)?;
473 
474         Ok(self.cancel_queued_buffers())
475     }
476 }
477 
478 impl<D: Direction, P: BufferHandles> TryDequeue for Queue<D, BuffersAllocated<P>> {
479     type Dequeued = DqBuffer<D, P>;
480 
try_dequeue(&self) -> DqBufResult<Self::Dequeued, V4l2BufferFromError>481     fn try_dequeue(&self) -> DqBufResult<Self::Dequeued, V4l2BufferFromError> {
482         let dqbuf: ioctl::V4l2Buffer = ioctl::dqbuf(&self.inner, self.inner.type_)?;
483 
484         let id = dqbuf.index() as usize;
485 
486         let buffer_info = self
487             .state
488             .buffer_info
489             .get(id)
490             .expect("Inconsistent buffer state!");
491 
492         let plane_handles = buffer_info.update_state(|state| match *state {
493             BufferState::Queued(_) => {
494                 // We just matched the state but need to do it again in order to take the handles
495                 // since `state` is a reference...
496                 match std::mem::replace(state, BufferState::Dequeued) {
497                     BufferState::Queued(handles) => handles,
498                     _ => unreachable!(),
499                 }
500             }
501             _ => unreachable!("Inconsistent buffer state!"),
502         });
503 
504         let fuse = BufferStateFuse::new(Arc::downgrade(buffer_info));
505 
506         let dqbuffer = DqBuffer::new(self, buffer_info, plane_handles, dqbuf, fuse);
507 
508         Ok(dqbuffer)
509     }
510 }
511 
512 #[derive(Debug, Error)]
513 pub enum TryGetBufferError {
514     #[error("buffer with provided index {0} does not exist")]
515     InvalidIndex(usize),
516     #[error("buffer is already in use")]
517     AlreadyUsed,
518 }
519 
520 #[derive(Debug, Error)]
521 pub enum GetFreeBufferError {
522     #[error("all buffers are currently being used")]
523     NoFreeBuffer,
524 }
525 
526 mod private {
527     use std::ops::Deref;
528 
529     use super::*;
530 
531     /// The lifetime `'a` is here to allow implementations to attach the lifetime of their return
532     /// value to `self`. This is useful when we want the buffer to hold a reference to the queue
533     /// that prevents the latter from mutating as long as the buffer is not consumed.
534     pub trait QueueableProvider<'a> {
535         type Queueable;
536     }
537 
538     /// Private trait for providing a Queuable regardless of the queue's direction.
539     ///
540     /// This avoids duplicating the same code in Capture/OutputQueueableProvider's implementations.
541     pub trait GetBufferByIndex<'a>: QueueableProvider<'a> {
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>542         fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>;
543     }
544 
545     /// Same as `GetBufferByIndex` but for providing any free buffer.
546     pub trait GetFreeBuffer<'a>: QueueableProvider<'a> {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>547         fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>;
548     }
549 
550     impl<'a, D: Direction, P: PrimitiveBufferHandles> QueueableProvider<'a>
551         for Queue<D, BuffersAllocated<P>>
552     {
553         type Queueable = QBuffer<D, P, P, &'a Queue<D, BuffersAllocated<P>>>;
554     }
555 
556     impl<'a, D: Direction, P: PrimitiveBufferHandles> GetBufferByIndex<'a>
557         for Queue<D, BuffersAllocated<P>>
558     {
559         // Take buffer `id` in order to prepare it for queueing, provided it is available.
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>560         fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
561             Ok(QBuffer::new(self, self.try_obtain_buffer(index)?))
562         }
563     }
564 
565     impl<'a, D, P, Q> QueueableProvider<'a> for Q
566     where
567         D: Direction,
568         P: PrimitiveBufferHandles,
569         Q: Deref<Target = Queue<D, BuffersAllocated<P>>> + Clone,
570     {
571         type Queueable = QBuffer<D, P, P, Q>;
572     }
573 
574     /// Allows to obtain a [`QBuffer`] with a `'static` lifetime from e.g. an `Arc<Queue>`.
575     ///
576     /// [`QBuffer`]s obtained directly from a [`Queue`] maintain consistency by holding a reference
577     /// to the [`Queue`], which can be inconvenient if we need to keep the [`QBuffer`] aside for
578     /// some time. This implementation allows [`QBuffer`]s to be created with a static lifetime
579     /// from a queue behind a cloneable and dereferencable type (typically [`std::rc::Rc`] or
580     /// [`std::sync::Arc`]).
581     ///
582     /// This added flexibility comes with the counterpart that the user must unwrap the [`Queue`]
583     /// from its container reference before applying mutable operations to it like
584     /// [`Queue::request_buffers`]. Doing so requires calling methods like
585     /// [`std::sync::Arc::into_inner`], which only succeed if there is no other reference to the
586     /// queue, preserving consistency explicitly at runtime instead of implicitly at compile-time.
587     impl<'a, D, P, Q> GetBufferByIndex<'a> for Q
588     where
589         D: Direction,
590         P: PrimitiveBufferHandles,
591         Q: Deref<Target = Queue<D, BuffersAllocated<P>>> + Clone,
592     {
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>593         fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
594             Ok(QBuffer::new(self.clone(), self.try_obtain_buffer(index)?))
595         }
596     }
597 
598     impl<'a, D, P> GetFreeBuffer<'a> for Queue<D, BuffersAllocated<P>>
599     where
600         D: Direction,
601         P: BufferHandles,
602         Self: GetBufferByIndex<'a>,
603     {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>604         fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError> {
605             self.state
606                 .buffer_info
607                 .iter()
608                 .enumerate()
609                 .find(|(_, s)| s.do_with_state(|s| matches!(s, BufferState::Free)))
610                 .ok_or(GetFreeBufferError::NoFreeBuffer)
611                 // We found a buffer with a `Free` state, so calling `try_get_buffer` on it is
612                 // guaranteed to succeed.
613                 .map(|(i, _)| self.try_get_buffer(i).unwrap())
614         }
615     }
616 
617     /// Allows to obtain a [`QBuffer`] with a `'static` lifetime from e.g. an `Arc<Queue>`.
618     ///
619     /// [`QBuffer`]s obtained directly from a [`Queue`] maintain consistency by holding a reference
620     /// to the [`Queue`], which can be inconvenient if we need to keep the [`QBuffer`] aside for
621     /// some time. This implementation allows [`QBuffer`]s to be created with a static lifetime
622     /// from a queue behind a cloneable and dereferencable type (typically [`std::rc::Rc`] or
623     /// [`std::sync::Arc`]).
624     ///
625     /// This added flexibility comes with the counterpart that the user must unwrap the [`Queue`]
626     /// from its container reference before applying mutable operations to it like
627     /// [`Queue::request_buffers`]. Doing so requires calling methods like
628     /// [`std::sync::Arc::into_inner`], which only succeed if there is no other reference to the
629     /// queue, preserving consistency explicitly at runtime instead of implicitly at compile-time.
630     impl<'a, D, P, Q> GetFreeBuffer<'a> for Q
631     where
632         D: Direction,
633         P: PrimitiveBufferHandles,
634         Q: Deref<Target = Queue<D, BuffersAllocated<P>>> + Clone,
635     {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>636         fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError> {
637             self.state
638                 .buffer_info
639                 .iter()
640                 .enumerate()
641                 .find(|(_, s)| s.do_with_state(|s| matches!(s, BufferState::Free)))
642                 .ok_or(GetFreeBufferError::NoFreeBuffer)
643                 // We found a buffer with a `Free` state, so calling `try_get_buffer` on it is
644                 // guaranteed to succeed.
645                 .map(|(i, _)| self.try_get_buffer(i).unwrap())
646         }
647     }
648 }
649 
650 /// Trait for queueable CAPTURE buffers. These buffers only require handles to
651 /// be queued.
652 pub trait CaptureQueueable<B: BufferHandles> {
653     /// Queue the buffer after binding `handles`, consuming the object.
654     /// The number of handles must match the buffer's expected number of planes.
queue_with_handles(self, handles: B) -> QueueResult<(), B>655     fn queue_with_handles(self, handles: B) -> QueueResult<(), B>;
656 }
657 
658 /// Trait for queueable OUTPUT buffers. The number of bytes used must be
659 /// specified for each plane.
660 pub trait OutputQueueable<B: BufferHandles> {
661     /// Queue the buffer after binding `handles`, consuming the object.
662     /// The number of handles must match the buffer's expected number of planes.
663     /// `bytes_used` must be a slice with as many slices as there are handles,
664     /// describing the amount of useful data in each of them.
queue_with_handles(self, handles: B, bytes_used: &[usize]) -> QueueResult<(), B>665     fn queue_with_handles(self, handles: B, bytes_used: &[usize]) -> QueueResult<(), B>;
666 }
667 
668 /// Trait for all objects that are capable of providing objects that can be
669 /// queued to the CAPTURE queue.
670 pub trait CaptureQueueableProvider<'a, B: BufferHandles> {
671     type Queueable: CaptureQueueable<B>;
672 }
673 
674 impl<'a, B, Q> CaptureQueueableProvider<'a, B> for Q
675 where
676     B: BufferHandles,
677     Q: private::QueueableProvider<'a>,
678     Q::Queueable: CaptureQueueable<B>,
679 {
680     type Queueable = <Self as private::QueueableProvider<'a>>::Queueable;
681 }
682 
683 /// Trait for all objects that are capable of providing objects that can be
684 /// queued to the CAPTURE queue.
685 pub trait OutputQueueableProvider<'a, B: BufferHandles> {
686     type Queueable: OutputQueueable<B>;
687 }
688 
689 impl<'a, B, Q> OutputQueueableProvider<'a, B> for Q
690 where
691     B: BufferHandles,
692     Q: private::QueueableProvider<'a>,
693     Q::Queueable: OutputQueueable<B>,
694 {
695     type Queueable = <Self as private::QueueableProvider<'a>>::Queueable;
696 }
697 
698 pub trait GetOutputBufferByIndex<'a, B, ErrorType = TryGetBufferError>
699 where
700     B: BufferHandles,
701     Self: OutputQueueableProvider<'a, B>,
702 {
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, ErrorType>703     fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, ErrorType>;
704 }
705 
706 impl<'a, B: BufferHandles> GetOutputBufferByIndex<'a, B> for Queue<Output, BuffersAllocated<B>>
707 where
708     Self: private::GetBufferByIndex<'a>,
709     <Self as private::QueueableProvider<'a>>::Queueable: OutputQueueable<B>,
710 {
711     // Take buffer `id` in order to prepare it for queueing, provided it is available.
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>712     fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
713         <Self as private::GetBufferByIndex<'a>>::try_get_buffer(self, index)
714     }
715 }
716 
717 pub trait GetCaptureBufferByIndex<'a, P: BufferHandles, ErrorType = TryGetBufferError>
718 where
719     Self: CaptureQueueableProvider<'a, P>,
720 {
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, ErrorType>721     fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, ErrorType>;
722 }
723 
724 impl<'a, P: BufferHandles> GetCaptureBufferByIndex<'a, P> for Queue<Capture, BuffersAllocated<P>>
725 where
726     Self: private::GetBufferByIndex<'a>,
727     <Self as private::QueueableProvider<'a>>::Queueable: CaptureQueueable<P>,
728 {
729     // Take buffer `id` in order to prepare it for queueing, provided it is available.
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>730     fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
731         <Self as private::GetBufferByIndex<'a>>::try_get_buffer(self, index)
732     }
733 }
734 
735 pub trait GetFreeOutputBuffer<'a, P: BufferHandles, ErrorType = GetFreeBufferError>
736 where
737     Self: OutputQueueableProvider<'a, P>,
738 {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, ErrorType>739     fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, ErrorType>;
740 }
741 
742 impl<'a, P: BufferHandles, Q> GetFreeOutputBuffer<'a, P> for Q
743 where
744     Self: private::GetFreeBuffer<'a>,
745     <Self as private::QueueableProvider<'a>>::Queueable: OutputQueueable<P>,
746 {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>747     fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError> {
748         <Self as private::GetFreeBuffer<'a>>::try_get_free_buffer(self)
749     }
750 }
751 
752 pub trait GetFreeCaptureBuffer<'a, P: BufferHandles, ErrorType = GetFreeBufferError>
753 where
754     Self: CaptureQueueableProvider<'a, P>,
755 {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, ErrorType>756     fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, ErrorType>;
757 }
758 
759 impl<'a, P: BufferHandles, Q> GetFreeCaptureBuffer<'a, P> for Q
760 where
761     Self: private::GetFreeBuffer<'a>,
762     <Self as private::QueueableProvider<'a>>::Queueable: CaptureQueueable<P>,
763 {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>764     fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError> {
765         <Self as private::GetFreeBuffer<'a>>::try_get_free_buffer(self)
766     }
767 }
768 
769 /// A fuse that will return the buffer to the Free state when destroyed, unless
770 /// it has been disarmed.
771 struct BufferStateFuse<P: BufferHandles> {
772     buffer_info: Weak<BufferInfo<P>>,
773 }
774 
775 impl<P: BufferHandles> BufferStateFuse<P> {
776     /// Create a new fuse that will set `state` to `BufferState::Free` if
777     /// destroyed before `disarm()` has been called.
new(buffer_info: Weak<BufferInfo<P>>) -> Self778     fn new(buffer_info: Weak<BufferInfo<P>>) -> Self {
779         BufferStateFuse { buffer_info }
780     }
781 
782     /// Disarm this fuse, e.g. the monitored state will be left untouched when
783     /// the fuse is destroyed.
disarm(&mut self)784     fn disarm(&mut self) {
785         // Drop our weak reference.
786         self.buffer_info = Weak::new();
787     }
788 
789     /// Trigger the fuse, i.e. make the buffer return to the Free state, unless the fuse has been
790     /// `disarm`ed or the buffer freed. This method should only be called when the reference to the
791     /// buffer is being dropped, otherwise inconsistent state may ensue. The fuse will be disarmed
792     /// after this call.
trigger(&mut self)793     fn trigger(&mut self) {
794         match self.buffer_info.upgrade() {
795             None => (),
796             Some(buffer_info) => {
797                 buffer_info.update_state(|state| *state = BufferState::Free);
798                 self.disarm();
799             }
800         };
801     }
802 }
803 
804 impl<P: BufferHandles> Drop for BufferStateFuse<P> {
drop(&mut self)805     fn drop(&mut self) {
806         self.trigger();
807     }
808 }
809