Skip to content

Commit

Permalink
struct Rav1dContext: Make frame contexts a Box<[_]> (#1000)
Browse files Browse the repository at this point in the history
Replaces the C allocation and `fc` array pointer of `Rav1dFrameContext`
structures with a Rust boxed slice.
  • Loading branch information
rinon authored Apr 25, 2024
2 parents f4578a2 + b83c712 commit 502452a
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 181 deletions.
44 changes: 20 additions & 24 deletions src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3890,7 +3890,7 @@ pub(crate) unsafe fn rav1d_decode_tile_sbrow(
);
}

if frame_hdr.frame_type.is_inter_or_switch() && c.n_fc > 1 {
if frame_hdr.frame_type.is_inter_or_switch() && c.fc.len() > 1 {
let sby = t.b.y - ts.tiling.row_start >> f.sb_shift;
*f.lowest_pixel_mem.index_mut(ts.lowest_pixel + sby as usize) = [[i32::MIN; 2]; 7];
}
Expand Down Expand Up @@ -4098,7 +4098,7 @@ pub(crate) unsafe fn rav1d_decode_frame_init(

let n_ts = frame_hdr.tiling.cols * frame_hdr.tiling.rows;
if n_ts != f.n_ts {
if c.n_fc > 1 {
if c.fc.len() > 1 {
// TODO: Fallible allocation
f.frame_thread.tile_start_off.resize(n_ts as usize, 0);
}
Expand All @@ -4111,15 +4111,15 @@ pub(crate) unsafe fn rav1d_decode_frame_init(
f.n_ts = n_ts;
}

let a_sz = f.sb128w * frame_hdr.tiling.rows * (1 + (c.n_fc > 1 && c.tc.len() > 1) as c_int);
let a_sz = f.sb128w * frame_hdr.tiling.rows * (1 + (c.fc.len() > 1 && c.tc.len() > 1) as c_int);
// TODO: Fallible allocation
f.a.resize_with(a_sz as usize, Default::default);

let num_sb128 = f.sb128w * f.sb128h;
let size_mul = &ss_size_mul[f.cur.p.layout];
let seq_hdr = &***f.seq_hdr.as_ref().unwrap();
let hbd = (seq_hdr.hbd != 0) as c_int;
if c.n_fc > 1 {
if c.fc.len() > 1 {
let mut tile_idx = 0;
let sb_step4 = f.sb_step as u32 * 4;
for tile_row in 0..frame_hdr.tiling.rows {
Expand Down Expand Up @@ -4286,7 +4286,7 @@ pub(crate) unsafe fn rav1d_decode_frame_init(
// index this from the level type and can thus over-read by up to 3 bytes.
f.lf.level
.resize(num_sb128 as usize * 32 * 32 + 1, [0u8; 4]); // TODO: Fallible allocation
if c.n_fc > 1 {
if c.fc.len() > 1 {
// TODO: Fallible allocation
f.frame_thread
.b
Expand Down Expand Up @@ -4348,7 +4348,7 @@ pub(crate) unsafe fn rav1d_decode_frame_init(
&f.refrefpoc,
&f.ref_mvs,
c.tc.len() as u32,
c.n_fc,
c.fc.len() as u32,
)?;
}

Expand Down Expand Up @@ -4423,7 +4423,7 @@ pub(crate) unsafe fn rav1d_decode_frame_init_cdf(
rav1d_cdf_thread_copy(&mut f.out_cdf.cdf_write(), in_cdf);
}

let uses_2pass = c.n_fc > 1;
let uses_2pass = c.fc.len() > 1;

let tiling = &frame_hdr.tiling;

Expand Down Expand Up @@ -4592,7 +4592,7 @@ pub(crate) unsafe fn rav1d_decode_frame_exit(
task_thread.error.store(0, Ordering::Relaxed);
}
let cf = f.frame_thread.cf.get_mut();
if c.n_fc > 1 && retval.is_err() && !cf.is_empty() {
if c.fc.len() > 1 && retval.is_err() && !cf.is_empty() {
cf.fill_with(Default::default);
}
// TODO(kkysen) use array::zip when stable
Expand Down Expand Up @@ -4628,7 +4628,7 @@ pub(crate) unsafe fn rav1d_decode_frame_exit(
}

pub(crate) unsafe fn rav1d_decode_frame(c: &Rav1dContext, fc: &Rav1dFrameContext) -> Rav1dResult {
assert!(c.n_fc == 1);
assert!(c.fc.len() == 1);
// if.tc.len() > 1 (but n_fc == 1), we could run init/exit in the task
// threads also. Not sure it makes a measurable difference.
let mut res = rav1d_decode_frame_init(c, fc);
Expand Down Expand Up @@ -4682,22 +4682,19 @@ fn get_upscale_x0(in_w: c_int, out_w: c_int, step: c_int) -> c_int {

pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
// wait for c->out_delayed[next] and move into c->out if visible
let (fc, out, _task_thread_lock) = if c.n_fc > 1 {
let (fc, out, _task_thread_lock) = if c.fc.len() > 1 {
let mut task_thread_lock = c.task_thread.delayed_fg.lock().unwrap();
let next = c.frame_thread.next;
c.frame_thread.next += 1;
if c.frame_thread.next == c.n_fc {
c.frame_thread.next = 0;
}
c.frame_thread.next = (c.frame_thread.next + 1) % c.fc.len() as u32;

let fc = &(*c.fc.offset(next as isize));
let fc = &c.fc[next as usize];
while !fc.task_thread.finished.load(Ordering::SeqCst) {
task_thread_lock = fc.task_thread.cond.wait(task_thread_lock).unwrap();
}
let out_delayed = &mut c.frame_thread.out_delayed[next as usize];
if out_delayed.p.data.is_some() || fc.task_thread.error.load(Ordering::SeqCst) != 0 {
let first = c.task_thread.first.load(Ordering::SeqCst);
if first + 1 < c.n_fc {
if first as usize + 1 < c.fc.len() {
c.task_thread.first.fetch_add(1, Ordering::SeqCst);
} else {
c.task_thread.first.store(0, Ordering::SeqCst);
Expand All @@ -4710,7 +4707,7 @@ pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
);
// `cur` is not actually mutated from multiple threads concurrently
let cur = c.task_thread.cur.load(Ordering::Relaxed);
if cur != 0 && cur < c.n_fc {
if cur != 0 && (cur as usize) < c.fc.len() {
c.task_thread.cur.fetch_sub(1, Ordering::Relaxed);
}
}
Expand All @@ -4729,7 +4726,7 @@ pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
}
(fc, out_delayed as *mut _, Some(task_thread_lock))
} else {
(&(*c.fc), &mut c.out as *mut _, None)
(&c.fc[0], &mut c.out as *mut _, None)
};

let mut f = fc.data.try_write().unwrap();
Expand Down Expand Up @@ -4834,7 +4831,7 @@ pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
*fc.in_cdf.try_write().unwrap() = c.cdf[pri_ref].clone();
}
if frame_hdr.refresh_context != 0 {
let res = rav1d_cdf_thread_alloc(c, (c.n_fc > 1) as c_int);
let res = rav1d_cdf_thread_alloc(c, (c.fc.len() > 1) as c_int);
match res {
Err(e) => {
on_error(fc, &mut f, c, out);
Expand Down Expand Up @@ -4889,7 +4886,7 @@ pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
}

// move f->cur into output queue
if c.n_fc == 1 {
if c.fc.len() == 1 {
if frame_hdr.show_frame != 0 || c.output_invisible_frames {
c.out = f.sr_cur.clone();
c.event_flags |= f.sr_cur.flags.into();
Expand All @@ -4910,7 +4907,7 @@ pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
f.b4_stride = (f.bw + 31 & !31) as ptrdiff_t;
f.bitdepth_max = (1 << f.cur.p.bpc) - 1;
fc.task_thread.error.store(0, Ordering::Relaxed);
let uses_2pass = (c.n_fc > 1) as c_int;
let uses_2pass = (c.fc.len() > 1) as c_int;
let cols = frame_hdr.tiling.cols;
let rows = frame_hdr.tiling.rows;
fc.task_thread
Expand Down Expand Up @@ -5021,10 +5018,9 @@ pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
c.refs[i].refpoc = f.refpoc;
}
}
let index = f.index;
drop(f);

if c.n_fc == 1 {
if c.fc.len() == 1 {
let res = rav1d_decode_frame(c, &fc);
if res.is_err() {
let _ = mem::take(&mut c.out);
Expand All @@ -5043,7 +5039,7 @@ pub unsafe fn rav1d_submit_frame(c: &mut Rav1dContext) -> Rav1dResult {
return res;
}
} else {
rav1d_task_frame_init(c, fc, index);
rav1d_task_frame_init(c, fc);
}

Ok(())
Expand Down
65 changes: 60 additions & 5 deletions src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,22 @@ pub(crate) struct TaskThreadData_delayed_fg {
pub grain: BitDepthUnion<Grain>,
}

impl Default for TaskThreadData_delayed_fg {
fn default() -> Self {
Self {
exec: 0,
in_0: std::ptr::null(),
out: std::ptr::null_mut(),
type_0: Default::default(),
grain: Default::default(),
}
}
}

// TODO(SJC): Remove when TaskThreadData_delayed_fg is thread-safe
unsafe impl Send for TaskThreadData_delayed_fg {}

#[derive(Default)]
#[repr(C)]
pub(crate) struct TaskThreadData {
pub cond: Condvar,
Expand Down Expand Up @@ -316,8 +329,7 @@ impl Rav1dContextTaskThread {

#[repr(C)]
pub struct Rav1dContext {
pub(crate) fc: *mut Rav1dFrameContext,
pub(crate) n_fc: c_uint,
pub(crate) fc: Box<[Rav1dFrameContext]>,

/// Worker thread join handles and communication, or main thread task
/// context if single-threaded
Expand Down Expand Up @@ -372,6 +384,15 @@ pub struct Rav1dContext {
pub(crate) picture_pool: *mut Rav1dMemPool,
}

impl Rav1dContext {
/// Iterates over all frame contexts in the `fc` buffer, starting at a given
/// index. The iterator wraps around to the start of the buffer. so all
/// contexts will be included.
pub(crate) fn fc_iter(&self, start: usize) -> impl Iterator<Item = &Rav1dFrameContext> {
self.fc.iter().skip(start).chain(self.fc.iter().take(start))
}
}

// TODO(SJC): Remove when Rav1dContext is thread-safe
unsafe impl Send for Rav1dContext {}
// TODO(SJC): Remove when Rav1dContext is thread-safe
Expand Down Expand Up @@ -788,6 +809,26 @@ pub(crate) struct Rav1dFrameContext_task_thread {
pub pending_tasks: Mutex<Rav1dFrameContext_task_thread_pending_tasks>,
}

impl Default for Rav1dFrameContext_task_thread {
fn default() -> Self {
Self {
lock: Default::default(),
cond: Default::default(),
ttd: Default::default(),
tasks: Default::default(),
init_done: Default::default(),
done: Default::default(),
retval: Mutex::new(Ok(())),
finished: Default::default(),
update_set: Default::default(),
error: Default::default(),
task_counter: Default::default(),
pending_tasks_merge: Default::default(),
pending_tasks: Default::default(),
}
}
}

impl Rav1dFrameContext_task_thread {
pub unsafe fn tasks(&self) -> *mut Rav1dTasks {
self.tasks.get()
Expand All @@ -803,13 +844,26 @@ pub(crate) struct Rav1dFrameContext_frame_thread_progress {
}

pub(crate) struct Rav1dFrameContext {
/// Index in [`Rav1dContext::fc`]
pub index: usize,

pub data: RwLock<Rav1dFrameData>,
pub in_cdf: RwLock<CdfThreadContext>,
pub task_thread: Rav1dFrameContext_task_thread,
pub frame_thread_progress: Rav1dFrameContext_frame_thread_progress,
}

impl Rav1dFrameContext {
pub(crate) unsafe fn zeroed(index: usize) -> Self {
Self {
index,
data: RwLock::new(unsafe { Rav1dFrameData::zeroed() }),
in_cdf: Default::default(),
task_thread: Default::default(),
frame_thread_progress: Default::default(),
}
}

pub fn in_cdf<'a>(&'a self) -> RwLockReadGuard<'a, CdfThreadContext> {
self.in_cdf.try_read().unwrap()
}
Expand All @@ -827,9 +881,6 @@ impl Rav1dFrameContext {

#[repr(C)]
pub(crate) struct Rav1dFrameData {
/// Index in [`Rav1dContext::fc`]
pub index: usize,

pub seq_hdr: Option<Arc<DRav1d<Rav1dSequenceHeader, Dav1dSequenceHeader>>>,
pub frame_hdr: Option<Arc<DRav1d<Rav1dFrameHeader, Dav1dFrameHeader>>>,
pub refp: [Rav1dThreadPicture; 7],
Expand Down Expand Up @@ -884,9 +935,13 @@ pub(crate) struct Rav1dFrameData {
impl Rav1dFrameData {
pub unsafe fn zeroed() -> Self {
let mut data: MaybeUninit<Rav1dFrameData> = MaybeUninit::zeroed();
addr_of_mut!((*data.as_mut_ptr()).refp).write(Default::default());
addr_of_mut!((*data.as_mut_ptr()).cur).write(Default::default());
addr_of_mut!((*data.as_mut_ptr()).sr_cur).write(Default::default());
addr_of_mut!((*data.as_mut_ptr()).out_cdf).write(Default::default());
addr_of_mut!((*data.as_mut_ptr()).tiles).write(vec![]);
addr_of_mut!((*data.as_mut_ptr()).a).write(vec![]);
addr_of_mut!((*data.as_mut_ptr()).rf).write(Default::default());
addr_of_mut!((*data.as_mut_ptr()).lowest_pixel_mem).write(Default::default());
addr_of_mut!((*data.as_mut_ptr()).frame_thread).write(Default::default());
addr_of_mut!((*data.as_mut_ptr()).lf).write(Default::default());
Expand Down
Loading

0 comments on commit 502452a

Please sign in to comment.