Home | History | Annotate | Download | only in test
      1 /*
      2  *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include <math.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 #include "third_party/googletest/src/include/gtest/gtest.h"
     16 
     17 #include "./vp9_rtcd.h"
     18 #include "./vpx_dsp_rtcd.h"
     19 #include "test/acm_random.h"
     20 #include "test/clear_system_state.h"
     21 #include "test/register_state_check.h"
     22 #include "test/util.h"
     23 #include "vp9/common/vp9_entropy.h"
     24 #include "vp9/common/vp9_scan.h"
     25 #include "vpx/vpx_codec.h"
     26 #include "vpx/vpx_integer.h"
     27 #include "vpx_ports/mem.h"
     28 
     29 using libvpx_test::ACMRandom;
     30 
     31 namespace {
     32 
     33 const int kNumCoeffs = 64;
     34 const double kPi = 3.141592653589793238462643383279502884;
     35 
     36 const int kSignBiasMaxDiff255 = 1500;
     37 const int kSignBiasMaxDiff15 = 10000;
     38 
     39 typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride);
     40 typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride);
     41 typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride,
     42                         int tx_type);
     43 typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
     44                         int tx_type);
     45 
     46 typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param;
     47 typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param;
     48 typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t> Idct8x8Param;
     49 
     50 void reference_8x8_dct_1d(const double in[8], double out[8]) {
     51   const double kInvSqrt2 = 0.707106781186547524400844362104;
     52   for (int k = 0; k < 8; k++) {
     53     out[k] = 0.0;
     54     for (int n = 0; n < 8; n++) {
     55       out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 16.0);
     56     }
     57     if (k == 0) out[k] = out[k] * kInvSqrt2;
     58   }
     59 }
     60 
     61 void reference_8x8_dct_2d(const int16_t input[kNumCoeffs],
     62                           double output[kNumCoeffs]) {
     63   // First transform columns
     64   for (int i = 0; i < 8; ++i) {
     65     double temp_in[8], temp_out[8];
     66     for (int j = 0; j < 8; ++j) temp_in[j] = input[j * 8 + i];
     67     reference_8x8_dct_1d(temp_in, temp_out);
     68     for (int j = 0; j < 8; ++j) output[j * 8 + i] = temp_out[j];
     69   }
     70   // Then transform rows
     71   for (int i = 0; i < 8; ++i) {
     72     double temp_in[8], temp_out[8];
     73     for (int j = 0; j < 8; ++j) temp_in[j] = output[j + i * 8];
     74     reference_8x8_dct_1d(temp_in, temp_out);
     75     // Scale by some magic number
     76     for (int j = 0; j < 8; ++j) output[j + i * 8] = temp_out[j] * 2;
     77   }
     78 }
     79 
     80 void fdct8x8_ref(const int16_t *in, tran_low_t *out, int stride,
     81                  int /*tx_type*/) {
     82   vpx_fdct8x8_c(in, out, stride);
     83 }
     84 
     85 void fht8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
     86   vp9_fht8x8_c(in, out, stride, tx_type);
     87 }
     88 
     89 #if CONFIG_VP9_HIGHBITDEPTH
     90 void idct8x8_10(const tran_low_t *in, uint8_t *out, int stride) {
     91   vpx_highbd_idct8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, 10);
     92 }
     93 
     94 void idct8x8_12(const tran_low_t *in, uint8_t *out, int stride) {
     95   vpx_highbd_idct8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, 12);
     96 }
     97 
     98 void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
     99   vp9_highbd_iht8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 10);
    100 }
    101 
    102 void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
    103   vp9_highbd_iht8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 12);
    104 }
    105 
    106 #if HAVE_SSE2
    107 
    108 void idct8x8_12_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
    109   vpx_highbd_idct8x8_12_add_c(in, CAST_TO_SHORTPTR(out), stride, 10);
    110 }
    111 
    112 void idct8x8_12_add_12_c(const tran_low_t *in, uint8_t *out, int stride) {
    113   vpx_highbd_idct8x8_12_add_c(in, CAST_TO_SHORTPTR(out), stride, 12);
    114 }
    115 
    116 void idct8x8_12_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
    117   vpx_highbd_idct8x8_12_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10);
    118 }
    119 
    120 void idct8x8_12_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
    121   vpx_highbd_idct8x8_12_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12);
    122 }
    123 
    124 void idct8x8_64_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
    125   vpx_highbd_idct8x8_64_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10);
    126 }
    127 
    128 void idct8x8_64_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
    129   vpx_highbd_idct8x8_64_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12);
    130 }
    131 #endif  // HAVE_SSE2
    132 #endif  // CONFIG_VP9_HIGHBITDEPTH
    133 
    134 class FwdTrans8x8TestBase {
    135  public:
    136   virtual ~FwdTrans8x8TestBase() {}
    137 
    138  protected:
    139   virtual void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) = 0;
    140   virtual void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) = 0;
    141 
    142   void RunSignBiasCheck() {
    143     ACMRandom rnd(ACMRandom::DeterministicSeed());
    144     DECLARE_ALIGNED(16, int16_t, test_input_block[64]);
    145     DECLARE_ALIGNED(16, tran_low_t, test_output_block[64]);
    146     int count_sign_block[64][2];
    147     const int count_test_block = 100000;
    148 
    149     memset(count_sign_block, 0, sizeof(count_sign_block));
    150 
    151     for (int i = 0; i < count_test_block; ++i) {
    152       // Initialize a test block with input range [-255, 255].
    153       for (int j = 0; j < 64; ++j) {
    154         test_input_block[j] = ((rnd.Rand16() >> (16 - bit_depth_)) & mask_) -
    155                               ((rnd.Rand16() >> (16 - bit_depth_)) & mask_);
    156       }
    157       ASM_REGISTER_STATE_CHECK(
    158           RunFwdTxfm(test_input_block, test_output_block, pitch_));
    159 
    160       for (int j = 0; j < 64; ++j) {
    161         if (test_output_block[j] < 0) {
    162           ++count_sign_block[j][0];
    163         } else if (test_output_block[j] > 0) {
    164           ++count_sign_block[j][1];
    165         }
    166       }
    167     }
    168 
    169     for (int j = 0; j < 64; ++j) {
    170       const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
    171       const int max_diff = kSignBiasMaxDiff255;
    172       EXPECT_LT(diff, max_diff << (bit_depth_ - 8))
    173           << "Error: 8x8 FDCT/FHT has a sign bias > "
    174           << 1. * max_diff / count_test_block * 100 << "%"
    175           << " for input range [-255, 255] at index " << j
    176           << " count0: " << count_sign_block[j][0]
    177           << " count1: " << count_sign_block[j][1] << " diff: " << diff;
    178     }
    179 
    180     memset(count_sign_block, 0, sizeof(count_sign_block));
    181 
    182     for (int i = 0; i < count_test_block; ++i) {
    183       // Initialize a test block with input range [-mask_ / 16, mask_ / 16].
    184       for (int j = 0; j < 64; ++j) {
    185         test_input_block[j] =
    186             ((rnd.Rand16() & mask_) >> 4) - ((rnd.Rand16() & mask_) >> 4);
    187       }
    188       ASM_REGISTER_STATE_CHECK(
    189           RunFwdTxfm(test_input_block, test_output_block, pitch_));
    190 
    191       for (int j = 0; j < 64; ++j) {
    192         if (test_output_block[j] < 0) {
    193           ++count_sign_block[j][0];
    194         } else if (test_output_block[j] > 0) {
    195           ++count_sign_block[j][1];
    196         }
    197       }
    198     }
    199 
    200     for (int j = 0; j < 64; ++j) {
    201       const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
    202       const int max_diff = kSignBiasMaxDiff15;
    203       EXPECT_LT(diff, max_diff << (bit_depth_ - 8))
    204           << "Error: 8x8 FDCT/FHT has a sign bias > "
    205           << 1. * max_diff / count_test_block * 100 << "%"
    206           << " for input range [-15, 15] at index " << j
    207           << " count0: " << count_sign_block[j][0]
    208           << " count1: " << count_sign_block[j][1] << " diff: " << diff;
    209     }
    210   }
    211 
    212   void RunRoundTripErrorCheck() {
    213     ACMRandom rnd(ACMRandom::DeterministicSeed());
    214     int max_error = 0;
    215     int total_error = 0;
    216     const int count_test_block = 100000;
    217     DECLARE_ALIGNED(16, int16_t, test_input_block[64]);
    218     DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]);
    219     DECLARE_ALIGNED(16, uint8_t, dst[64]);
    220     DECLARE_ALIGNED(16, uint8_t, src[64]);
    221 #if CONFIG_VP9_HIGHBITDEPTH
    222     DECLARE_ALIGNED(16, uint16_t, dst16[64]);
    223     DECLARE_ALIGNED(16, uint16_t, src16[64]);
    224 #endif
    225 
    226     for (int i = 0; i < count_test_block; ++i) {
    227       // Initialize a test block with input range [-mask_, mask_].
    228       for (int j = 0; j < 64; ++j) {
    229         if (bit_depth_ == VPX_BITS_8) {
    230           src[j] = rnd.Rand8();
    231           dst[j] = rnd.Rand8();
    232           test_input_block[j] = src[j] - dst[j];
    233 #if CONFIG_VP9_HIGHBITDEPTH
    234         } else {
    235           src16[j] = rnd.Rand16() & mask_;
    236           dst16[j] = rnd.Rand16() & mask_;
    237           test_input_block[j] = src16[j] - dst16[j];
    238 #endif
    239         }
    240       }
    241 
    242       ASM_REGISTER_STATE_CHECK(
    243           RunFwdTxfm(test_input_block, test_temp_block, pitch_));
    244       for (int j = 0; j < 64; ++j) {
    245         if (test_temp_block[j] > 0) {
    246           test_temp_block[j] += 2;
    247           test_temp_block[j] /= 4;
    248           test_temp_block[j] *= 4;
    249         } else {
    250           test_temp_block[j] -= 2;
    251           test_temp_block[j] /= 4;
    252           test_temp_block[j] *= 4;
    253         }
    254       }
    255       if (bit_depth_ == VPX_BITS_8) {
    256         ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
    257 #if CONFIG_VP9_HIGHBITDEPTH
    258       } else {
    259         ASM_REGISTER_STATE_CHECK(
    260             RunInvTxfm(test_temp_block, CAST_TO_BYTEPTR(dst16), pitch_));
    261 #endif
    262       }
    263 
    264       for (int j = 0; j < 64; ++j) {
    265 #if CONFIG_VP9_HIGHBITDEPTH
    266         const int diff =
    267             bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
    268 #else
    269         const int diff = dst[j] - src[j];
    270 #endif
    271         const int error = diff * diff;
    272         if (max_error < error) max_error = error;
    273         total_error += error;
    274       }
    275     }
    276 
    277     EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error)
    278         << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual"
    279         << " roundtrip error > 1";
    280 
    281     EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8)) / 5, total_error)
    282         << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip "
    283         << "error > 1/5 per block";
    284   }
    285 
    286   void RunExtremalCheck() {
    287     ACMRandom rnd(ACMRandom::DeterministicSeed());
    288     int max_error = 0;
    289     int total_error = 0;
    290     int total_coeff_error = 0;
    291     const int count_test_block = 100000;
    292     DECLARE_ALIGNED(16, int16_t, test_input_block[64]);
    293     DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]);
    294     DECLARE_ALIGNED(16, tran_low_t, ref_temp_block[64]);
    295     DECLARE_ALIGNED(16, uint8_t, dst[64]);
    296     DECLARE_ALIGNED(16, uint8_t, src[64]);
    297 #if CONFIG_VP9_HIGHBITDEPTH
    298     DECLARE_ALIGNED(16, uint16_t, dst16[64]);
    299     DECLARE_ALIGNED(16, uint16_t, src16[64]);
    300 #endif
    301 
    302     for (int i = 0; i < count_test_block; ++i) {
    303       // Initialize a test block with input range [-mask_, mask_].
    304       for (int j = 0; j < 64; ++j) {
    305         if (bit_depth_ == VPX_BITS_8) {
    306           if (i == 0) {
    307             src[j] = 255;
    308             dst[j] = 0;
    309           } else if (i == 1) {
    310             src[j] = 0;
    311             dst[j] = 255;
    312           } else {
    313             src[j] = rnd.Rand8() % 2 ? 255 : 0;
    314             dst[j] = rnd.Rand8() % 2 ? 255 : 0;
    315           }
    316           test_input_block[j] = src[j] - dst[j];
    317 #if CONFIG_VP9_HIGHBITDEPTH
    318         } else {
    319           if (i == 0) {
    320             src16[j] = mask_;
    321             dst16[j] = 0;
    322           } else if (i == 1) {
    323             src16[j] = 0;
    324             dst16[j] = mask_;
    325           } else {
    326             src16[j] = rnd.Rand8() % 2 ? mask_ : 0;
    327             dst16[j] = rnd.Rand8() % 2 ? mask_ : 0;
    328           }
    329           test_input_block[j] = src16[j] - dst16[j];
    330 #endif
    331         }
    332       }
    333 
    334       ASM_REGISTER_STATE_CHECK(
    335           RunFwdTxfm(test_input_block, test_temp_block, pitch_));
    336       ASM_REGISTER_STATE_CHECK(
    337           fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_));
    338       if (bit_depth_ == VPX_BITS_8) {
    339         ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
    340 #if CONFIG_VP9_HIGHBITDEPTH
    341       } else {
    342         ASM_REGISTER_STATE_CHECK(
    343             RunInvTxfm(test_temp_block, CAST_TO_BYTEPTR(dst16), pitch_));
    344 #endif
    345       }
    346 
    347       for (int j = 0; j < 64; ++j) {
    348 #if CONFIG_VP9_HIGHBITDEPTH
    349         const int diff =
    350             bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
    351 #else
    352         const int diff = dst[j] - src[j];
    353 #endif
    354         const int error = diff * diff;
    355         if (max_error < error) max_error = error;
    356         total_error += error;
    357 
    358         const int coeff_diff = test_temp_block[j] - ref_temp_block[j];
    359         total_coeff_error += abs(coeff_diff);
    360       }
    361 
    362       EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error)
    363           << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has"
    364           << "an individual roundtrip error > 1";
    365 
    366       EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8)) / 5, total_error)
    367           << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average"
    368           << " roundtrip error > 1/5 per block";
    369 
    370       EXPECT_EQ(0, total_coeff_error)
    371           << "Error: Extremal 8x8 FDCT/FHT has"
    372           << "overflow issues in the intermediate steps > 1";
    373     }
    374   }
    375 
    376   void RunInvAccuracyCheck() {
    377     ACMRandom rnd(ACMRandom::DeterministicSeed());
    378     const int count_test_block = 1000;
    379     DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]);
    380     DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
    381     DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]);
    382     DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]);
    383 #if CONFIG_VP9_HIGHBITDEPTH
    384     DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
    385     DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
    386 #endif
    387 
    388     for (int i = 0; i < count_test_block; ++i) {
    389       double out_r[kNumCoeffs];
    390 
    391       // Initialize a test block with input range [-255, 255].
    392       for (int j = 0; j < kNumCoeffs; ++j) {
    393         if (bit_depth_ == VPX_BITS_8) {
    394           src[j] = rnd.Rand8() % 2 ? 255 : 0;
    395           dst[j] = src[j] > 0 ? 0 : 255;
    396           in[j] = src[j] - dst[j];
    397 #if CONFIG_VP9_HIGHBITDEPTH
    398         } else {
    399           src16[j] = rnd.Rand8() % 2 ? mask_ : 0;
    400           dst16[j] = src16[j] > 0 ? 0 : mask_;
    401           in[j] = src16[j] - dst16[j];
    402 #endif
    403         }
    404       }
    405 
    406       reference_8x8_dct_2d(in, out_r);
    407       for (int j = 0; j < kNumCoeffs; ++j) {
    408         coeff[j] = static_cast<tran_low_t>(round(out_r[j]));
    409       }
    410 
    411       if (bit_depth_ == VPX_BITS_8) {
    412         ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
    413 #if CONFIG_VP9_HIGHBITDEPTH
    414       } else {
    415         ASM_REGISTER_STATE_CHECK(
    416             RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), pitch_));
    417 #endif
    418       }
    419 
    420       for (int j = 0; j < kNumCoeffs; ++j) {
    421 #if CONFIG_VP9_HIGHBITDEPTH
    422         const int diff =
    423             bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
    424 #else
    425         const int diff = dst[j] - src[j];
    426 #endif
    427         const uint32_t error = diff * diff;
    428         EXPECT_GE(1u << 2 * (bit_depth_ - 8), error)
    429             << "Error: 8x8 IDCT has error " << error << " at index " << j;
    430       }
    431     }
    432   }
    433 
    434   void RunFwdAccuracyCheck() {
    435     ACMRandom rnd(ACMRandom::DeterministicSeed());
    436     const int count_test_block = 1000;
    437     DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]);
    438     DECLARE_ALIGNED(16, tran_low_t, coeff_r[kNumCoeffs]);
    439     DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
    440 
    441     for (int i = 0; i < count_test_block; ++i) {
    442       double out_r[kNumCoeffs];
    443 
    444       // Initialize a test block with input range [-mask_, mask_].
    445       for (int j = 0; j < kNumCoeffs; ++j) {
    446         in[j] = rnd.Rand8() % 2 == 0 ? mask_ : -mask_;
    447       }
    448 
    449       RunFwdTxfm(in, coeff, pitch_);
    450       reference_8x8_dct_2d(in, out_r);
    451       for (int j = 0; j < kNumCoeffs; ++j) {
    452         coeff_r[j] = static_cast<tran_low_t>(round(out_r[j]));
    453       }
    454 
    455       for (int j = 0; j < kNumCoeffs; ++j) {
    456         const int32_t diff = coeff[j] - coeff_r[j];
    457         const uint32_t error = diff * diff;
    458         EXPECT_GE(9u << 2 * (bit_depth_ - 8), error)
    459             << "Error: 8x8 DCT has error " << error << " at index " << j;
    460       }
    461     }
    462   }
    463 
    464   void CompareInvReference(IdctFunc ref_txfm, int thresh) {
    465     ACMRandom rnd(ACMRandom::DeterministicSeed());
    466     const int count_test_block = 10000;
    467     const int eob = 12;
    468     DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
    469     DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]);
    470     DECLARE_ALIGNED(16, uint8_t, ref[kNumCoeffs]);
    471 #if CONFIG_VP9_HIGHBITDEPTH
    472     DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
    473     DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]);
    474 #endif
    475     const int16_t *scan = vp9_default_scan_orders[TX_8X8].scan;
    476 
    477     for (int i = 0; i < count_test_block; ++i) {
    478       for (int j = 0; j < kNumCoeffs; ++j) {
    479         if (j < eob) {
    480           // Random values less than the threshold, either positive or negative
    481           coeff[scan[j]] = rnd(thresh) * (1 - 2 * (i % 2));
    482         } else {
    483           coeff[scan[j]] = 0;
    484         }
    485         if (bit_depth_ == VPX_BITS_8) {
    486           dst[j] = 0;
    487           ref[j] = 0;
    488 #if CONFIG_VP9_HIGHBITDEPTH
    489         } else {
    490           dst16[j] = 0;
    491           ref16[j] = 0;
    492 #endif
    493         }
    494       }
    495       if (bit_depth_ == VPX_BITS_8) {
    496         ref_txfm(coeff, ref, pitch_);
    497         ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
    498 #if CONFIG_VP9_HIGHBITDEPTH
    499       } else {
    500         ref_txfm(coeff, CAST_TO_BYTEPTR(ref16), pitch_);
    501         ASM_REGISTER_STATE_CHECK(
    502             RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), pitch_));
    503 #endif
    504       }
    505 
    506       for (int j = 0; j < kNumCoeffs; ++j) {
    507 #if CONFIG_VP9_HIGHBITDEPTH
    508         const int diff =
    509             bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j];
    510 #else
    511         const int diff = dst[j] - ref[j];
    512 #endif
    513         const uint32_t error = diff * diff;
    514         EXPECT_EQ(0u, error) << "Error: 8x8 IDCT has error " << error
    515                              << " at index " << j;
    516       }
    517     }
    518   }
    519   int pitch_;
    520   int tx_type_;
    521   FhtFunc fwd_txfm_ref;
    522   vpx_bit_depth_t bit_depth_;
    523   int mask_;
    524 };
    525 
    526 class FwdTrans8x8DCT : public FwdTrans8x8TestBase,
    527                        public ::testing::TestWithParam<Dct8x8Param> {
    528  public:
    529   virtual ~FwdTrans8x8DCT() {}
    530 
    531   virtual void SetUp() {
    532     fwd_txfm_ = GET_PARAM(0);
    533     inv_txfm_ = GET_PARAM(1);
    534     tx_type_ = GET_PARAM(2);
    535     pitch_ = 8;
    536     fwd_txfm_ref = fdct8x8_ref;
    537     bit_depth_ = GET_PARAM(3);
    538     mask_ = (1 << bit_depth_) - 1;
    539   }
    540 
    541   virtual void TearDown() { libvpx_test::ClearSystemState(); }
    542 
    543  protected:
    544   void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) {
    545     fwd_txfm_(in, out, stride);
    546   }
    547   void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
    548     inv_txfm_(out, dst, stride);
    549   }
    550 
    551   FdctFunc fwd_txfm_;
    552   IdctFunc inv_txfm_;
    553 };
    554 
    555 TEST_P(FwdTrans8x8DCT, SignBiasCheck) { RunSignBiasCheck(); }
    556 
    557 TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); }
    558 
    559 TEST_P(FwdTrans8x8DCT, ExtremalCheck) { RunExtremalCheck(); }
    560 
    561 TEST_P(FwdTrans8x8DCT, FwdAccuracyCheck) { RunFwdAccuracyCheck(); }
    562 
    563 TEST_P(FwdTrans8x8DCT, InvAccuracyCheck) { RunInvAccuracyCheck(); }
    564 
    565 class FwdTrans8x8HT : public FwdTrans8x8TestBase,
    566                       public ::testing::TestWithParam<Ht8x8Param> {
    567  public:
    568   virtual ~FwdTrans8x8HT() {}
    569 
    570   virtual void SetUp() {
    571     fwd_txfm_ = GET_PARAM(0);
    572     inv_txfm_ = GET_PARAM(1);
    573     tx_type_ = GET_PARAM(2);
    574     pitch_ = 8;
    575     fwd_txfm_ref = fht8x8_ref;
    576     bit_depth_ = GET_PARAM(3);
    577     mask_ = (1 << bit_depth_) - 1;
    578   }
    579 
    580   virtual void TearDown() { libvpx_test::ClearSystemState(); }
    581 
    582  protected:
    583   void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) {
    584     fwd_txfm_(in, out, stride, tx_type_);
    585   }
    586   void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
    587     inv_txfm_(out, dst, stride, tx_type_);
    588   }
    589 
    590   FhtFunc fwd_txfm_;
    591   IhtFunc inv_txfm_;
    592 };
    593 
    594 TEST_P(FwdTrans8x8HT, SignBiasCheck) { RunSignBiasCheck(); }
    595 
    596 TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); }
    597 
    598 TEST_P(FwdTrans8x8HT, ExtremalCheck) { RunExtremalCheck(); }
    599 
    600 class InvTrans8x8DCT : public FwdTrans8x8TestBase,
    601                        public ::testing::TestWithParam<Idct8x8Param> {
    602  public:
    603   virtual ~InvTrans8x8DCT() {}
    604 
    605   virtual void SetUp() {
    606     ref_txfm_ = GET_PARAM(0);
    607     inv_txfm_ = GET_PARAM(1);
    608     thresh_ = GET_PARAM(2);
    609     pitch_ = 8;
    610     bit_depth_ = GET_PARAM(3);
    611     mask_ = (1 << bit_depth_) - 1;
    612   }
    613 
    614   virtual void TearDown() { libvpx_test::ClearSystemState(); }
    615 
    616  protected:
    617   void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
    618     inv_txfm_(out, dst, stride);
    619   }
    620   void RunFwdTxfm(int16_t * /*out*/, tran_low_t * /*dst*/, int /*stride*/) {}
    621 
    622   IdctFunc ref_txfm_;
    623   IdctFunc inv_txfm_;
    624   int thresh_;
    625 };
    626 
    627 TEST_P(InvTrans8x8DCT, CompareReference) {
    628   CompareInvReference(ref_txfm_, thresh_);
    629 }
    630 
    631 using std::tr1::make_tuple;
    632 
    633 #if CONFIG_VP9_HIGHBITDEPTH
    634 INSTANTIATE_TEST_CASE_P(
    635     C, FwdTrans8x8DCT,
    636     ::testing::Values(
    637         make_tuple(&vpx_fdct8x8_c, &vpx_idct8x8_64_add_c, 0, VPX_BITS_8),
    638         make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_10, 0, VPX_BITS_10),
    639         make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_12, 0, VPX_BITS_12)));
    640 #else
    641 INSTANTIATE_TEST_CASE_P(C, FwdTrans8x8DCT,
    642                         ::testing::Values(make_tuple(&vpx_fdct8x8_c,
    643                                                      &vpx_idct8x8_64_add_c, 0,
    644                                                      VPX_BITS_8)));
    645 #endif  // CONFIG_VP9_HIGHBITDEPTH
    646 
    647 #if CONFIG_VP9_HIGHBITDEPTH
    648 INSTANTIATE_TEST_CASE_P(
    649     C, FwdTrans8x8HT,
    650     ::testing::Values(
    651         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8),
    652         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 0, VPX_BITS_10),
    653         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 1, VPX_BITS_10),
    654         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 2, VPX_BITS_10),
    655         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 3, VPX_BITS_10),
    656         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 0, VPX_BITS_12),
    657         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 1, VPX_BITS_12),
    658         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 2, VPX_BITS_12),
    659         make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 3, VPX_BITS_12),
    660         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8),
    661         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8),
    662         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8)));
    663 #else
    664 INSTANTIATE_TEST_CASE_P(
    665     C, FwdTrans8x8HT,
    666     ::testing::Values(
    667         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8),
    668         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8),
    669         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8),
    670         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8)));
    671 #endif  // CONFIG_VP9_HIGHBITDEPTH
    672 
    673 #if HAVE_NEON && !CONFIG_EMULATE_HARDWARE
    674 INSTANTIATE_TEST_CASE_P(NEON, FwdTrans8x8DCT,
    675                         ::testing::Values(make_tuple(&vpx_fdct8x8_neon,
    676                                                      &vpx_idct8x8_64_add_neon,
    677                                                      0, VPX_BITS_8)));
    678 #if !CONFIG_VP9_HIGHBITDEPTH
    679 INSTANTIATE_TEST_CASE_P(
    680     NEON, FwdTrans8x8HT,
    681     ::testing::Values(
    682         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 0, VPX_BITS_8),
    683         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 1, VPX_BITS_8),
    684         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 2, VPX_BITS_8),
    685         make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 3, VPX_BITS_8)));
    686 #endif  // !CONFIG_VP9_HIGHBITDEPTH
    687 #endif  // HAVE_NEON && !CONFIG_EMULATE_HARDWARE
    688 
    689 #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
    690 INSTANTIATE_TEST_CASE_P(SSE2, FwdTrans8x8DCT,
    691                         ::testing::Values(make_tuple(&vpx_fdct8x8_sse2,
    692                                                      &vpx_idct8x8_64_add_sse2,
    693                                                      0, VPX_BITS_8)));
    694 INSTANTIATE_TEST_CASE_P(
    695     SSE2, FwdTrans8x8HT,
    696     ::testing::Values(
    697         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 0, VPX_BITS_8),
    698         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 1, VPX_BITS_8),
    699         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 2, VPX_BITS_8),
    700         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3, VPX_BITS_8)));
    701 #endif  // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
    702 
    703 #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
    704 INSTANTIATE_TEST_CASE_P(
    705     SSE2, FwdTrans8x8DCT,
    706     ::testing::Values(make_tuple(&vpx_fdct8x8_sse2, &vpx_idct8x8_64_add_c, 0,
    707                                  VPX_BITS_8),
    708                       make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_10_sse2,
    709                                  12, VPX_BITS_10),
    710                       make_tuple(&vpx_highbd_fdct8x8_sse2,
    711                                  &idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
    712                       make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_12_sse2,
    713                                  12, VPX_BITS_12),
    714                       make_tuple(&vpx_highbd_fdct8x8_sse2,
    715                                  &idct8x8_64_add_12_sse2, 12, VPX_BITS_12)));
    716 
    717 INSTANTIATE_TEST_CASE_P(
    718     SSE2, FwdTrans8x8HT,
    719     ::testing::Values(
    720         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8),
    721         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8),
    722         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8),
    723         make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8)));
    724 
    725 // Optimizations take effect at a threshold of 6201, so we use a value close to
    726 // that to test both branches.
    727 INSTANTIATE_TEST_CASE_P(
    728     SSE2, InvTrans8x8DCT,
    729     ::testing::Values(
    730         make_tuple(&idct8x8_12_add_10_c, &idct8x8_12_add_10_sse2, 6225,
    731                    VPX_BITS_10),
    732         make_tuple(&idct8x8_10, &idct8x8_64_add_10_sse2, 6225, VPX_BITS_10),
    733         make_tuple(&idct8x8_12_add_12_c, &idct8x8_12_add_12_sse2, 6225,
    734                    VPX_BITS_12),
    735         make_tuple(&idct8x8_12, &idct8x8_64_add_12_sse2, 6225, VPX_BITS_12)));
    736 #endif  // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
    737 
    738 #if HAVE_SSSE3 && ARCH_X86_64 && !CONFIG_VP9_HIGHBITDEPTH && \
    739     !CONFIG_EMULATE_HARDWARE
    740 INSTANTIATE_TEST_CASE_P(SSSE3, FwdTrans8x8DCT,
    741                         ::testing::Values(make_tuple(&vpx_fdct8x8_ssse3,
    742                                                      &vpx_idct8x8_64_add_ssse3,
    743                                                      0, VPX_BITS_8)));
    744 #endif
    745 
    746 #if HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
    747 INSTANTIATE_TEST_CASE_P(MSA, FwdTrans8x8DCT,
    748                         ::testing::Values(make_tuple(&vpx_fdct8x8_msa,
    749                                                      &vpx_idct8x8_64_add_msa, 0,
    750                                                      VPX_BITS_8)));
    751 INSTANTIATE_TEST_CASE_P(
    752     MSA, FwdTrans8x8HT,
    753     ::testing::Values(
    754         make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 0, VPX_BITS_8),
    755         make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 1, VPX_BITS_8),
    756         make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 2, VPX_BITS_8),
    757         make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 3, VPX_BITS_8)));
    758 #endif  // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
    759 }  // namespace
    760