use crate::device::queue::{
buffer::BufferInfo, BufferState, BufferStateFuse, BuffersAllocated, Capture, CaptureQueueable,
Direction, Output, OutputQueueable, Queue,
};
use crate::ioctl::{self, QBufIoctlError, QBufResult};
use crate::memory::*;
use std::convert::Infallible;
use std::ops::Deref;
use std::{
fmt::{self, Debug},
os::fd::RawFd,
sync::Arc,
};
use nix::sys::time::{TimeVal, TimeValLike};
use thiserror::Error;
#[derive(Error)]
#[error("{}", self.error)]
pub struct QueueError<B: BufferHandles> {
pub error: ioctl::QBufError<Infallible>,
pub plane_handles: B,
}
impl<B: BufferHandles> Debug for QueueError<B> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.error, f)
}
}
#[allow(type_alias_bounds)]
pub type QueueResult<R, B: BufferHandles> = std::result::Result<R, QueueError<B>>;
pub struct QBuffer<
D: Direction,
P: PrimitiveBufferHandles,
B: BufferHandles + From<P>,
Q: Deref<Target = Queue<D, BuffersAllocated<B>>>,
> {
queue: Q,
index: usize,
num_planes: usize,
timestamp: TimeVal,
request: Option<RawFd>,
fuse: BufferStateFuse<B>,
_p: std::marker::PhantomData<P>,
}
impl<D, P, B, Q> QBuffer<D, P, B, Q>
where
D: Direction,
P: PrimitiveBufferHandles,
B: BufferHandles + From<P>,
Q: Deref<Target = Queue<D, BuffersAllocated<B>>>,
{
pub(super) fn new(queue: Q, buffer_info: &Arc<BufferInfo<B>>) -> Self {
let buffer = &buffer_info.features;
let fuse = BufferStateFuse::new(Arc::downgrade(buffer_info));
QBuffer {
queue,
index: buffer.index,
num_planes: buffer.planes.len(),
timestamp: TimeVal::zero(),
request: None,
fuse,
_p: std::marker::PhantomData,
}
}
pub fn index(&self) -> usize {
self.index
}
pub fn num_expected_planes(&self) -> usize {
self.num_planes
}
pub fn set_timestamp(mut self, timestamp: TimeVal) -> Self {
self.timestamp = timestamp;
self
}
pub fn set_request(mut self, fd: RawFd) -> Self {
self.request = Some(fd);
self
}
fn queue_bound_planes<R: BufferHandles + Into<B>>(
mut self,
planes: Vec<ioctl::QBufPlane>,
plane_handles: R,
) -> QueueResult<(), R> {
let mut qbuffer =
ioctl::QBuffer::<P::HandleType>::new(self.queue.inner.type_, self.index as u32);
if let Some(request) = self.request {
qbuffer = qbuffer.set_request(request);
}
qbuffer.planes = planes;
qbuffer.timestamp = self.timestamp;
match ioctl::qbuf(&self.queue.inner, qbuffer) {
Ok(()) => (),
Err(error) => {
return Err(QueueError {
error,
plane_handles,
})
}
};
self.fuse.disarm();
self.queue
.state
.buffer_info
.get(self.index)
.expect("Inconsistent buffer state!")
.update_state(|state| {
*state = BufferState::Queued(plane_handles.into());
});
Ok(())
}
}
impl<P, B, Q> QBuffer<Output, P, B, Q>
where
P: PrimitiveBufferHandles,
P::HandleType: Mappable,
B: BufferHandles + From<P>,
Q: Deref<Target = Queue<Output, BuffersAllocated<B>>>,
{
pub fn get_plane_mapping(&self, plane: usize) -> Option<ioctl::PlaneMapping> {
let buffer_info = self.queue.state.buffer_info.get(self.index)?;
let plane_info = buffer_info.features.planes.get(plane)?;
P::HandleType::map(self.queue.inner.device.as_ref(), plane_info)
}
}
impl<P, B, Q> CaptureQueueable<B> for QBuffer<Capture, P, B, Q>
where
P: PrimitiveBufferHandles,
B: BufferHandles + From<P>,
Q: Deref<Target = Queue<Capture, BuffersAllocated<B>>>,
{
fn queue_with_handles(self, handles: B) -> QueueResult<(), B> {
if handles.len() != self.num_expected_planes() {
return Err(QueueError {
error: QBufIoctlError::NumPlanesMismatch(handles.len(), self.num_expected_planes())
.into(),
plane_handles: handles,
});
}
let planes: Vec<_> = (0..self.num_expected_planes())
.map(|i| {
let mut plane = ioctl::QBufPlane::new(0);
handles.fill_v4l2_plane(i, &mut plane.0);
plane
})
.collect();
self.queue_bound_planes(planes, handles)
}
}
impl<P, B, Q> OutputQueueable<B> for QBuffer<Output, P, B, Q>
where
P: PrimitiveBufferHandles,
B: BufferHandles + From<P>,
Q: Deref<Target = Queue<Output, BuffersAllocated<B>>>,
{
fn queue_with_handles(self, handles: B, bytes_used: &[usize]) -> QueueResult<(), B> {
if handles.len() != self.num_expected_planes() {
return Err(QueueError {
error: QBufIoctlError::NumPlanesMismatch(handles.len(), self.num_expected_planes())
.into(),
plane_handles: handles,
});
}
if bytes_used.len() != self.num_expected_planes() {
return Err(QueueError {
error: QBufIoctlError::NumPlanesMismatch(
bytes_used.len(),
self.num_expected_planes(),
)
.into(),
plane_handles: handles,
});
}
let planes: Vec<_> = bytes_used
.iter()
.enumerate()
.map(|(i, size)| {
let mut plane = ioctl::QBufPlane::new(*size);
handles.fill_v4l2_plane(i, &mut plane.0);
plane
})
.collect();
self.queue_bound_planes(planes, handles)
}
}
impl<P, B, Q> QBuffer<Capture, P, B, Q>
where
P: PrimitiveBufferHandles + Default,
<P::HandleType as PlaneHandle>::Memory: SelfBacked,
B: BufferHandles + From<P>,
Q: Deref<Target = Queue<Capture, BuffersAllocated<B>>>,
{
pub fn queue(self) -> QBufResult<(), Infallible> {
let planes: Vec<_> = (0..self.num_expected_planes())
.map(|_| ioctl::QBufPlane::new(0))
.collect();
self.queue_bound_planes::<P>(planes, Default::default())
.map_err(|e| e.error)
}
}
impl<P, B, Q> QBuffer<Output, P, B, Q>
where
<P::HandleType as PlaneHandle>::Memory: SelfBacked,
P: PrimitiveBufferHandles + Default,
B: BufferHandles + From<P>,
Q: Deref<Target = Queue<Output, BuffersAllocated<B>>>,
{
pub fn queue(self, bytes_used: &[usize]) -> QBufResult<(), Infallible> {
if bytes_used.len() != self.num_expected_planes() {
return Err(QBufIoctlError::NumPlanesMismatch(
bytes_used.len(),
self.num_expected_planes(),
)
.into());
}
let planes: Vec<_> = bytes_used
.iter()
.map(|size| ioctl::QBufPlane::new(*size))
.collect();
self.queue_bound_planes::<P>(planes, Default::default())
.map_err(|e| e.error)
}
}