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

Yaowu Xu's avatar
Yaowu Xu committed
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 "vp10/common/entropy.h"
#include "vp10/common/scan.h"
25
#include "vpx/vpx_codec.h"
26
#include "vpx/vpx_integer.h"
27
#include "vpx_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
void reference_8x8_dct_1d(const double in[8], double out[8]) {
51
52
53
54
55
  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);
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
    reference_8x8_dct_1d(temp_in, temp_out);
74
    // 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
80
void fdct8x8_ref(const int16_t *in, tran_low_t *out, int stride,
                 int /*tx_type*/) {
81
  vpx_fdct8x8_c(in, out, stride);
Jingning Han's avatar
Jingning Han committed
82
}
83

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

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

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

void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
Yaowu Xu's avatar
Yaowu Xu committed
98
  vp10_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 10);
99
100
101
}

void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
Yaowu Xu's avatar
Yaowu Xu committed
102
  vp10_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 12);
103
}
104

105
106
#if HAVE_SSE2

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

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

void idct8x8_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
116
  vpx_highbd_idct8x8_10_add_sse2(in, out, stride, 10);
117
118
119
}

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

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

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

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

 protected:
138
139
  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
140

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

148
    memset(count_sign_block, 0, sizeof(count_sign_block));
Daniel Kang's avatar
Daniel Kang committed
149

150
151
152
    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)
153
154
        test_input_block[j] = ((rnd.Rand16() >> (16 - bit_depth_)) & mask_) -
                              ((rnd.Rand16() >> (16 - bit_depth_)) & mask_);
155
      ASM_REGISTER_STATE_CHECK(
156
          RunFwdTxfm(test_input_block, test_output_block, pitch_));
Daniel Kang's avatar
Daniel Kang committed
157

158
159
160
161
162
163
164
      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
165
166

    for (int j = 0; j < 64; ++j) {
167
      const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
168
      const int max_diff = kSignBiasMaxDiff255;
169
      EXPECT_LT(diff, max_diff << (bit_depth_ - 8))
170
171
172
173
          << "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
174
          << " count1: " << count_sign_block[j][1] << " diff: " << diff;
Daniel Kang's avatar
Daniel Kang committed
175
176
    }

177
    memset(count_sign_block, 0, sizeof(count_sign_block));
Daniel Kang's avatar
Daniel Kang committed
178

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

187
188
189
190
191
192
193
      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
194
195

    for (int j = 0; j < 64; ++j) {
196
      const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
197
      const int max_diff = kSignBiasMaxDiff15;
198
      EXPECT_LT(diff, max_diff << (bit_depth_ - 8))
199
          << "Error: 8x8 FDCT/FHT has a sign bias > "
200
201
202
          << 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
203
          << " count1: " << count_sign_block[j][1] << " diff: " << diff;
Daniel Kang's avatar
Daniel Kang committed
204
205
206
    }
  }

207
208
209
210
211
  void RunRoundTripErrorCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    int max_error = 0;
    int total_error = 0;
    const int count_test_block = 100000;
212
213
214
215
    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]);
216
#if CONFIG_VP9_HIGHBITDEPTH
217
218
    DECLARE_ALIGNED(16, uint16_t, dst16[64]);
    DECLARE_ALIGNED(16, uint16_t, src16[64]);
219
#endif
Daniel Kang's avatar
Daniel Kang committed
220

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

237
      ASM_REGISTER_STATE_CHECK(
238
239
          RunFwdTxfm(test_input_block, test_temp_block, pitch_));
      for (int j = 0; j < 64; ++j) {
clang-format's avatar
clang-format committed
240
241
242
243
244
245
246
247
248
        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;
        }
249
      }
250
      if (bit_depth_ == VPX_BITS_8) {
clang-format's avatar
clang-format committed
251
        ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
252
253
254
255
256
257
#if CONFIG_VP9_HIGHBITDEPTH
      } else {
        ASM_REGISTER_STATE_CHECK(
            RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
      }
258
259

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

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

clang-format's avatar
clang-format committed
276
277
278
    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";
279
  }
Daniel Kang's avatar
Daniel Kang committed
280

281
282
283
284
  void RunExtremalCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    int max_error = 0;
    int total_error = 0;
285
    int total_coeff_error = 0;
286
    const int count_test_block = 100000;
287
288
289
290
291
    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]);
292
#if CONFIG_VP9_HIGHBITDEPTH
293
294
    DECLARE_ALIGNED(16, uint16_t, dst16[64]);
    DECLARE_ALIGNED(16, uint16_t, src16[64]);
295
#endif
Daniel Kang's avatar
Daniel Kang committed
296

297
    for (int i = 0; i < count_test_block; ++i) {
298
      // Initialize a test block with input range [-mask_, mask_].
299
      for (int j = 0; j < 64; ++j) {
300
301
302
303
304
305
306
307
308
309
310
311
312
        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];
#if CONFIG_VP9_HIGHBITDEPTH
313
        } else {
314
315
316
317
318
319
320
321
322
323
324
325
          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
326
        }
327
      }
Daniel Kang's avatar
Daniel Kang committed
328

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

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

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

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

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

      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
368
    }
369
  }
Daniel Kang's avatar
Daniel Kang committed
370

371
372
373
  void RunInvAccuracyCheck() {
    ACMRandom rnd(ACMRandom::DeterministicSeed());
    const int count_test_block = 1000;
374
375
376
377
    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]);
378
#if CONFIG_VP9_HIGHBITDEPTH
379
380
    DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
    DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
#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];
#if CONFIG_VP9_HIGHBITDEPTH
        } 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)
403
        coeff[j] = static_cast<tran_low_t>(round(out_r[j]));
404
405
406
407
408

      if (bit_depth_ == VPX_BITS_8) {
        ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH
      } else {
clang-format's avatar
clang-format committed
409
410
        ASM_REGISTER_STATE_CHECK(
            RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16), pitch_));
411
412
413
414
415
#endif
      }

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

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

    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)
445
        coeff_r[j] = static_cast<tran_low_t>(round(out_r[j]));
446
447

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

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

    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
473
          coeff[scan[j]] = rnd(thresh) * (1 - 2 * (i % 2));
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
        } else {
          coeff[scan[j]] = 0;
        }
        if (bit_depth_ == VPX_BITS_8) {
          dst[j] = 0;
          ref[j] = 0;
#if CONFIG_VP9_HIGHBITDEPTH
        } 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_));
#if CONFIG_VP9_HIGHBITDEPTH
      } else {
        ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
clang-format's avatar
clang-format committed
493
494
        ASM_REGISTER_STATE_CHECK(
            RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16), pitch_));
495
496
497
498
499
#endif
      }

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

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

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

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

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

543
544
  FdctFunc fwd_txfm_;
  IdctFunc inv_txfm_;
545
546
};

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

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

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

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

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

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

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

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

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

582
583
  FhtFunc fwd_txfm_;
  IhtFunc inv_txfm_;
584
585
};

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

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

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

clang-format's avatar
clang-format committed
592
593
class InvTrans8x8DCT : public FwdTrans8x8TestBase,
                       public ::testing::TestWithParam<Idct8x8Param> {
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
 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);
  }
612
  void RunFwdTxfm(int16_t * /*out*/, tran_low_t * /*dst*/, int /*stride*/) {}
613
614
615
616
617
618
619
620
621
622

  IdctFunc ref_txfm_;
  IdctFunc inv_txfm_;
  int thresh_;
};

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

623
624
using std::tr1::make_tuple;

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

#if CONFIG_VP9_HIGHBITDEPTH
640
641
642
INSTANTIATE_TEST_CASE_P(
    C, FwdTrans8x8HT,
    ::testing::Values(
Yaowu Xu's avatar
Yaowu Xu committed
643
644
645
646
647
648
649
650
651
652
653
654
        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)));
655
656
657
658
#else
INSTANTIATE_TEST_CASE_P(
    C, FwdTrans8x8HT,
    ::testing::Values(
Yaowu Xu's avatar
Yaowu Xu committed
659
660
661
662
        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)));
663
#endif  // CONFIG_VP9_HIGHBITDEPTH
664

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

#if HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
James Zern's avatar
James Zern committed
673
INSTANTIATE_TEST_CASE_P(
674
    NEON, FwdTrans8x8HT,
James Zern's avatar
James Zern committed
675
    ::testing::Values(
Yaowu Xu's avatar
Yaowu Xu committed
676
677
678
679
        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)));
680
#endif  // HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
James Zern's avatar
James Zern committed
681

682
#if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
clang-format's avatar
clang-format committed
683
684
685
686
INSTANTIATE_TEST_CASE_P(SSE2, FwdTrans8x8DCT,
                        ::testing::Values(make_tuple(&vpx_fdct8x8_sse2,
                                                     &vpx_idct8x8_64_add_sse2,
                                                     0, VPX_BITS_8)));
687
688
689
INSTANTIATE_TEST_CASE_P(
    SSE2, FwdTrans8x8HT,
    ::testing::Values(
clang-format's avatar
clang-format committed
690
691
692
693
694
        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),
        make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, 3,
                   VPX_BITS_8)));
695
696
697
698
699
#endif  // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE

#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
    SSE2, FwdTrans8x8DCT,
clang-format's avatar
clang-format committed
700
701
702
703
704
705
706
707
708
709
    ::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)));
710
711
712
713

INSTANTIATE_TEST_CASE_P(
    SSE2, FwdTrans8x8HT,
    ::testing::Values(
Yaowu Xu's avatar
Yaowu Xu committed
714
715
716
717
        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)));
718
719
720
721
722
723

// 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
724
725
726
727
728
729
        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)));
730
#endif  // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
731

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

740
#if HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
clang-format's avatar
clang-format committed
741
742
743
744
INSTANTIATE_TEST_CASE_P(MSA, FwdTrans8x8DCT,
                        ::testing::Values(make_tuple(&vpx_fdct8x8_msa,
                                                     &vpx_idct8x8_64_add_msa, 0,
                                                     VPX_BITS_8)));
745
#if !CONFIG_EXT_TX
746
747
748
INSTANTIATE_TEST_CASE_P(
    MSA, FwdTrans8x8HT,
    ::testing::Values(
Yaowu Xu's avatar
Yaowu Xu committed
749
750
751
752
        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)));
753
#endif  // !CONFIG_EXT_TX
754
#endif  // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
Daniel Kang's avatar
Daniel Kang committed
755
}  // namespace