diff --git a/src/ipred_prepare.rs b/src/ipred_prepare.rs index a712a985b..60d5c610f 100644 --- a/src/ipred_prepare.rs +++ b/src/ipred_prepare.rs @@ -1,5 +1,6 @@ use crate::include::common::bitdepth::AsPrimitive; use crate::include::common::bitdepth::BitDepth; +use crate::include::dav1d::picture::Rav1dPictureDataComponent; use crate::src::align::AlignedVec64; use crate::src::const_fn::const_for; use crate::src::disjoint_mut::DisjointMut; @@ -24,7 +25,6 @@ use crate::src::levels::Z1_PRED; use crate::src::levels::Z2_PRED; use crate::src::levels::Z3_PRED; use bitflags::bitflags; -use libc::ptrdiff_t; use std::cmp; use std::ffi::c_int; @@ -117,6 +117,49 @@ static av1_intra_prediction_edges: [av1_intra_prediction_edge; N_IMPL_INTRA_PRED b }; +/// Luma intra edge preparation. +/// +/// `x`/`y`/`start`/`w`/`h` are in luma block (4px) units: +/// +/// - `x` and `y` are the absolute block positions in the image; +/// - `start`/`w`/`h` are the *dependent tile* boundary positions. +/// In practice, `start` is the horizontal tile start, +/// `w` is the horizontal tile end, +/// the vertical tile start is assumed to be `0`, +/// and `h` is the vertical image end. +/// +/// `edge_flags` signals which edges are available +/// for this transform-block inside the given partition, +/// as well as for the partition inside the superblock structure. +/// +/// `dst` and `stride` are pointers to the top/left position of the current block, +/// and can be used to locate the top, left, top/left, top/right, +/// and bottom/left edge pointers also. +/// +/// `angle` is the `angle_delta` `[-3..3]` on input, +/// and the absolute angle on output. +/// +/// `mode` is the intra prediction mode as coded in the bitstream. +/// The return value is this same mode, +/// converted to an index in the DSP functions. +/// +/// `tw`/`th` are the size of the transform block in block (4px) units. +/// +/// `topleft_out` is a pointer to scratch memory +/// that will be filled with the edge pixels. +/// The memory array should have space to be indexed +/// in the `-2 * w..=2 * w` range, in the following order: +/// +/// - `[0]` will be the top/left edge pixel +/// - `[1..w]` will be the top edge pixels (`1` being left-most, `w` being right-most) +/// - `[w + 1..2 * w]` will be the top/right edge pixels +/// - `[-1..-w]` will be the left edge pixels (`-1` being top-most, `-w` being bottom-most) +/// - `[-w - 1..-2 * w]` will be the bottom/left edge pixels +/// +/// Each edge may remain uninitialized if it is not used by the returned mode index. +/// If edges are not available (because the edge position +/// is outside the tile dimensions or because edge_flags indicates lack of edge availability), +/// they will be extended from nearby edges as defined by the AV1 spec. pub fn rav1d_prepare_intra_edges( x: c_int, have_left: bool, @@ -125,8 +168,8 @@ pub fn rav1d_prepare_intra_edges( w: c_int, h: c_int, edge_flags: EdgeFlags, - dst: &[BD::Pixel], // contains 4*h first rows of picture, last row in slice contains 4*w samples - stride: ptrdiff_t, + dst: &Rav1dPictureDataComponent, + dst_offset: usize, // Buffer and offset pair. `isize` value is the base offset that should be used // when indexing into the buffer. prefilter_toplevel_sb_edge: Option<(&DisjointMut>, isize)>, @@ -142,10 +185,7 @@ pub fn rav1d_prepare_intra_edges( assert!(y < h && x < w); let bitdepth = bd.bitdepth(); - let stride = BD::pxstride(stride); - - let dst_offset = 4 * x as usize - + (if stride >= 0 { 4 * y } else { 4 * (h - y) - 1 }) as usize * stride.unsigned_abs(); + let stride = dst.pixel_stride::(); match mode { VERT_PRED..=VERT_LEFT_PRED => { @@ -174,6 +214,7 @@ pub fn rav1d_prepare_intra_edges( // `dst_top` starts with either the top or top-left sample depending on whether have_left is true let edge_buf_guard; + let dst_guard; let dst_top = if have_top && (av1_intra_prediction_edges[mode as usize] .needs @@ -190,10 +231,12 @@ pub fn rav1d_prepare_intra_edges( let n = px_have + have_left as usize; if let Some((edge_buf, base)) = prefilter_toplevel_sb_edge { let offset = ((x * 4) as usize - have_left as usize).wrapping_add_signed(base); - edge_buf_guard = edge_buf.slice_as(offset..offset + n); - &edge_buf_guard + edge_buf_guard = edge_buf.slice_as((offset.., ..n)); + &*edge_buf_guard } else { - &dst[(dst_offset as isize - stride) as usize - have_left as usize..][..n] + let offset = dst_offset.wrapping_add_signed(-stride) - have_left as usize; + dst_guard = dst.slice::((offset.., ..n)); + &*dst_guard } } else { &[] @@ -208,7 +251,8 @@ pub fn rav1d_prepare_intra_edges( if have_left { let px_have = cmp::min(sz, (h - y << 2) as usize); for i in 0..px_have { - left[sz - 1 - i] = dst[(i as isize * stride + dst_offset as isize - 1) as usize]; + left[sz - 1 - i] = + *dst.index::(dst_offset.wrapping_add_signed(i as isize * stride) - 1); } if px_have < sz { BD::pixel_set(left, left[sz - px_have], sz - px_have); @@ -237,8 +281,9 @@ pub fn rav1d_prepare_intra_edges( if have_bottomleft { let px_have = cmp::min(sz, (h - y - th << 2) as usize); for i in 0..px_have { - bottom_left[sz - 1 - i] = - dst[((sz + i) as isize * stride + dst_offset as isize - 1) as usize]; + bottom_left[sz - 1 - i] = *dst.index::( + dst_offset.wrapping_add_signed((sz + i) as isize * stride) - 1, + ); } if px_have < sz { BD::pixel_set(bottom_left, bottom_left[sz - px_have], sz - px_have); @@ -265,7 +310,7 @@ pub fn rav1d_prepare_intra_edges( BD::pixel_set( top, if have_left { - dst[dst_offset - 1] + *dst.index::(dst_offset - 1) } else { ((1 << bitdepth >> 1) - 1).as_::() }, @@ -305,7 +350,7 @@ pub fn rav1d_prepare_intra_edges( corner[1] = if have_top { dst_top[0] } else if have_left { - dst[dst_offset - 1] + *dst.index::(dst_offset - 1) } else { (1 << bitdepth >> 1).as_::() }; diff --git a/src/recon.rs b/src/recon.rs index f46e51628..bbdc89c14 100644 --- a/src/recon.rs +++ b/src/recon.rs @@ -2618,16 +2618,6 @@ pub(crate) unsafe fn rav1d_recon_b_intra( .edge .buf_mut::(); let edge_offset = 128; - let data_stride = BD::pxstride(f.cur.stride[0]); - let data_width = 4 * ts.tiling.col_end; - let data_height = 4 * ts.tiling.row_end; - let data_diff = (data_height - 1) as isize * data_stride; - let dst_slice = slice::from_raw_parts( - cur_data[0] - .as_strided_ptr::() - .offset(cmp::min(data_diff, 0)), - data_diff.unsigned_abs() + data_width as usize, - ); m = rav1d_prepare_intra_edges( t.b.x, t.b.x > ts.tiling.col_start, @@ -2636,8 +2626,8 @@ pub(crate) unsafe fn rav1d_recon_b_intra( ts.tiling.col_end, ts.tiling.row_end, edge_flags, - dst_slice, - f.cur.stride[0], + y_dst, + y_dst_offset, top_sb_edge_slice, intra.y_mode as IntraPredMode, &mut angle, @@ -2855,15 +2845,10 @@ pub(crate) unsafe fn rav1d_recon_b_intra( let ystart = ts.tiling.row_start >> ss_ver; let edge_array = scratch.interintra_edge_pal.edge.buf_mut::(); let edge_offset = 128; - let data_stride = BD::pxstride(f.cur.stride[1]); - let data_width = 4 * ts.tiling.col_end >> ss_hor; - let data_height = 4 * ts.tiling.row_end >> ss_ver; - let data_diff = (data_height - 1) as isize * data_stride; - let uvdst_slice = slice::from_raw_parts( - cur_data[1 + pl] - .as_strided_ptr::() - .offset(cmp::min(data_diff, 0)), - data_diff.unsigned_abs() + data_width as usize, + let uv_dst = &cur_data[1 + pl]; + let uv_dst_offset = uv_dst.pixel_offset::().wrapping_add_signed( + 4 * ((t.b.x >> ss_hor) as isize + + (t.b.y >> ss_ver) as isize * uv_dst.pixel_stride::()), ); let m: IntraPredMode = rav1d_prepare_intra_edges( xpos, @@ -2873,8 +2858,8 @@ pub(crate) unsafe fn rav1d_recon_b_intra( ts.tiling.col_end >> ss_hor, ts.tiling.row_end >> ss_ver, EdgeFlags::empty(), - uvdst_slice, - stride, + uv_dst, + uv_dst_offset, top_sb_edge_slice, DC_PRED, &mut angle, @@ -2885,11 +2870,6 @@ pub(crate) unsafe fn rav1d_recon_b_intra( edge_offset, bd, ); - let uv_dst = &cur_data[1 + pl]; - let uv_dst_offset = uv_dst.pixel_offset::().wrapping_add_signed( - 4 * ((t.b.x >> ss_hor) as isize - + (t.b.y >> ss_ver) as isize * uv_dst.pixel_stride::()), - ); f.dsp.ipred.cfl_pred[m as usize].call( uv_dst, uv_dst_offset, @@ -3064,16 +3044,6 @@ pub(crate) unsafe fn rav1d_recon_b_intra( .edge .buf_mut::(); let edge_offset = 128; - let data_stride = BD::pxstride(f.cur.stride[1]); - let data_width = 4 * ts.tiling.col_end >> ss_hor; - let data_height = 4 * ts.tiling.row_end >> ss_ver; - let data_diff = (data_height - 1) as isize * data_stride; - let dstuv_slice = slice::from_raw_parts( - cur_data[1 + pl] - .as_strided_ptr::() - .offset(cmp::min(data_diff, 0)), - data_diff.unsigned_abs() + data_width as usize, - ); m = rav1d_prepare_intra_edges( xpos, xpos > xstart, @@ -3082,8 +3052,8 @@ pub(crate) unsafe fn rav1d_recon_b_intra( ts.tiling.col_end >> ss_hor, ts.tiling.row_end >> ss_ver, edge_flags, - dstuv_slice, - stride, + uv_dst, + uv_dst_offset, top_sb_edge_slice, uv_mode, &mut angle, @@ -3300,6 +3270,10 @@ pub(crate) unsafe fn rav1d_recon_b_inter( let mut dst = cur_data[0] .as_strided_mut_ptr::() .offset(4 * (t.b.y as isize * BD::pxstride(f.cur.stride[0]) + t.b.x as isize)); + let y_dst = &cur_data[0]; + let mut y_dst_offset = y_dst + .pixel_offset::() + .wrapping_add_signed(4 * (t.b.y as isize * y_dst.pixel_stride::() + t.b.x as isize)); let uvdstoff = 4 * ((t.b.x >> ss_hor) as isize + (t.b.y >> ss_ver) as isize * BD::pxstride(f.cur.stride[1])); let frame_hdr = &***f.frame_hdr.as_ref().unwrap(); @@ -3608,16 +3582,6 @@ pub(crate) unsafe fn rav1d_recon_b_inter( } else { None }; - let data_stride = BD::pxstride(f.cur.stride[0]); - let data_width = 4 * ts.tiling.col_end; - let data_height = 4 * ts.tiling.row_end; - let data_diff = (data_height - 1) as isize * data_stride; - let dst_slice = slice::from_raw_parts( - cur_data[0] - .as_strided_ptr::() - .offset(cmp::min(data_diff, 0)), - data_diff.unsigned_abs() + data_width as usize, - ); m = rav1d_prepare_intra_edges( t.b.x, t.b.x > ts.tiling.col_start, @@ -3626,8 +3590,8 @@ pub(crate) unsafe fn rav1d_recon_b_inter( ts.tiling.col_end, ts.tiling.row_end, EdgeFlags::empty(), - dst_slice, - f.cur.stride[0], + y_dst, + y_dst_offset, top_sb_edge_slice, m, &mut angle, @@ -3918,6 +3882,9 @@ pub(crate) unsafe fn rav1d_recon_b_inter( mode => mode as IntraPredMode, }; let mut angle = 0; + let uv_dst = &cur_data[1 + pl]; + let uv_dst_offset = + uv_dst.pixel_offset::().wrapping_add_signed(uvdstoff); let uvdst = cur_data[1 + pl].as_strided_mut_ptr::().offset(uvdstoff); let top_sb_edge_slice = if t.b.y & f.sb_step - 1 == 0 { let sby = t.b.y >> f.sb_shift; @@ -3927,26 +3894,16 @@ pub(crate) unsafe fn rav1d_recon_b_inter( } else { None }; - let data_stride = BD::pxstride(f.cur.stride[1]); - let data_width = 4 * ts.tiling.col_end >> ss_hor; - let data_height = 4 * ts.tiling.row_end >> ss_ver; - let data_diff = (data_height - 1) as isize * data_stride; - let dstuv_slice = slice::from_raw_parts( - cur_data[1 + pl] - .as_strided_ptr::() - .offset(cmp::min(data_diff, 0)), - data_diff.unsigned_abs() + data_width as usize, - ); m = rav1d_prepare_intra_edges( t.b.x >> ss_hor, - t.b.x >> ss_hor > ts.tiling.col_start >> ss_hor, + (t.b.x >> ss_hor) > (ts.tiling.col_start >> ss_hor), t.b.y >> ss_ver, - t.b.y >> ss_ver > ts.tiling.row_start >> ss_ver, + (t.b.y >> ss_ver) > (ts.tiling.row_start >> ss_ver), ts.tiling.col_end >> ss_hor, ts.tiling.row_end >> ss_ver, EdgeFlags::empty(), - dstuv_slice, - f.cur.stride[1], + uv_dst, + uv_dst_offset, top_sb_edge_slice, m, &mut angle, @@ -4048,6 +4005,8 @@ pub(crate) unsafe fn rav1d_recon_b_inter( // coefficient coding & inverse transforms let mut y_off = (init_y != 0) as c_int; let mut y; + y_dst_offset = + y_dst_offset.wrapping_add_signed(y_dst.pixel_stride::() * 4 * init_y as isize); dst = dst.offset(BD::pxstride(f.cur.stride[0]) * 4 * init_y as isize); y = init_y; t.b.y += init_y; @@ -4074,12 +4033,16 @@ pub(crate) unsafe fn rav1d_recon_b_inter( x += ytx.w as c_int; x_off += 1; } + y_dst_offset = y_dst_offset + .wrapping_add_signed(y_dst.pixel_stride::() * 4 * ytx.h as isize); dst = dst.offset(BD::pxstride(f.cur.stride[0]) * 4 * ytx.h as isize); t.b.x -= x; t.b.y += ytx.h as c_int; y += ytx.h as c_int; y_off += 1; } + y_dst_offset = + y_dst_offset.wrapping_add_signed(y_dst.pixel_stride::() * 4 * y as isize); dst = dst.offset(-BD::pxstride(f.cur.stride[0]) * 4 * y as isize); t.b.y -= y;