me.rs 15.6 KB
Newer Older
1 2 3 4 5 6 7 8 9
// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

Raphaël Zumer's avatar
Raphaël Zumer committed
10 11 12 13
#[cfg(all(target_arch = "x86_64", not(windows), feature = "nasm"))]
pub use self::nasm::get_sad;
#[cfg(any(not(target_arch = "x86_64"), windows, not(feature = "nasm")))]
pub use self::native::get_sad;
Raphaël Zumer's avatar
Raphaël Zumer committed
14 15 16 17 18
use crate::context::{BlockOffset, BLOCK_TO_PLANE_SHIFT, MI_SIZE};
use crate::FrameInvariants;
use crate::FrameState;
use crate::partition::*;
use crate::plane::*;
19

20 21
#[cfg(all(target_arch = "x86_64", not(windows), feature = "nasm"))]
mod nasm {
Raphaël Zumer's avatar
Raphaël Zumer committed
22 23
  use crate::plane::*;
  use crate::util::*;
Luca Barbato's avatar
Luca Barbato committed
24

Raphaël Zumer's avatar
Raphaël Zumer committed
25 26
  use libc;

Luca Barbato's avatar
Luca Barbato committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
  extern {
    fn rav1e_sad_4x4_hbd_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_8x8_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_16x16_hbd_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_32x32_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_64x64_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;

    fn rav1e_sad_128x128_hbd10_ssse3(
      src: *const u16, src_stride: libc::ptrdiff_t, dst: *const u16,
      dst_stride: libc::ptrdiff_t
    ) -> u32;
  }
Kyle Siefring's avatar
Kyle Siefring committed
58

Luca Barbato's avatar
Luca Barbato committed
59 60
  #[target_feature(enable = "ssse3")]
  unsafe fn sad_ssse3(
61
    plane_org: &PlaneSlice<'_>, plane_ref: &PlaneSlice<'_>, blk_h: usize,
Luca Barbato's avatar
Luca Barbato committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    blk_w: usize, bit_depth: usize
  ) -> u32 {
    let mut sum = 0 as u32;
    // TODO: stride *2??? What is the correct way to do this?
    let org_stride = plane_org.plane.cfg.stride as libc::ptrdiff_t * 2;
    let ref_stride = plane_ref.plane.cfg.stride as libc::ptrdiff_t * 2;
    assert!(blk_h >= 4 && blk_w >= 4);
    let step_size =
      blk_h.min(blk_w).min(if bit_depth <= 10 { 128 } else { 4 });
    let func = match step_size.ilog() {
      3 => rav1e_sad_4x4_hbd_ssse3,
      4 => rav1e_sad_8x8_hbd10_ssse3,
      5 => rav1e_sad_16x16_hbd_ssse3,
      6 => rav1e_sad_32x32_hbd10_ssse3,
      7 => rav1e_sad_64x64_hbd10_ssse3,
      8 => rav1e_sad_128x128_hbd10_ssse3,
      _ => rav1e_sad_128x128_hbd10_ssse3
    };
    for r in (0..blk_h).step_by(step_size) {
      for c in (0..blk_w).step_by(step_size) {
        let org_slice = plane_org.subslice(c, r);
        let ref_slice = plane_ref.subslice(c, r);
        let org_ptr = org_slice.as_slice().as_ptr();
        let ref_ptr = ref_slice.as_slice().as_ptr();
        sum += func(org_ptr, org_stride, ref_ptr, ref_stride);
      }
Kyle Siefring's avatar
Kyle Siefring committed
88
    }
89
    sum
Kyle Siefring's avatar
Kyle Siefring committed
90 91
  }

Luca Barbato's avatar
Luca Barbato committed
92 93
  #[inline(always)]
  pub fn get_sad(
94
    plane_org: &PlaneSlice<'_>, plane_ref: &PlaneSlice<'_>, blk_h: usize,
Luca Barbato's avatar
Luca Barbato committed
95 96 97 98 99 100 101 102 103
    blk_w: usize, bit_depth: usize
  ) -> u32 {
    #[cfg(all(target_arch = "x86_64", not(windows), feature = "nasm"))]
    {
      if is_x86_feature_detected!("ssse3") && blk_h >= 4 && blk_w >= 4 {
        return unsafe {
          sad_ssse3(plane_org, plane_ref, blk_h, blk_w, bit_depth)
        };
      }
Kyle Siefring's avatar
Kyle Siefring committed
104
    }
Luca Barbato's avatar
Luca Barbato committed
105
    super::native::get_sad(plane_org, plane_ref, blk_h, blk_w, bit_depth)
Kyle Siefring's avatar
Kyle Siefring committed
106
  }
107 108 109
}

mod native {
Raphaël Zumer's avatar
Raphaël Zumer committed
110
  use crate::plane::*;
111

Luca Barbato's avatar
Luca Barbato committed
112 113
  #[inline(always)]
  pub fn get_sad(
114
    plane_org: &PlaneSlice<'_>, plane_ref: &PlaneSlice<'_>, blk_h: usize,
Luca Barbato's avatar
Luca Barbato committed
115 116 117
    blk_w: usize, _bit_depth: usize
  ) -> u32 {
    let mut sum = 0 as u32;
118

Luca Barbato's avatar
Luca Barbato committed
119 120
    let org_iter = plane_org.iter_width(blk_w);
    let ref_iter = plane_ref.iter_width(blk_w);
121

Luca Barbato's avatar
Luca Barbato committed
122
    for (slice_org, slice_ref) in org_iter.take(blk_h).zip(ref_iter) {
123 124 125 126 127
      sum += slice_org
        .iter()
        .zip(slice_ref)
        .map(|(&a, &b)| (a as i32 - b as i32).abs() as u32)
        .sum::<u32>();
Luca Barbato's avatar
Luca Barbato committed
128
    }
129

Luca Barbato's avatar
Luca Barbato committed
130 131
    sum
  }
132 133
}

134 135 136
fn get_mv_range(
  fi: &FrameInvariants, bo: &BlockOffset, blk_w: usize, blk_h: usize
) -> (isize, isize, isize, isize) {
137 138 139 140 141 142 143 144 145 146
  let border_w = 128 + blk_w as isize * 8;
  let border_h = 128 + blk_h as isize * 8;
  let mvx_min = -(bo.x as isize) * (8 * MI_SIZE) as isize - border_w;
  let mvx_max = (fi.w_in_b - bo.x - blk_w / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_w;
  let mvy_min = -(bo.y as isize) * (8 * MI_SIZE) as isize - border_h;
  let mvy_max = (fi.h_in_b - bo.y - blk_h / MI_SIZE) as isize * (8 * MI_SIZE) as isize + border_h;

  (mvx_min, mvx_max, mvy_min, mvy_max)
}

147
pub fn motion_estimation(
Kyle Siefring's avatar
Kyle Siefring committed
148
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, bo: &BlockOffset,
149
  ref_frame: usize, cmv: MotionVector, pmv: &[MotionVector; 2]
150
) -> MotionVector {
151
  match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME] as usize] {
152
    Some(ref rec) => {
153 154 155 156
      let po = PlaneOffset {
        x: (bo.x as isize) << BLOCK_TO_PLANE_SHIFT,
        y: (bo.y as isize) << BLOCK_TO_PLANE_SHIFT
      };
157
      let range = 16;
158 159
      let blk_w = bsize.width();
      let blk_h = bsize.height();
160
      let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, bo, blk_w, blk_h);
161 162 163 164
      let x_lo = po.x + ((-range + (cmv.col / 8) as isize).max(mvx_min / 8).min(mvx_max / 8));
      let x_hi = po.x + ((range + (cmv.col / 8) as isize).max(mvx_min / 8).min(mvx_max / 8));
      let y_lo = po.y + ((-range + (cmv.row / 8) as isize).max(mvy_min / 8).min(mvy_max / 8));
      let y_hi = po.y + ((range + (cmv.row / 8) as isize).max(mvy_min / 8).min(mvy_max / 8));
165

166
      let mut lowest_cost = std::u64::MAX;
167 168
      let mut best_mv = MotionVector { row: 0, col: 0 };

Frank Bossen's avatar
Frank Bossen committed
169
      // 0.5 is a fudge factor
170
      let lambda = (fi.me_lambda * 256.0 * 0.5) as u32;
Frank Bossen's avatar
Frank Bossen committed
171

172
      full_search(
Kyle Siefring's avatar
Kyle Siefring committed
173 174 175 176 177 178 179 180 181
        x_lo,
        x_hi,
        y_lo,
        y_hi,
        blk_h,
        blk_w,
        &fs.input.planes[0],
        &rec.frame.planes[0],
        &mut best_mv,
Frank Bossen's avatar
Frank Bossen committed
182
        &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
183 184
        &po,
        2,
185
        fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
186 187 188
        lambda,
        pmv,
        fi.allow_high_precision_mv
189
      );
Frank Bossen's avatar
Frank Bossen committed
190 191

      let mode = PredictionMode::NEWMV;
fbossen's avatar
fbossen committed
192
      let mut tmp_plane = Plane::new(blk_w, blk_h, 0, 0, 0, 0);
Frank Bossen's avatar
Frank Bossen committed
193

194
      let mut steps = vec![8, 4, 2];
195 196 197 198 199
      if fi.allow_high_precision_mv {
        steps.push(1);
      }

      for step in steps {
Frank Bossen's avatar
Frank Bossen committed
200 201 202 203
        let center_mv_h = best_mv;
        for i in 0..3 {
          for j in 0..3 {
            // Skip the center point that was already tested
204 205 206
            if i == 1 && j == 1 {
              continue;
            }
Frank Bossen's avatar
Frank Bossen committed
207

208 209 210 211
            let cand_mv = MotionVector {
              row: center_mv_h.row + step * (i as i16 - 1),
              col: center_mv_h.col + step * (j as i16 - 1)
            };
Frank Bossen's avatar
Frank Bossen committed
212

213
            if (cand_mv.col as isize) < mvx_min || (cand_mv.col as isize) > mvx_max {
214 215
              continue;
            }
216
            if (cand_mv.row as isize) < mvy_min || (cand_mv.row as isize) > mvy_max {
217 218 219
              continue;
            }

Frank Bossen's avatar
Frank Bossen committed
220
            {
221 222
              let tmp_slice =
                &mut tmp_plane.mut_slice(&PlaneOffset { x: 0, y: 0 });
Frank Bossen's avatar
Frank Bossen committed
223

224
              mode.predict_inter(
225 226 227 228 229 230 231
                fi,
                0,
                &po,
                tmp_slice,
                blk_w,
                blk_h,
                [ref_frame, NONE_FRAME],
232
                [cand_mv, MotionVector { row: 0, col: 0 }]
233
              );
Frank Bossen's avatar
Frank Bossen committed
234 235
            }

236 237
            let plane_org = fs.input.planes[0].slice(&po);
            let plane_ref = tmp_plane.slice(&PlaneOffset { x: 0, y: 0 });
Frank Bossen's avatar
Frank Bossen committed
238

239
            let sad = get_sad(&plane_org, &plane_ref, blk_h, blk_w, fi.sequence.bit_depth);
Frank Bossen's avatar
Frank Bossen committed
240

Frank Bossen's avatar
Frank Bossen committed
241 242 243
            let rate1 = get_mv_rate(cand_mv, pmv[0], fi.allow_high_precision_mv);
            let rate2 = get_mv_rate(cand_mv, pmv[1], fi.allow_high_precision_mv);
            let rate = rate1.min(rate2 + 1);
244
            let cost = 256 * sad as u64 + rate as u64 * lambda as u64;
Frank Bossen's avatar
Frank Bossen committed
245 246 247

            if cost < lowest_cost {
              lowest_cost = cost;
Frank Bossen's avatar
Frank Bossen committed
248 249 250 251 252 253
              best_mv = cand_mv;
            }
          }
        }
      }

254
      best_mv
255
    }
256

257
    None => MotionVector { row: 0, col: 0 }
258 259
  }
}
260

Kyle Siefring's avatar
Kyle Siefring committed
261 262 263
fn full_search(
  x_lo: isize, x_hi: isize, y_lo: isize, y_hi: isize, blk_h: usize,
  blk_w: usize, p_org: &Plane, p_ref: &Plane, best_mv: &mut MotionVector,
264
  lowest_cost: &mut u64, po: &PlaneOffset, step: usize, bit_depth: usize,
Frank Bossen's avatar
Frank Bossen committed
265
  lambda: u32, pmv: &[MotionVector; 2], allow_high_precision_mv: bool
Kyle Siefring's avatar
Kyle Siefring committed
266
) {
Luca Barbato's avatar
Luca Barbato committed
267 268 269 270 271
    let search_range_y = (y_lo..=y_hi).step_by(step);
    let search_range_x = (x_lo..=x_hi).step_by(step);
    let search_area = search_range_y.flat_map(|y| { search_range_x.clone().map(move |x| (y, x)) });

    let (cost, mv) = search_area.map(|(y, x)| {
272 273 274
      let plane_org = p_org.slice(po);
      let plane_ref = p_ref.slice(&PlaneOffset { x, y });

Kyle Siefring's avatar
Kyle Siefring committed
275
      let sad = get_sad(&plane_org, &plane_ref, blk_h, blk_w, bit_depth);
276

Frank Bossen's avatar
Frank Bossen committed
277 278 279 280 281 282 283 284
      let mv = MotionVector {
        row: 8 * (y as i16 - po.y as i16),
        col: 8 * (x as i16 - po.x as i16)
      };

      let rate1 = get_mv_rate(mv, pmv[0], allow_high_precision_mv);
      let rate2 = get_mv_rate(mv, pmv[1], allow_high_precision_mv);
      let rate = rate1.min(rate2 + 1);
285
      let cost = 256 * sad as u64 + rate as u64 * lambda as u64;
Frank Bossen's avatar
Frank Bossen committed
286

Luca Barbato's avatar
Luca Barbato committed
287 288 289 290 291
      (cost, mv)
  }).min_by_key(|(c, _)| *c).unwrap();

    *lowest_cost = cost;
    *best_mv = mv;
292 293 294 295 296 297 298 299 300 301
}

// Adjust block offset such that entire block lies within frame boundaries
fn adjust_bo(bo: &BlockOffset, fi: &FrameInvariants, blk_w: usize, blk_h: usize) -> BlockOffset {
  BlockOffset {
    x: (bo.x as isize).min(fi.w_in_b as isize - blk_w as isize / 4).max(0) as usize,
    y: (bo.y as isize).min(fi.h_in_b as isize - blk_h as isize / 4).max(0) as usize
  }
}

Frank Bossen's avatar
Frank Bossen committed
302 303 304 305 306 307 308 309 310 311 312 313 314
fn get_mv_rate(a: MotionVector, b: MotionVector, allow_high_precision_mv: bool) -> u32 {
  fn diff_to_rate(diff: i16, allow_high_precision_mv: bool) -> u32 {
    let d = if allow_high_precision_mv { diff } else { diff >> 1 };
    if d == 0 {
      0
    } else {
      2 * (16 - d.abs().leading_zeros())
    }
  }

  diff_to_rate(a.row - b.row, allow_high_precision_mv) + diff_to_rate(a.col - b.col, allow_high_precision_mv)
}

315
pub fn estimate_motion_ss4(
Kyle Siefring's avatar
Kyle Siefring committed
316
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
317
  bo: &BlockOffset
318 319 320 321 322 323 324 325 326
) -> Option<MotionVector> {
  if let Some(ref rec) = fi.rec_buffer.frames[ref_idx] {
    let blk_w = bsize.width();
    let blk_h = bsize.height();
    let bo_adj = adjust_bo(bo, fi, blk_w, blk_h);
    let po = PlaneOffset {
      x: (bo_adj.x as isize) << BLOCK_TO_PLANE_SHIFT >> 2,
      y: (bo_adj.y as isize) << BLOCK_TO_PLANE_SHIFT >> 2
    };
327 328
    let range_x = 192 * fi.me_range_scale as isize;
    let range_y = 64 * fi.me_range_scale as isize;
329
    let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, &bo_adj, blk_w, blk_h);
330 331 332 333
    let x_lo = po.x + (((-range_x).max(mvx_min / 8)) >> 2);
    let x_hi = po.x + (((range_x).min(mvx_max / 8)) >> 2);
    let y_lo = po.y + (((-range_y).max(mvy_min / 8)) >> 2);
    let y_hi = po.y + (((range_y).min(mvy_max / 8)) >> 2);
334

335
    let mut lowest_cost = std::u64::MAX;
336 337
    let mut best_mv = MotionVector { row: 0, col: 0 };

Frank Bossen's avatar
Frank Bossen committed
338
    // Divide by 16 to account for subsampling, 0.125 is a fudge factor
339
    let lambda = (fi.me_lambda * 256.0 / 16.0 * 0.125) as u32;
Frank Bossen's avatar
Frank Bossen committed
340

341
    full_search(
Kyle Siefring's avatar
Kyle Siefring committed
342 343 344 345 346 347 348 349 350
      x_lo,
      x_hi,
      y_lo,
      y_hi,
      blk_h >> 2,
      blk_w >> 2,
      &fs.input_qres,
      &rec.input_qres,
      &mut best_mv,
Frank Bossen's avatar
Frank Bossen committed
351
      &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
352 353
      &po,
      1,
354
      fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
355 356 357
      lambda,
      &[MotionVector { row: 0, col: 0 }; 2],
      fi.allow_high_precision_mv
358 359 360 361 362 363 364 365 366
    );

    Some(MotionVector { row: best_mv.row * 4, col: best_mv.col * 4 })
  } else {
    None
  }
}

pub fn estimate_motion_ss2(
Kyle Siefring's avatar
Kyle Siefring committed
367
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
368
  bo: &BlockOffset, pmvs: &[Option<MotionVector>; 3]
369 370 371 372 373 374 375 376 377 378 379 380
) -> Option<MotionVector> {
  if let Some(ref rec) = fi.rec_buffer.frames[ref_idx] {
    let blk_w = bsize.width();
    let blk_h = bsize.height();
    let bo_adj = adjust_bo(bo, fi, blk_w, blk_h);
    let po = PlaneOffset {
      x: (bo_adj.x as isize) << BLOCK_TO_PLANE_SHIFT >> 1,
      y: (bo_adj.y as isize) << BLOCK_TO_PLANE_SHIFT >> 1
    };
    let range = 16;
    let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, &bo_adj, blk_w, blk_h);

381
    let mut lowest_cost = std::u64::MAX;
382 383
    let mut best_mv = MotionVector { row: 0, col: 0 };

Frank Bossen's avatar
Frank Bossen committed
384
    // Divide by 4 to account for subsampling, 0.125 is a fudge factor
385
    let lambda = (fi.me_lambda * 256.0 / 4.0 * 0.125) as u32;
Frank Bossen's avatar
Frank Bossen committed
386

387 388
    for omv in pmvs.iter() {
      if let Some(pmv) = omv {
389 390 391 392
        let x_lo = po.x + (((pmv.col as isize / 8 - range).max(mvx_min / 8).min(mvx_max / 8)) >> 1);
        let x_hi = po.x + (((pmv.col as isize / 8 + range).max(mvx_min / 8).min(mvx_max / 8)) >> 1);
        let y_lo = po.y + (((pmv.row as isize / 8 - range).max(mvy_min / 8).min(mvy_max / 8)) >> 1);
        let y_hi = po.y + (((pmv.row as isize / 8 + range).max(mvy_min / 8).min(mvy_max / 8)) >> 1);
393 394

        full_search(
Kyle Siefring's avatar
Kyle Siefring committed
395 396 397 398 399 400 401 402 403
          x_lo,
          x_hi,
          y_lo,
          y_hi,
          blk_h >> 1,
          blk_w >> 1,
          &fs.input_hres,
          &rec.input_hres,
          &mut best_mv,
Frank Bossen's avatar
Frank Bossen committed
404
          &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
405 406
          &po,
          1,
407
          fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
408 409 410
          lambda,
          &[MotionVector { row: 0, col: 0 }; 2],
          fi.allow_high_precision_mv
411 412 413 414 415 416 417 418 419 420
        );
      }
    }

    Some(MotionVector { row: best_mv.row * 2, col: best_mv.col * 2 })
  } else {
    None
  }
}

421 422 423
#[cfg(test)]
pub mod test {
  use super::*;
Raphaël Zumer's avatar
Raphaël Zumer committed
424 425
  use crate::partition::BlockSize;
  use crate::partition::BlockSize::*;
426 427 428 429 430

  // Generate plane data for get_sad_same()
  fn setup_sad() -> (Plane, Plane) {
    let mut input_plane = Plane::new(640, 480, 0, 0, 128 + 8, 128 + 8);
    let mut rec_plane = input_plane.clone();
Luca Barbato's avatar
Luca Barbato committed
431

432
    for (i, row) in input_plane.data.chunks_mut(input_plane.cfg.stride).enumerate() {
433
      for (j, pixel) in row.into_iter().enumerate() {
434
        let val = ((j + i) as i32 & 255i32) as u16;
Luca Barbato's avatar
Luca Barbato committed
435
        assert!(val >= u8::min_value().into() &&
436 437
            val <= u8::max_value().into());
        *pixel = val;
438 439 440 441
      }
    }

    for (i, row) in rec_plane.data.chunks_mut(rec_plane.cfg.stride).enumerate() {
442
      for (j, pixel) in row.into_iter().enumerate() {
443
        let val = (j as i32 - i as i32 & 255i32) as u16;
Luca Barbato's avatar
Luca Barbato committed
444
        assert!(val >= u8::min_value().into() &&
445 446
            val <= u8::max_value().into());
        *pixel = val;
447 448 449 450 451 452 453 454 455 456
      }
    }

    (input_plane, rec_plane)
  }

  // Regression and validation test for SAD computation
  #[test]
  fn get_sad_same() {
    let blocks: Vec<(BlockSize, u32)> = vec![
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
      (BLOCK_4X4, 1912),
      (BLOCK_4X8, 3496),
      (BLOCK_8X4, 4296),
      (BLOCK_8X8, 7824),
      (BLOCK_8X16, 14416),
      (BLOCK_16X8, 16592),
      (BLOCK_16X16, 31136),
      (BLOCK_16X32, 59552),
      (BLOCK_32X16, 60064),
      (BLOCK_32X32, 120128),
      (BLOCK_32X64, 250176),
      (BLOCK_64X32, 186688),
      (BLOCK_64X64, 438912),
      (BLOCK_64X128, 1016768),
      (BLOCK_128X64, 654272),
      (BLOCK_128X128, 1689792),
      (BLOCK_4X16, 6664),
      (BLOCK_16X4, 8680),
      (BLOCK_8X32, 27600),
      (BLOCK_32X8, 31056),
      (BLOCK_16X64, 116384),
      (BLOCK_64X16, 93344),
479 480
    ];

Kyle Siefring's avatar
Kyle Siefring committed
481
    let bit_depth: usize = 8;
482 483 484
    let (input_plane, rec_plane) = setup_sad();

    for block in blocks {
Kyle Siefring's avatar
Kyle Siefring committed
485 486 487
      let bsw = block.0.width();
      let bsh = block.0.height();
      let po = PlaneOffset { x: 40, y: 40 };
488

Kyle Siefring's avatar
Kyle Siefring committed
489 490
      let mut input_slice = input_plane.slice(&po);
      let mut rec_slice = rec_plane.slice(&po);
491

Kyle Siefring's avatar
Kyle Siefring committed
492 493 494 495
      assert_eq!(
        block.1,
        get_sad(&mut input_slice, &mut rec_slice, bsw, bsh, bit_depth)
      );
496 497 498
    }
  }
}