Skip to content

Commit

Permalink
struct Rav1dData{,Props}: Replace Rav1dRefs with CArcs.
Browse files Browse the repository at this point in the history
  • Loading branch information
kkysen committed Dec 19, 2023
1 parent 6d8411f commit 3e3208a
Show file tree
Hide file tree
Showing 16 changed files with 606 additions and 462 deletions.
48 changes: 14 additions & 34 deletions include/dav1d/common.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,29 @@
use crate::include::dav1d::dav1d::Dav1dRef;
use crate::src::r#ref::Rav1dRef;
use std::ptr;
use crate::src::c_arc::CArc;
use crate::src::c_arc::RawCArc;
use std::ptr::NonNull;

#[derive(Default)]
#[repr(C)]
pub struct Dav1dUserData {
pub data: *const u8,
pub r#ref: *mut Dav1dRef,
pub data: Option<NonNull<u8>>,
pub r#ref: Option<RawCArc<u8>>, // opaque, so we can change this
}

impl Default for Dav1dUserData {
fn default() -> Self {
Self {
data: ptr::null(),
r#ref: ptr::null_mut(),
}
}
}

#[derive(Clone)]
#[repr(C)]
pub(crate) struct Rav1dUserData {
pub data: *const u8,
pub r#ref: *mut Rav1dRef,
}

impl Default for Rav1dUserData {
fn default() -> Self {
Self {
data: ptr::null(),
r#ref: ptr::null_mut(),
}
}
}
pub(crate) type Rav1dUserData = Option<CArc<u8>>;

impl From<Dav1dUserData> for Rav1dUserData {
fn from(value: Dav1dUserData) -> Self {
let Dav1dUserData { data, r#ref } = value;
Self { data, r#ref }
let Dav1dUserData { data: _, r#ref } = value;
r#ref.map(|r#ref| unsafe { CArc::from_raw(r#ref) })
}
}

impl From<Rav1dUserData> for Dav1dUserData {
fn from(value: Rav1dUserData) -> Self {
let Rav1dUserData { data, r#ref } = value;
Self { data, r#ref }
Self {
data: value.as_ref().map(|user_data| user_data.as_ref().into()),
r#ref: value.map(|user_data| user_data.into_raw()),
}
}
}

Expand All @@ -57,7 +37,7 @@ pub struct Dav1dDataProps {
pub user_data: Dav1dUserData,
}

#[derive(Clone)]
#[derive(Clone, Debug)]
#[repr(C)]
pub(crate) struct Rav1dDataProps {
pub timestamp: i64,
Expand Down
61 changes: 22 additions & 39 deletions include/dav1d/data.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,50 @@
use crate::include::dav1d::common::Dav1dDataProps;
use crate::include::dav1d::common::Rav1dDataProps;
use crate::include::dav1d::dav1d::Dav1dRef;
use crate::src::r#ref::Rav1dRef;
use std::ptr;
use crate::src::c_arc::CArc;
use crate::src::c_arc::RawCArc;
use std::ptr::NonNull;
use to_method::To as _;

#[derive(Default)]
#[repr(C)]
pub struct Dav1dData {
pub data: *const u8,
pub data: Option<NonNull<u8>>,
pub sz: usize,
pub r#ref: *mut Dav1dRef,
pub r#ref: Option<RawCArc<[u8]>>, // opaque, so we can change this
pub m: Dav1dDataProps,
}

impl Default for Dav1dData {
fn default() -> Self {
Self {
data: ptr::null(),
sz: Default::default(),
r#ref: ptr::null_mut(),
m: Default::default(),
}
}
}

#[derive(Clone)]
#[derive(Clone, Default)]
#[repr(C)]
pub(crate) struct Rav1dData {
pub data: *const u8,
pub sz: usize,
pub r#ref: *mut Rav1dRef,
pub data: Option<CArc<[u8]>>,
pub m: Rav1dDataProps,
}

impl Default for Rav1dData {
fn default() -> Self {
Self {
data: ptr::null(),
sz: Default::default(),
r#ref: ptr::null_mut(),
m: Default::default(),
}
}
}

impl From<Dav1dData> for Rav1dData {
fn from(value: Dav1dData) -> Self {
let Dav1dData { data, sz, r#ref, m } = value;
Self {
data,
sz,
let Dav1dData {
data: _,
sz: _,
r#ref,
m,
} = value;
Self {
data: r#ref.map(|r#ref| unsafe { CArc::from_raw(r#ref) }),
m: m.into(),
}
}
}

impl From<Rav1dData> for Dav1dData {
fn from(value: Rav1dData) -> Self {
let Rav1dData { data, sz, r#ref, m } = value;
let Rav1dData { data, m } = value;
Self {
data,
sz,
r#ref,
data: data
.as_ref()
.map(|data| data.as_ref().to::<NonNull<[u8]>>().cast()),
sz: data.as_ref().map(|data| data.len()).unwrap_or_default(),
r#ref: data.map(|data| data.into_raw()),
m: m.into(),
}
}
Expand Down
4 changes: 3 additions & 1 deletion include/dav1d/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,10 @@ impl From<Rav1dWarpedMotionParams> for Dav1dWarpedMotionParams {
}
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, EnumCount, FromRepr, Debug)]
// TODO(kkysen) Eventually the [`impl Default`] might not be needed.
#[derive(Clone, Copy, PartialEq, Eq, Hash, EnumCount, FromRepr, Debug, Default)]
pub(crate) enum Rav1dPixelLayout {
#[default]
I400 = 0,
I420 = 1,
I422 = 2,
Expand Down
31 changes: 29 additions & 2 deletions include/dav1d/picture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ pub struct Dav1dPictureParameters {
pub bpc: c_int,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
// TODO(kkysen) Eventually the [`impl Default`] might not be needed.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
#[repr(C)]
pub(crate) struct Rav1dPictureParameters {
pub w: c_int,
Expand Down Expand Up @@ -85,7 +86,7 @@ pub struct Dav1dPicture {
pub allocator_data: *mut c_void,
}

#[derive(Clone)]
#[derive(Clone, Debug)]
#[repr(C)]
pub(crate) struct Rav1dPicture {
pub seq_hdr: *mut Rav1dSequenceHeader,
Expand Down Expand Up @@ -274,6 +275,32 @@ impl From<Rav1dPicture> for Dav1dPicture {
}
}

// TODO(kkysen) Eventually the [`impl Default`] might not be needed.
impl Default for Rav1dPicture {
fn default() -> Self {
Self {
seq_hdr: ptr::null_mut(),
frame_hdr: ptr::null_mut(),
data: [ptr::null_mut(); 3],
stride: Default::default(),
p: Default::default(),
m: Default::default(),
content_light: ptr::null_mut(),
mastering_display: ptr::null_mut(),
itut_t35: ptr::null_mut(),
reserved: Default::default(),
frame_hdr_ref: ptr::null_mut(),
seq_hdr_ref: ptr::null_mut(),
content_light_ref: ptr::null_mut(),
mastering_display_ref: ptr::null_mut(),
itut_t35_ref: ptr::null_mut(),
reserved_ref: Default::default(),
r#ref: ptr::null_mut(),
allocator_data: ptr::null_mut(),
}
}
}

#[derive(Clone)]
#[repr(C)]
pub struct Dav1dPicAllocator {
Expand Down
2 changes: 2 additions & 0 deletions lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub mod include {
pub mod src {
pub mod align;
mod assume;
pub(crate) mod c_arc;
pub(crate) mod c_box;
mod cdef;
#[cfg_attr(not(feature = "bitdepth_16"), allow(dead_code))]
mod cdef_apply_tmpl_16;
Expand Down
122 changes: 122 additions & 0 deletions src/c_arc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use crate::src::c_box::CBox;
use crate::src::error::Rav1dResult;
use std::marker::PhantomData;
use std::ops::AddAssign;
use std::ops::Deref;
use std::ptr::NonNull;
use std::sync::Arc;

/// A C/custom [`Arc`].
///
/// That is, it is analogous to an [`Arc`],
/// but it lets you set a C-style `free` `fn` for deallocation
/// instead of the normal [`Box`] (de)allocator.
/// It can also store a normal [`Box`] as well.
///
/// It is built around the [`CBox`] abstraction.
/// However, that necessitates a double indirection
/// to reach the ptr through the [`Arc`] and [`CBox`].
/// To remedy this and improve performance,
/// a stable pointer is stored inline,
/// removing the double indirection.
/// This self-referential ptr is sound
/// because [`Arc`] and [`Box`]/[`CBox`]
/// never move their data ptr during moves, as it's on the heap.
/// As long as [`Self::owner`] is never moved
/// without also re-updating [`Self::stable_ref`], this is sound.
///
/// Furthermore, storing this stable ref ptr like this
/// allows for provenance projections of [`Self::stable_ref`],
/// such as slicing it for a `CArc<[T]>`.
#[derive(Debug)]
pub struct CArc<T: ?Sized> {
owner: Arc<CBox<T>>,
stable_ref: NonNull<T>,
}

impl<T: ?Sized> AsRef<T> for CArc<T> {
fn as_ref(&self) -> &T {
// Safety: [`Self::stable_ref`] is a ptr
// derived from [`Self::owner`]'s through [`CBox::as_ref`]
// and is thus safe to dereference.
unsafe { self.stable_ref.as_ref() }
}
}

impl<T: ?Sized> Deref for CArc<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
self.as_ref()
}
}

impl<T: ?Sized> Clone for CArc<T> {
fn clone(&self) -> Self {
let Self { owner, stable_ref } = self;
Self {
owner: owner.clone(),
// Safety: The ref remains stable across an [`Arc::clone`].
stable_ref: stable_ref.clone(),
}
}
}

impl<T: ?Sized> From<Arc<CBox<T>>> for CArc<T> {
fn from(owner: Arc<CBox<T>>) -> Self {
let stable_ref = (*owner).as_ref().into();
Self { owner, stable_ref }
}
}

impl<T: ?Sized> CArc<T> {
pub fn wrap(owner: CBox<T>) -> Rav1dResult<Self> {
let owner = Arc::new(owner); // TODO fallible allocation
Ok(owner.into())
}
}

/// An opaque, raw [`CArc`], which is represented as a [`NonNull`] ptr to a [`CBox`].
///
/// To keep the type FFI-safe, a [`PhantomData`] wrapper is used,
/// but the ptr is actually a [`CBox`].
#[repr(transparent)]
pub struct RawCArc<T: ?Sized>(NonNull<PhantomData<CBox<T>>>);

impl<T: ?Sized> CArc<T> {
/// Convert into a raw, opaque form suitable for C FFI.
pub fn into_raw(self) -> RawCArc<T> {
let raw = Arc::into_raw(self.owner);
// Safety: [`Arc::into_raw`] guarantees it always returns non-null ptrs.
let raw = unsafe { NonNull::new_unchecked(raw.cast_mut()) };
RawCArc(raw.cast())
}

/// # Safety
///
/// The [`RawCArc`] must be originally from [`Self::into_raw`].
#[deny(unsafe_op_in_unsafe_fn)]
pub unsafe fn from_raw(raw: RawCArc<T>) -> Self {
// Safety: The [`RawCArc`] contains the output of [`Arc::into_raw`],
// so we can call [`Arc::from_raw`] on it.
let owner = unsafe { Arc::from_raw(raw.0.cast::<CBox<T>>().as_ptr()) };
owner.into()
}
}

impl<T> AddAssign<usize> for CArc<[T]> {
/// Slice [`Self::stable_ref`].
fn add_assign(&mut self, rhs: usize) {
self.stable_ref = self[rhs..].into();
}
}

impl<T> CArc<[T]>
where
T: Default + 'static,
{
pub fn zeroed_slice(size: usize) -> Rav1dResult<Self> {
let owned_slice = (0..size).map(|_| Default::default()).collect::<Box<[_]>>(); // TODO fallible allocation
Self::wrap(CBox::from_box(owned_slice))
}
}
Loading

0 comments on commit 3e3208a

Please sign in to comment.