fdct8x8_test.cc 26.4 KB
Newer Older
Daniel Kang's avatar
Daniel Kang committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <math.h>
#include <stdlib.h>
#include <string.h>

#include "third_party/googletest/src/include/gtest/gtest.h"
16

17
#include "./vp10_rtcd.h"
18
#include "./vpx_dsp_rtcd.h"
19
#include "test/acm_random.h"
20
21
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
22
#include "test/util.h"
Yaowu Xu's avatar
Yaowu Xu committed
23
24
#include "av1/common/entropy.h"
#include "av1/common/scan.h"
Yaowu Xu's avatar
Yaowu Xu committed
25
26
27
#include "aom/vpx_codec.h"
#include "aom/vpx_integer.h"
#include "aom_ports/mem.h"
28

29
30
31
32
using libvpx_test::ACMRandom;

namespace {

33
34
const int kNumCoeffs = 64;
const double kPi = 3.141592653589793238462643383279502884;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

const int kSignBiasMaxDiff255 = 1500;
const int kSignBiasMaxDiff15 = 10000;

typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride);
typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride);
typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride,
                        int tx_type);
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
                        int tx_type);

typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param;
typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param;
typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t> Idct8x8Param;

50
51
52
53
54
55
void reference_8x8_dct_1d(const double in[8], double out[8], int stride) {
  const double kInvSqrt2 = 0.707106781186547524400844362104;
  for (int k = 0; k < 8; k++) {
    out[k] = 0.0;
    for (int n = 0; n < 8; n++)
      out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 16.0);
clang-format's avatar
clang-format committed
56
    if (k == 0) out[k] = out[k] * kInvSqrt2;
57
58
59
60
61
62
63
64
  }
}

void reference_8x8_dct_2d(const int16_t input[kNumCoeffs],
                          double output[kNumCoeffs]) {
  // First transform columns
  for (int i = 0; i < 8; ++i) {
    double temp_in[8], temp_out[8];
clang-format's avatar
clang-format committed
65
    for (int j = 0; j < 8; ++j) temp_in[j] = input[j * 8 + i];
66
    reference_8x8_dct_1d(temp_in, temp_out, 1);
clang-format's avatar
clang-format committed
67
    for (int j = 0; j < 8; ++j) output[j * 8 + i] = temp_out[j];
68
69
70
71
  }
  // Then transform rows
  for (int i = 0; i < 8; ++i) {
    double temp_in[8], temp_out[8];
clang-format's avatar
clang-format committed
72
    for (int j = 0; j < 8; ++j) temp_in[j] = output[j + i * 8];
73
74
    reference_8x8_dct_1d(temp_in, temp_out, 1);
    // Scale by some magic number
clang-format's avatar
clang-format committed
75
    for (int j = 0; j < 8; ++j) output[j + i * 8] = temp_out[j] * 2;
76
  }
Daniel Kang's avatar
Daniel Kang committed
77
78
}

79
void fdct8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
80
  vpx_fdct8x8_c(in, out, stride);
Jingning Han's avatar
Jingning Han committed
81
}
82

83
void fht8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
84
  vp10_fht8x8_c(in, out, stride, tx_type);
Jingning Han's avatar
Jingning Han committed
85
86
}

87
#if CONFIG_VPX_HIGHBITDEPTH
88
void idct8x8_10(const tran_low_t *in, uint8_t *out, int stride) {
89
  vpx_highbd_idct8x8_64_add_c(in, out, stride, 10);
90
91
92
}

void idct8x8_12(const tran_low_t *in, uint8_t *out, int stride) {
93
  vpx_highbd_idct8x8_64_add_c(in, out, stride, 12);
94
95
96
}

void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
97
  vp10_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 10);
98
99
100
}

void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
101
  vp10_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 12);
102
}
103
104

void idct8x8_10_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
105
  vpx_highbd_idct8x8_10_add_c(in, out, stride, 10);
106
107
108
}

void idct8x8_10_add_12_c(const tran_low_t *in, uint8_t *out, int stride) {
109
  vpx_highbd_idct8x8_10_add_c(in, out, stride, 12);
110
111
112
113
}

#if HAVE_SSE2
void idct8x8_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
114
  vpx_highbd_idct8x8_10_add_sse2(in, out, stride, 10);
115
116
117
}

void idct8x8_10_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
118
  vpx_highbd_idct8x8_10_add_sse2(in, out, stride, 12);
119
120
121
}

void idct8x8_64_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
122
  vpx_highbd_idct8x8_64_add_sse2(in, out, stride, 10);
123
124
125
}

void idct8x8_64_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
126
  vpx_highbd_idct8x8_64_add_sse2(in, out, stride, 12);
127
128
}
#endif  // HAVE_SSE2
129
#endif  // CONFIG_VPX_HIGHBITDEPTH
130

131
class FwdTrans8x8TestBase {
Jingning Han's avatar
Jingning Han committed
132
 public:
133
  virtual ~FwdTrans8x8TestBase() {}
Jingning Han's avatar
Jingning Han committed
134
135

 protected:
136
137
  virtual void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) = 0;
  virtual void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) = 0;
Jingning Han's avatar
Jingning Han committed
138

139
140
  void RunSignBiasCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
141
142
    DECLARE_ALIGNED(16, int16_t, test_input_block[64]);
    DECLARE_ALIGNED(16, tran_low_t, test_output_block[64]);
143
144
    int count_sign_block[64][2];
    const int count_test_block = 100000;
Daniel Kang's avatar
Daniel Kang committed
145

146
    memset(count_sign_block, 0, sizeof(count_sign_block));
Daniel Kang's avatar
Daniel Kang committed
147

148
149
150
    for (int i = 0; i < count_test_block; ++i) {
      // Initialize a test block with input range [-255, 255].
      for (int j = 0; j < 64; ++j)
151
152
        test_input_block[j] = ((rnd.Rand16() >> (16 - bit_depth_)) & mask_) -
                              ((rnd.Rand16() >> (16 - bit_depth_)) & mask_);
153
      ASM_REGISTER_STATE_CHECK(
154
          RunFwdTxfm(test_input_block, test_output_block, pitch_));
Daniel Kang's avatar
Daniel Kang committed
155

156
157
158
159
160
161
162
      for (int j = 0; j < 64; ++j) {
        if (test_output_block[j] < 0)
          ++count_sign_block[j][0];
        else if (test_output_block[j] > 0)
          ++count_sign_block[j][1];
      }
    }
Daniel Kang's avatar
Daniel Kang committed
163
164

    for (int j = 0; j < 64; ++j) {
165
      const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
166
      const int max_diff = kSignBiasMaxDiff255;
167
      EXPECT_LT(diff, max_diff << (bit_depth_ - 8))
168
169
170
171
          << "Error: 8x8 FDCT/FHT has a sign bias > "
          << 1. * max_diff / count_test_block * 100 << "%"
          << " for input range [-255, 255] at index " << j
          << " count0: " << count_sign_block[j][0]
clang-format's avatar
clang-format committed
172
          << " count1: " << count_sign_block[j][1] << " diff: " << diff;
Daniel Kang's avatar
Daniel Kang committed
173
174
    }

175
    memset(count_sign_block, 0, sizeof(count_sign_block));
Daniel Kang's avatar
Daniel Kang committed
176

177
    for (int i = 0; i < count_test_block; ++i) {
178
      // Initialize a test block with input range [-mask_ / 16, mask_ / 16].
179
      for (int j = 0; j < 64; ++j)
clang-format's avatar
clang-format committed
180
181
        test_input_block[j] =
            ((rnd.Rand16() & mask_) >> 4) - ((rnd.Rand16() & mask_) >> 4);
182
      ASM_REGISTER_STATE_CHECK(
183
          RunFwdTxfm(test_input_block, test_output_block, pitch_));
Daniel Kang's avatar
Daniel Kang committed
184

185
186
187
188
189
190
191
      for (int j = 0; j < 64; ++j) {
        if (test_output_block[j] < 0)
          ++count_sign_block[j][0];
        else if (test_output_block[j] > 0)
          ++count_sign_block[j][1];
      }
    }
Daniel Kang's avatar
Daniel Kang committed
192
193

    for (int j = 0; j < 64; ++j) {
194
      const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
195
      const int max_diff = kSignBiasMaxDiff15;
196
      EXPECT_LT(diff, max_diff << (bit_depth_ - 8))
197
          << "Error: 8x8 FDCT/FHT has a sign bias > "
198
199
200
          << 1. * max_diff / count_test_block * 100 << "%"
          << " for input range [-15, 15] at index " << j
          << " count0: " << count_sign_block[j][0]
clang-format's avatar
clang-format committed
201
          << " count1: " << count_sign_block[j][1] << " diff: " << diff;
Daniel Kang's avatar
Daniel Kang committed
202
203
204
    }
  }

205
206
207
208
209
  void RunRoundTripErrorCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    int max_error = 0;
    int total_error = 0;
    const int count_test_block = 100000;
210
211
212
213
    DECLARE_ALIGNED(16, int16_t, test_input_block[64]);
    DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]);
    DECLARE_ALIGNED(16, uint8_t, dst[64]);
    DECLARE_ALIGNED(16, uint8_t, src[64]);
214
#if CONFIG_VPX_HIGHBITDEPTH
215
216
    DECLARE_ALIGNED(16, uint16_t, dst16[64]);
    DECLARE_ALIGNED(16, uint16_t, src16[64]);
217
#endif
Daniel Kang's avatar
Daniel Kang committed
218

219
    for (int i = 0; i < count_test_block; ++i) {
220
      // Initialize a test block with input range [-mask_, mask_].
221
      for (int j = 0; j < 64; ++j) {
222
223
224
225
        if (bit_depth_ == VPX_BITS_8) {
          src[j] = rnd.Rand8();
          dst[j] = rnd.Rand8();
          test_input_block[j] = src[j] - dst[j];
226
#if CONFIG_VPX_HIGHBITDEPTH
227
228
229
230
231
232
        } else {
          src16[j] = rnd.Rand16() & mask_;
          dst16[j] = rnd.Rand16() & mask_;
          test_input_block[j] = src16[j] - dst16[j];
#endif
        }
233
      }
Daniel Kang's avatar
Daniel Kang committed
234

235
      ASM_REGISTER_STATE_CHECK(
236
237
          RunFwdTxfm(test_input_block, test_temp_block, pitch_));
      for (int j = 0; j < 64; ++j) {
clang-format's avatar
clang-format committed
238
239
240
241
242
243
244
245
246
        if (test_temp_block[j] > 0) {
          test_temp_block[j] += 2;
          test_temp_block[j] /= 4;
          test_temp_block[j] *= 4;
        } else {
          test_temp_block[j] -= 2;
          test_temp_block[j] /= 4;
          test_temp_block[j] *= 4;
        }
247
      }
248
      if (bit_depth_ == VPX_BITS_8) {
clang-format's avatar
clang-format committed
249
        ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
250
#if CONFIG_VPX_HIGHBITDEPTH
251
252
253
254
255
      } else {
        ASM_REGISTER_STATE_CHECK(
            RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
      }
256
257

      for (int j = 0; j < 64; ++j) {
258
#if CONFIG_VPX_HIGHBITDEPTH
259
260
261
        const int diff =
            bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
262
        const int diff = dst[j] - src[j];
263
#endif
264
        const int error = diff * diff;
clang-format's avatar
clang-format committed
265
        if (max_error < error) max_error = error;
266
267
        total_error += error;
      }
Daniel Kang's avatar
Daniel Kang committed
268
269
    }

270
    EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error)
clang-format's avatar
clang-format committed
271
272
        << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual"
        << " roundtrip error > 1";
Daniel Kang's avatar
Daniel Kang committed
273

clang-format's avatar
clang-format committed
274
275
276
    EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8)) / 5, total_error)
        << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip "
        << "error > 1/5 per block";
277
  }
Daniel Kang's avatar
Daniel Kang committed
278

279
280
281
282
  void RunExtremalCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    int max_error = 0;
    int total_error = 0;
283
    int total_coeff_error = 0;
284
    const int count_test_block = 100000;
285
286
287
288
289
    DECLARE_ALIGNED(16, int16_t, test_input_block[64]);
    DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]);
    DECLARE_ALIGNED(16, tran_low_t, ref_temp_block[64]);
    DECLARE_ALIGNED(16, uint8_t, dst[64]);
    DECLARE_ALIGNED(16, uint8_t, src[64]);
290
#if CONFIG_VPX_HIGHBITDEPTH
291
292
    DECLARE_ALIGNED(16, uint16_t, dst16[64]);
    DECLARE_ALIGNED(16, uint16_t, src16[64]);
293
#endif
Daniel Kang's avatar
Daniel Kang committed
294

295
    for (int i = 0; i < count_test_block; ++i) {
296
      // Initialize a test block with input range [-mask_, mask_].
297
      for (int j = 0; j < 64; ++j) {
298
299
300
301
302
303
304
305
306
307
308
309
        if (bit_depth_ == VPX_BITS_8) {
          if (i == 0) {
            src[j] = 255;
            dst[j] = 0;
          } else if (i == 1) {
            src[j] = 0;
            dst[j] = 255;
          } else {
            src[j] = rnd.Rand8() % 2 ? 255 : 0;
            dst[j] = rnd.Rand8() % 2 ? 255 : 0;
          }
          test_input_block[j] = src[j] - dst[j];
310
#if CONFIG_VPX_HIGHBITDEPTH
311
        } else {
312
313
314
315
316
317
318
319
320
321
322
323
          if (i == 0) {
            src16[j] = mask_;
            dst16[j] = 0;
          } else if (i == 1) {
            src16[j] = 0;
            dst16[j] = mask_;
          } else {
            src16[j] = rnd.Rand8() % 2 ? mask_ : 0;
            dst16[j] = rnd.Rand8() % 2 ? mask_ : 0;
          }
          test_input_block[j] = src16[j] - dst16[j];
#endif
324
        }
325
      }
Daniel Kang's avatar
Daniel Kang committed
326

327
      ASM_REGISTER_STATE_CHECK(
328
          RunFwdTxfm(test_input_block, test_temp_block, pitch_));
329
      ASM_REGISTER_STATE_CHECK(
330
          fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_));
331
      if (bit_depth_ == VPX_BITS_8) {
clang-format's avatar
clang-format committed
332
        ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
333
#if CONFIG_VPX_HIGHBITDEPTH
334
335
336
337
338
      } else {
        ASM_REGISTER_STATE_CHECK(
            RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
      }
339
340

      for (int j = 0; j < 64; ++j) {
341
#if CONFIG_VPX_HIGHBITDEPTH
342
343
344
        const int diff =
            bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
345
        const int diff = dst[j] - src[j];
346
#endif
347
        const int error = diff * diff;
clang-format's avatar
clang-format committed
348
        if (max_error < error) max_error = error;
349
        total_error += error;
350
351
352

        const int coeff_diff = test_temp_block[j] - ref_temp_block[j];
        total_coeff_error += abs(coeff_diff);
353
354
      }

355
      EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error)
356
357
358
          << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has"
          << "an individual roundtrip error > 1";

clang-format's avatar
clang-format committed
359
      EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8)) / 5, total_error)
360
361
          << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average"
          << " roundtrip error > 1/5 per block";
362
363
364
365

      EXPECT_EQ(0, total_coeff_error)
          << "Error: Extremal 8x8 FDCT/FHT has"
          << "overflow issues in the intermediate steps > 1";
Daniel Kang's avatar
Daniel Kang committed
366
    }
367
  }
Daniel Kang's avatar
Daniel Kang committed
368

369
370
371
  void RunInvAccuracyCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    const int count_test_block = 1000;
372
373
374
375
    DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]);
    DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
    DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]);
    DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]);
376
#if CONFIG_VPX_HIGHBITDEPTH
377
378
    DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
    DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
379
380
381
382
383
384
385
386
387
388
389
#endif

    for (int i = 0; i < count_test_block; ++i) {
      double out_r[kNumCoeffs];

      // Initialize a test block with input range [-255, 255].
      for (int j = 0; j < kNumCoeffs; ++j) {
        if (bit_depth_ == VPX_BITS_8) {
          src[j] = rnd.Rand8() % 2 ? 255 : 0;
          dst[j] = src[j] > 0 ? 0 : 255;
          in[j] = src[j] - dst[j];
390
#if CONFIG_VPX_HIGHBITDEPTH
391
392
393
394
395
396
397
398
399
400
        } else {
          src16[j] = rnd.Rand8() % 2 ? mask_ : 0;
          dst16[j] = src16[j] > 0 ? 0 : mask_;
          in[j] = src16[j] - dst16[j];
#endif
        }
      }

      reference_8x8_dct_2d(in, out_r);
      for (int j = 0; j < kNumCoeffs; ++j)
401
        coeff[j] = static_cast<tran_low_t>(round(out_r[j]));
402
403
404

      if (bit_depth_ == VPX_BITS_8) {
        ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
405
#if CONFIG_VPX_HIGHBITDEPTH
406
      } else {
clang-format's avatar
clang-format committed
407
408
        ASM_REGISTER_STATE_CHECK(
            RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16), pitch_));
409
410
411
412
#endif
      }

      for (int j = 0; j < kNumCoeffs; ++j) {
413
#if CONFIG_VPX_HIGHBITDEPTH
414
415
416
417
418
419
420
        const uint32_t diff =
            bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
        const uint32_t diff = dst[j] - src[j];
#endif
        const uint32_t error = diff * diff;
        EXPECT_GE(1u << 2 * (bit_depth_ - 8), error)
clang-format's avatar
clang-format committed
421
            << "Error: 8x8 IDCT has error " << error << " at index " << j;
422
423
424
425
426
427
428
      }
    }
  }

  void RunFwdAccuracyCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    const int count_test_block = 1000;
429
430
431
    DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]);
    DECLARE_ALIGNED(16, tran_low_t, coeff_r[kNumCoeffs]);
    DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
432
433
434
435
436
437
438
439
440
441
442

    for (int i = 0; i < count_test_block; ++i) {
      double out_r[kNumCoeffs];

      // Initialize a test block with input range [-mask_, mask_].
      for (int j = 0; j < kNumCoeffs; ++j)
        in[j] = rnd.Rand8() % 2 == 0 ? mask_ : -mask_;

      RunFwdTxfm(in, coeff, pitch_);
      reference_8x8_dct_2d(in, out_r);
      for (int j = 0; j < kNumCoeffs; ++j)
443
        coeff_r[j] = static_cast<tran_low_t>(round(out_r[j]));
444
445
446
447
448

      for (int j = 0; j < kNumCoeffs; ++j) {
        const uint32_t diff = coeff[j] - coeff_r[j];
        const uint32_t error = diff * diff;
        EXPECT_GE(9u << 2 * (bit_depth_ - 8), error)
clang-format's avatar
clang-format committed
449
            << "Error: 8x8 DCT has error " << error << " at index " << j;
450
451
452
      }
    }
  }
453

clang-format's avatar
clang-format committed
454
  void CompareInvReference(IdctFunc ref_txfm, int thresh) {
455
456
457
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    const int count_test_block = 10000;
    const int eob = 12;
458
459
460
    DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
    DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]);
    DECLARE_ALIGNED(16, uint8_t, ref[kNumCoeffs]);
461
#if CONFIG_VPX_HIGHBITDEPTH
462
463
    DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
    DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]);
464
#endif
465
    const int16_t *scan = vp10_default_scan_orders[TX_8X8].scan;
466
467
468
469
470

    for (int i = 0; i < count_test_block; ++i) {
      for (int j = 0; j < kNumCoeffs; ++j) {
        if (j < eob) {
          // Random values less than the threshold, either positive or negative
clang-format's avatar
clang-format committed
471
          coeff[scan[j]] = rnd(thresh) * (1 - 2 * (i % 2));
472
473
474
475
476
477
        } else {
          coeff[scan[j]] = 0;
        }
        if (bit_depth_ == VPX_BITS_8) {
          dst[j] = 0;
          ref[j] = 0;
478
#if CONFIG_VPX_HIGHBITDEPTH
479
480
481
482
483
484
485
486
487
        } else {
          dst16[j] = 0;
          ref16[j] = 0;
#endif
        }
      }
      if (bit_depth_ == VPX_BITS_8) {
        ref_txfm(coeff, ref, pitch_);
        ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
488
#if CONFIG_VPX_HIGHBITDEPTH
489
490
      } else {
        ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
clang-format's avatar
clang-format committed
491
492
        ASM_REGISTER_STATE_CHECK(
            RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16), pitch_));
493
494
495
496
#endif
      }

      for (int j = 0; j < kNumCoeffs; ++j) {
497
#if CONFIG_VPX_HIGHBITDEPTH
498
499
500
501
502
503
        const uint32_t diff =
            bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j];
#else
        const uint32_t diff = dst[j] - ref[j];
#endif
        const uint32_t error = diff * diff;
clang-format's avatar
clang-format committed
504
505
        EXPECT_EQ(0u, error) << "Error: 8x8 IDCT has error " << error
                             << " at index " << j;
506
507
508
      }
    }
  }
509
510
  int pitch_;
  int tx_type_;
511
  FhtFunc fwd_txfm_ref;
512
513
  vpx_bit_depth_t bit_depth_;
  int mask_;
514
};
Daniel Kang's avatar
Daniel Kang committed
515

clang-format's avatar
clang-format committed
516
517
class FwdTrans8x8DCT : public FwdTrans8x8TestBase,
                       public ::testing::TestWithParam<Dct8x8Param> {
518
519
520
521
522
523
 public:
  virtual ~FwdTrans8x8DCT() {}

  virtual void SetUp() {
    fwd_txfm_ = GET_PARAM(0);
    inv_txfm_ = GET_PARAM(1);
clang-format's avatar
clang-format committed
524
525
    tx_type_ = GET_PARAM(2);
    pitch_ = 8;
526
    fwd_txfm_ref = fdct8x8_ref;
527
528
    bit_depth_ = GET_PARAM(3);
    mask_ = (1 << bit_depth_) - 1;
529
530
531
532
533
  }

  virtual void TearDown() { libvpx_test::ClearSystemState(); }

 protected:
534
  void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) {
535
536
    fwd_txfm_(in, out, stride);
  }
537
  void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
538
    inv_txfm_(out, dst, stride);
Daniel Kang's avatar
Daniel Kang committed
539
  }
540

541
542
  FdctFunc fwd_txfm_;
  IdctFunc inv_txfm_;
543
544
};

clang-format's avatar
clang-format committed
545
TEST_P(FwdTrans8x8DCT, SignBiasCheck) { RunSignBiasCheck(); }
Daniel Kang's avatar
Daniel Kang committed
546

clang-format's avatar
clang-format committed
547
TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); }
548

clang-format's avatar
clang-format committed
549
TEST_P(FwdTrans8x8DCT, ExtremalCheck) { RunExtremalCheck(); }
550

clang-format's avatar
clang-format committed
551
TEST_P(FwdTrans8x8DCT, FwdAccuracyCheck) { RunFwdAccuracyCheck(); }
552

clang-format's avatar
clang-format committed
553
TEST_P(FwdTrans8x8DCT, InvAccuracyCheck) { RunInvAccuracyCheck(); }
554

clang-format's avatar
clang-format committed
555
556
class FwdTrans8x8HT : public FwdTrans8x8TestBase,
                      public ::testing::TestWithParam<Ht8x8Param> {
557
558
559
560
561
562
 public:
  virtual ~FwdTrans8x8HT() {}

  virtual void SetUp() {
    fwd_txfm_ = GET_PARAM(0);
    inv_txfm_ = GET_PARAM(1);
clang-format's avatar
clang-format committed
563
564
    tx_type_ = GET_PARAM(2);
    pitch_ = 8;
565
    fwd_txfm_ref = fht8x8_ref;
566
567
    bit_depth_ = GET_PARAM(3);
    mask_ = (1 << bit_depth_) - 1;
568
569
570
571
572
  }

  virtual void TearDown() { libvpx_test::ClearSystemState(); }

 protected:
573
  void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) {
574
575
    fwd_txfm_(in, out, stride, tx_type_);
  }
576
  void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
577
578
579
    inv_txfm_(out, dst, stride, tx_type_);
  }

580
581
  FhtFunc fwd_txfm_;
  IhtFunc inv_txfm_;
582
583
};

clang-format's avatar
clang-format committed
584
TEST_P(FwdTrans8x8HT, SignBiasCheck) { RunSignBiasCheck(); }
585

clang-format's avatar
clang-format committed
586
TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); }
587

clang-format's avatar
clang-format committed
588
TEST_P(FwdTrans8x8HT, ExtremalCheck) { RunExtremalCheck(); }
589

clang-format's avatar
clang-format committed
590
591
class InvTrans8x8DCT : public FwdTrans8x8TestBase,
                       public ::testing::TestWithParam<Idct8x8Param> {
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
 public:
  virtual ~InvTrans8x8DCT() {}

  virtual void SetUp() {
    ref_txfm_ = GET_PARAM(0);
    inv_txfm_ = GET_PARAM(1);
    thresh_ = GET_PARAM(2);
    pitch_ = 8;
    bit_depth_ = GET_PARAM(3);
    mask_ = (1 << bit_depth_) - 1;
  }

  virtual void TearDown() { libvpx_test::ClearSystemState(); }

 protected:
  void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
    inv_txfm_(out, dst, stride);
  }
  void RunFwdTxfm(int16_t *out, tran_low_t *dst, int stride) {}

  IdctFunc ref_txfm_;
  IdctFunc inv_txfm_;
  int thresh_;
};

TEST_P(InvTrans8x8DCT, CompareReference) {
  CompareInvReference(ref_txfm_, thresh_);
}

621
622
using std::tr1::make_tuple;

623
#if CONFIG_VPX_HIGHBITDEPTH
624
625
626
INSTANTIATE_TEST_CASE_P(
    C, FwdTrans8x8DCT,
    ::testing::Values(
627
        make_tuple(&vpx_fdct8x8_c, &vpx_idct8x8_64_add_c, 0, VPX_BITS_8),
628
629
        make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_10, 0, VPX_BITS_10),
        make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_12, 0, VPX_BITS_12)));
630
#else
clang-format's avatar
clang-format committed
631
632
633
634
INSTANTIATE_TEST_CASE_P(C, FwdTrans8x8DCT,
                        ::testing::Values(make_tuple(&vpx_fdct8x8_c,
                                                     &vpx_idct8x8_64_add_c, 0,
                                                     VPX_BITS_8)));
635
#endif  // CONFIG_VPX_HIGHBITDEPTH
636

637
#if CONFIG_VPX_HIGHBITDEPTH
638
639
640
INSTANTIATE_TEST_CASE_P(
    C, FwdTrans8x8HT,
    ::testing::Values(
641
642
643
644
645
646
647
648
649
650
651
652
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 0, VPX_BITS_8),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 0, VPX_BITS_10),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 1, VPX_BITS_10),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 2, VPX_BITS_10),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 3, VPX_BITS_10),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 0, VPX_BITS_12),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 1, VPX_BITS_12),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 2, VPX_BITS_12),
        make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 3, VPX_BITS_12),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 1, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 2, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 3, VPX_BITS_8)));
653
654
655
656
#else
INSTANTIATE_TEST_CASE_P(
    C, FwdTrans8x8HT,
    ::testing::Values(
657
658
659
660
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 0, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 1, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 2, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 3, VPX_BITS_8)));
661
#endif  // CONFIG_VPX_HIGHBITDEPTH
662

663
#if HAVE_NEON_ASM && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
clang-format's avatar
clang-format committed
664
665
666
667
INSTANTIATE_TEST_CASE_P(NEON, FwdTrans8x8DCT,
                        ::testing::Values(make_tuple(&vpx_fdct8x8_neon,
                                                     &vpx_idct8x8_64_add_neon,
                                                     0, VPX_BITS_8)));
668
#endif  // HAVE_NEON_ASM && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
669

670
#if HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
James Zern's avatar
James Zern committed
671
INSTANTIATE_TEST_CASE_P(
672
    NEON, FwdTrans8x8HT,
James Zern's avatar
James Zern committed
673
    ::testing::Values(
674
675
676
677
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 0, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 1, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 2, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 3, VPX_BITS_8)));
678
#endif  // HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
James Zern's avatar
James Zern committed
679

680
#if HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
clang-format's avatar
clang-format committed
681
682
683
684
INSTANTIATE_TEST_CASE_P(SSE2, FwdTrans8x8DCT,
                        ::testing::Values(make_tuple(&vpx_fdct8x8_sse2,
                                                     &vpx_idct8x8_64_add_sse2,
                                                     0, VPX_BITS_8)));
685
686
687
INSTANTIATE_TEST_CASE_P(
    SSE2, FwdTrans8x8HT,
    ::testing::Values(
688
689
690
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, 0, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, 1, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, 2, VPX_BITS_8),
clang-format's avatar
clang-format committed
691
692
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, 3,
                   VPX_BITS_8)));
693
#endif  // HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
694

695
#if HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
696
697
INSTANTIATE_TEST_CASE_P(
    SSE2, FwdTrans8x8DCT,
clang-format's avatar
clang-format committed
698
699
700
701
702
703
704
705
706
707
    ::testing::Values(make_tuple(&vpx_fdct8x8_sse2, &vpx_idct8x8_64_add_c, 0,
                                 VPX_BITS_8),
                      make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_10_sse2,
                                 12, VPX_BITS_10),
                      make_tuple(&vpx_highbd_fdct8x8_sse2,
                                 &idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
                      make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_12_sse2,
                                 12, VPX_BITS_12),
                      make_tuple(&vpx_highbd_fdct8x8_sse2,
                                 &idct8x8_64_add_12_sse2, 12, VPX_BITS_12)));
708
709
710
711

INSTANTIATE_TEST_CASE_P(
    SSE2, FwdTrans8x8HT,
    ::testing::Values(
712
713
714
715
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 0, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 1, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 2, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 3, VPX_BITS_8)));
716
717
718
719
720
721

// Optimizations take effect at a threshold of 6201, so we use a value close to
// that to test both branches.
INSTANTIATE_TEST_CASE_P(
    SSE2, InvTrans8x8DCT,
    ::testing::Values(
clang-format's avatar
clang-format committed
722
723
724
725
726
727
        make_tuple(&idct8x8_10_add_10_c, &idct8x8_10_add_10_sse2, 6225,
                   VPX_BITS_10),
        make_tuple(&idct8x8_10, &idct8x8_64_add_10_sse2, 6225, VPX_BITS_10),
        make_tuple(&idct8x8_10_add_12_c, &idct8x8_10_add_12_sse2, 6225,
                   VPX_BITS_12),
        make_tuple(&idct8x8_12, &idct8x8_64_add_12_sse2, 6225, VPX_BITS_12)));
728
#endif  // HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
729

Johann's avatar
Johann committed
730
#if HAVE_SSSE3 && CONFIG_USE_X86INC && ARCH_X86_64 && \
731
    !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
clang-format's avatar
clang-format committed
732
733
734
735
INSTANTIATE_TEST_CASE_P(SSSE3, FwdTrans8x8DCT,
                        ::testing::Values(make_tuple(&vpx_fdct8x8_ssse3,
                                                     &vpx_idct8x8_64_add_ssse3,
                                                     0, VPX_BITS_8)));
736
#endif
737

738
#if HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
clang-format's avatar
clang-format committed
739
740
741
742
INSTANTIATE_TEST_CASE_P(MSA, FwdTrans8x8DCT,
                        ::testing::Values(make_tuple(&vpx_fdct8x8_msa,
                                                     &vpx_idct8x8_64_add_msa, 0,
                                                     VPX_BITS_8)));
743
744
745
INSTANTIATE_TEST_CASE_P(
    MSA, FwdTrans8x8HT,
    ::testing::Values(
746
747
748
749
        make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 0, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 1, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 2, VPX_BITS_8),
        make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 3, VPX_BITS_8)));
750
#endif  // HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
Daniel Kang's avatar
Daniel Kang committed
751
}  // namespace