me.rs 15.4 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

Frank Bossen's avatar
Frank Bossen committed
166
      let mut lowest_cost = std::u32::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 244 245 246 247
            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);
            let cost = 256 * sad + rate * lambda;

            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,
Frank Bossen's avatar
Frank Bossen committed
264 265
  lowest_cost: &mut u32, po: &PlaneOffset, step: usize, bit_depth: usize,
  lambda: u32, pmv: &[MotionVector; 2], allow_high_precision_mv: bool
Kyle Siefring's avatar
Kyle Siefring committed
266
) {
267 268
  for y in (y_lo..=y_hi).step_by(step) {
    for x in (x_lo..=x_hi).step_by(step) {
269 270 271
      let plane_org = p_org.slice(po);
      let plane_ref = p_ref.slice(&PlaneOffset { x, y });

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

Frank Bossen's avatar
Frank Bossen committed
274 275 276 277 278 279 280 281 282 283 284 285 286
      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);
      let cost = 256 * sad + rate * lambda;

      if cost < *lowest_cost {
        *lowest_cost = cost;
        *best_mv = mv;
287 288 289 290 291 292 293 294 295 296 297 298 299
      }
    }
  }
}

// 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
300 301 302 303 304 305 306 307 308 309 310 311 312
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)
}

313
pub fn estimate_motion_ss4(
Kyle Siefring's avatar
Kyle Siefring committed
314
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
315
  bo: &BlockOffset
316 317 318 319 320 321 322 323 324
) -> 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
    };
325 326
    let range_x = 192 * fi.me_range_scale as isize;
    let range_y = 64 * fi.me_range_scale as isize;
327
    let (mvx_min, mvx_max, mvy_min, mvy_max) = get_mv_range(fi, &bo_adj, blk_w, blk_h);
328 329 330 331
    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);
332

Frank Bossen's avatar
Frank Bossen committed
333
    let mut lowest_cost = std::u32::MAX;
334 335
    let mut best_mv = MotionVector { row: 0, col: 0 };

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

339
    full_search(
Kyle Siefring's avatar
Kyle Siefring committed
340 341 342 343 344 345 346 347 348
      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
349
      &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
350 351
      &po,
      1,
352
      fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
353 354 355
      lambda,
      &[MotionVector { row: 0, col: 0 }; 2],
      fi.allow_high_precision_mv
356 357 358 359 360 361 362 363 364
    );

    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
365
  fi: &FrameInvariants, fs: &FrameState, bsize: BlockSize, ref_idx: usize,
366
  bo: &BlockOffset, pmvs: &[Option<MotionVector>; 3]
367 368 369 370 371 372 373 374 375 376 377 378
) -> 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);

Frank Bossen's avatar
Frank Bossen committed
379
    let mut lowest_cost = std::u32::MAX;
380 381
    let mut best_mv = MotionVector { row: 0, col: 0 };

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

385 386
    for omv in pmvs.iter() {
      if let Some(pmv) = omv {
387 388 389 390
        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);
391 392

        full_search(
Kyle Siefring's avatar
Kyle Siefring committed
393 394 395 396 397 398 399 400 401
          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
402
          &mut lowest_cost,
Kyle Siefring's avatar
Kyle Siefring committed
403 404
          &po,
          1,
405
          fi.sequence.bit_depth,
Frank Bossen's avatar
Frank Bossen committed
406 407 408
          lambda,
          &[MotionVector { row: 0, col: 0 }; 2],
          fi.allow_high_precision_mv
409 410 411 412 413 414 415 416 417 418
        );
      }
    }

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

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

  // 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
429

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

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

    (input_plane, rec_plane)
  }

  // Regression and validation test for SAD computation
  #[test]
  fn get_sad_same() {
    let blocks: Vec<(BlockSize, u32)> = vec![
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
      (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),
477 478
    ];

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

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

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

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