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