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