Skip to content

Commit

Permalink
queue/qbuf: remove lifetime requirement on QBuffer
Browse files Browse the repository at this point in the history
Similarly to what the previous commit did for some traits, remove the
lifetime generic parameter from QBuffer, and make the reference type
generic.

This will allow us to use either direct references to the providing
queue (which guarantees at compile-time that the queue cannot be mutated
while a buffer is being prepared), or reference-counter ones like Rc or
  Arc (which gives us more freedom as for how long we can keep a QBuffer
  alive, but require runtime-checks on the provided queue before it can
  be mutated).
  • Loading branch information
Gnurou committed Oct 6, 2024
1 parent 2c56d1f commit d4af16d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 30 deletions.
4 changes: 2 additions & 2 deletions lib/src/device/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ mod private {
impl<'a, D: Direction, P: PrimitiveBufferHandles> GetBufferByIndex<'a>
for Queue<D, BuffersAllocated<P>>
{
type Queueable = QBuffer<'a, D, P, P>;
type Queueable = QBuffer<D, P, P, &'a Queue<D, BuffersAllocated<P>>>;

// Take buffer `id` in order to prepare it for queueing, provided it is available.
fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
Expand All @@ -548,7 +548,7 @@ mod private {
}

impl<'a, D: Direction> GetBufferByIndex<'a> for Queue<D, BuffersAllocated<GenericBufferHandles>> {
type Queueable = GenericQBuffer<'a, D>;
type Queueable = GenericQBuffer<D, &'a Self>;

fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
let buffer_info = self.try_obtain_buffer(index)?;
Expand Down
50 changes: 34 additions & 16 deletions lib/src/device/queue/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ use crate::{
device::queue::{
direction::{Capture, Direction, Output},
qbuf::{CaptureQueueable, OutputQueueable, QBuffer, QueueResult},
BuffersAllocated, Queue,
},
memory::DmaBufHandle,
};
use crate::{
memory::MmapHandle,
memory::{BufferHandles, MemoryType, UserPtrHandle},
};
use std::{fmt::Debug, fs::File};
use std::{fmt::Debug, fs::File, ops::Deref};

/// Supported memory types for `GenericBufferHandles`.
/// TODO: This should be renamed to "DynamicBufferHandles", and be constructed
Expand Down Expand Up @@ -80,38 +81,52 @@ impl BufferHandles for GenericBufferHandles {

/// A QBuffer that holds either MMAP or UserPtr handles, depending on which
/// memory type has been selected for the queue at runtime.
pub enum GenericQBuffer<'a, D: Direction> {
Mmap(QBuffer<'a, D, Vec<MmapHandle>, GenericBufferHandles>),
User(QBuffer<'a, D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles>),
DmaBuf(QBuffer<'a, D, Vec<DmaBufHandle<File>>, GenericBufferHandles>),
pub enum GenericQBuffer<
D: Direction,
Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
> {
Mmap(QBuffer<D, Vec<MmapHandle>, GenericBufferHandles, Q>),
User(QBuffer<D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles, Q>),
DmaBuf(QBuffer<D, Vec<DmaBufHandle<File>>, GenericBufferHandles, Q>),
}

impl<'a, D: Direction> From<QBuffer<'a, D, Vec<MmapHandle>, GenericBufferHandles>>
for GenericQBuffer<'a, D>
impl<D, Q> From<QBuffer<D, Vec<MmapHandle>, GenericBufferHandles, Q>> for GenericQBuffer<D, Q>
where
D: Direction,
Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
{
fn from(qb: QBuffer<'a, D, Vec<MmapHandle>, GenericBufferHandles>) -> Self {
fn from(qb: QBuffer<D, Vec<MmapHandle>, GenericBufferHandles, Q>) -> Self {
GenericQBuffer::Mmap(qb)
}
}

impl<'a, D: Direction> From<QBuffer<'a, D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles>>
for GenericQBuffer<'a, D>
impl<D, Q> From<QBuffer<D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles, Q>>
for GenericQBuffer<D, Q>
where
D: Direction,
Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
{
fn from(qb: QBuffer<'a, D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles>) -> Self {
fn from(qb: QBuffer<D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles, Q>) -> Self {
GenericQBuffer::User(qb)
}
}

impl<'a, D: Direction> From<QBuffer<'a, D, Vec<DmaBufHandle<File>>, GenericBufferHandles>>
for GenericQBuffer<'a, D>
impl<D, Q> From<QBuffer<D, Vec<DmaBufHandle<File>>, GenericBufferHandles, Q>>
for GenericQBuffer<D, Q>
where
D: Direction,
Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
{
fn from(qb: QBuffer<'a, D, Vec<DmaBufHandle<File>>, GenericBufferHandles>) -> Self {
fn from(qb: QBuffer<D, Vec<DmaBufHandle<File>>, GenericBufferHandles, Q>) -> Self {
GenericQBuffer::DmaBuf(qb)
}
}

/// Any CAPTURE GenericQBuffer implements CaptureQueueable.
impl CaptureQueueable<GenericBufferHandles> for GenericQBuffer<'_, Capture> {
impl<Q> CaptureQueueable<GenericBufferHandles> for GenericQBuffer<Capture, Q>
where
Q: Deref<Target = Queue<Capture, BuffersAllocated<GenericBufferHandles>>>,
{
fn queue_with_handles(
self,
handles: GenericBufferHandles,
Expand All @@ -125,7 +140,10 @@ impl CaptureQueueable<GenericBufferHandles> for GenericQBuffer<'_, Capture> {
}

/// Any OUTPUT GenericQBuffer implements OutputQueueable.
impl OutputQueueable<GenericBufferHandles> for GenericQBuffer<'_, Output> {
impl<Q> OutputQueueable<GenericBufferHandles> for GenericQBuffer<Output, Q>
where
Q: Deref<Target = Queue<Output, BuffersAllocated<GenericBufferHandles>>>,
{
fn queue_with_handles(
self,
handles: GenericBufferHandles,
Expand Down
33 changes: 21 additions & 12 deletions lib/src/device/queue/qbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::{BufferState, BufferStateFuse, BuffersAllocated, 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,
Expand Down Expand Up @@ -61,8 +62,13 @@ pub type QueueResult<R, B: BufferHandles> = std::result::Result<R, QueueError<B>
/// queue or device cannot be changed while it is being used. Contrary to
/// DQBuffer which can be freely duplicated and passed around, instances of this
/// struct are supposed to be short-lived.
pub struct QBuffer<'a, D: Direction, P: PrimitiveBufferHandles, B: BufferHandles + From<P>> {
queue: &'a Queue<D, BuffersAllocated<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,
Expand All @@ -71,16 +77,14 @@ pub struct QBuffer<'a, D: Direction, P: PrimitiveBufferHandles, B: BufferHandles
_p: std::marker::PhantomData<P>,
}

impl<'a, D, P, B> QBuffer<'a, D, P, B>
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: &'a Queue<D, BuffersAllocated<B>>,
buffer_info: &Arc<BufferInfo<B>>,
) -> Self {
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));

Expand Down Expand Up @@ -159,11 +163,12 @@ where
}
}

impl<'a, P, B> QBuffer<'a, Output, P, B>
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)?;
Expand Down Expand Up @@ -203,10 +208,11 @@ pub trait OutputQueueableProvider<'a, B: BufferHandles> {
}

/// Any CAPTURE QBuffer implements CaptureQueueable.
impl<P, B> CaptureQueueable<B> for QBuffer<'_, Capture, P, B>
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() {
Expand All @@ -233,10 +239,11 @@ where
}

/// Any OUTPUT QBuffer implements OutputQueueable.
impl<P, B> OutputQueueable<B> for QBuffer<'_, Output, P, B>
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() {
Expand Down Expand Up @@ -280,11 +287,12 @@ where
/// empty handles.
/// Since we don't receive plane handles, we also don't need to return any, so
/// the returned error can be simplified.
impl<P, B> QBuffer<'_, Capture, P, B>
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())
Expand All @@ -300,11 +308,12 @@ where
/// empty handles.
/// Since we don't receive plane handles, we also don't need to return any, so
/// the returned error can be simplified.
impl<P, B> QBuffer<'_, Output, P, B>
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> {
// TODO make specific error for bytes_used?
Expand Down

0 comments on commit d4af16d

Please sign in to comment.