1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker * Copyright (c) 2013 The WebM project authors. All Rights Reserved.
3*fb1b10abSAndroid Build Coastguard Worker *
4*fb1b10abSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker */
10*fb1b10abSAndroid Build Coastguard Worker
11*fb1b10abSAndroid Build Coastguard Worker #include <math.h>
12*fb1b10abSAndroid Build Coastguard Worker #include <stddef.h>
13*fb1b10abSAndroid Build Coastguard Worker #include <stdio.h>
14*fb1b10abSAndroid Build Coastguard Worker #include <stdlib.h>
15*fb1b10abSAndroid Build Coastguard Worker #include <string.h>
16*fb1b10abSAndroid Build Coastguard Worker #include <sys/types.h>
17*fb1b10abSAndroid Build Coastguard Worker
18*fb1b10abSAndroid Build Coastguard Worker #include "gtest/gtest.h"
19*fb1b10abSAndroid Build Coastguard Worker
20*fb1b10abSAndroid Build Coastguard Worker #include "./vpx_config.h"
21*fb1b10abSAndroid Build Coastguard Worker #include "./vp8_rtcd.h"
22*fb1b10abSAndroid Build Coastguard Worker #include "test/acm_random.h"
23*fb1b10abSAndroid Build Coastguard Worker #include "vpx/vpx_integer.h"
24*fb1b10abSAndroid Build Coastguard Worker #include "vpx_ports/mem.h"
25*fb1b10abSAndroid Build Coastguard Worker
26*fb1b10abSAndroid Build Coastguard Worker namespace {
27*fb1b10abSAndroid Build Coastguard Worker
28*fb1b10abSAndroid Build Coastguard Worker typedef void (*FdctFunc)(int16_t *a, int16_t *b, int a_stride);
29*fb1b10abSAndroid Build Coastguard Worker
30*fb1b10abSAndroid Build Coastguard Worker const int cospi8sqrt2minus1 = 20091;
31*fb1b10abSAndroid Build Coastguard Worker const int sinpi8sqrt2 = 35468;
32*fb1b10abSAndroid Build Coastguard Worker
reference_idct4x4(const int16_t * input,int16_t * output)33*fb1b10abSAndroid Build Coastguard Worker void reference_idct4x4(const int16_t *input, int16_t *output) {
34*fb1b10abSAndroid Build Coastguard Worker const int16_t *ip = input;
35*fb1b10abSAndroid Build Coastguard Worker int16_t *op = output;
36*fb1b10abSAndroid Build Coastguard Worker
37*fb1b10abSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
38*fb1b10abSAndroid Build Coastguard Worker const int a1 = ip[0] + ip[8];
39*fb1b10abSAndroid Build Coastguard Worker const int b1 = ip[0] - ip[8];
40*fb1b10abSAndroid Build Coastguard Worker const int temp1 = (ip[4] * sinpi8sqrt2) >> 16;
41*fb1b10abSAndroid Build Coastguard Worker const int temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
42*fb1b10abSAndroid Build Coastguard Worker const int c1 = temp1 - temp2;
43*fb1b10abSAndroid Build Coastguard Worker const int temp3 = ip[4] + ((ip[4] * cospi8sqrt2minus1) >> 16);
44*fb1b10abSAndroid Build Coastguard Worker const int temp4 = (ip[12] * sinpi8sqrt2) >> 16;
45*fb1b10abSAndroid Build Coastguard Worker const int d1 = temp3 + temp4;
46*fb1b10abSAndroid Build Coastguard Worker op[0] = a1 + d1;
47*fb1b10abSAndroid Build Coastguard Worker op[12] = a1 - d1;
48*fb1b10abSAndroid Build Coastguard Worker op[4] = b1 + c1;
49*fb1b10abSAndroid Build Coastguard Worker op[8] = b1 - c1;
50*fb1b10abSAndroid Build Coastguard Worker ++ip;
51*fb1b10abSAndroid Build Coastguard Worker ++op;
52*fb1b10abSAndroid Build Coastguard Worker }
53*fb1b10abSAndroid Build Coastguard Worker ip = output;
54*fb1b10abSAndroid Build Coastguard Worker op = output;
55*fb1b10abSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) {
56*fb1b10abSAndroid Build Coastguard Worker const int a1 = ip[0] + ip[2];
57*fb1b10abSAndroid Build Coastguard Worker const int b1 = ip[0] - ip[2];
58*fb1b10abSAndroid Build Coastguard Worker const int temp1 = (ip[1] * sinpi8sqrt2) >> 16;
59*fb1b10abSAndroid Build Coastguard Worker const int temp2 = ip[3] + ((ip[3] * cospi8sqrt2minus1) >> 16);
60*fb1b10abSAndroid Build Coastguard Worker const int c1 = temp1 - temp2;
61*fb1b10abSAndroid Build Coastguard Worker const int temp3 = ip[1] + ((ip[1] * cospi8sqrt2minus1) >> 16);
62*fb1b10abSAndroid Build Coastguard Worker const int temp4 = (ip[3] * sinpi8sqrt2) >> 16;
63*fb1b10abSAndroid Build Coastguard Worker const int d1 = temp3 + temp4;
64*fb1b10abSAndroid Build Coastguard Worker op[0] = (a1 + d1 + 4) >> 3;
65*fb1b10abSAndroid Build Coastguard Worker op[3] = (a1 - d1 + 4) >> 3;
66*fb1b10abSAndroid Build Coastguard Worker op[1] = (b1 + c1 + 4) >> 3;
67*fb1b10abSAndroid Build Coastguard Worker op[2] = (b1 - c1 + 4) >> 3;
68*fb1b10abSAndroid Build Coastguard Worker ip += 4;
69*fb1b10abSAndroid Build Coastguard Worker op += 4;
70*fb1b10abSAndroid Build Coastguard Worker }
71*fb1b10abSAndroid Build Coastguard Worker }
72*fb1b10abSAndroid Build Coastguard Worker
73*fb1b10abSAndroid Build Coastguard Worker using libvpx_test::ACMRandom;
74*fb1b10abSAndroid Build Coastguard Worker
75*fb1b10abSAndroid Build Coastguard Worker class FdctTest : public ::testing::TestWithParam<FdctFunc> {
76*fb1b10abSAndroid Build Coastguard Worker public:
SetUp()77*fb1b10abSAndroid Build Coastguard Worker void SetUp() override {
78*fb1b10abSAndroid Build Coastguard Worker fdct_func_ = GetParam();
79*fb1b10abSAndroid Build Coastguard Worker rnd_.Reset(ACMRandom::DeterministicSeed());
80*fb1b10abSAndroid Build Coastguard Worker }
81*fb1b10abSAndroid Build Coastguard Worker
82*fb1b10abSAndroid Build Coastguard Worker protected:
83*fb1b10abSAndroid Build Coastguard Worker FdctFunc fdct_func_;
84*fb1b10abSAndroid Build Coastguard Worker ACMRandom rnd_;
85*fb1b10abSAndroid Build Coastguard Worker };
86*fb1b10abSAndroid Build Coastguard Worker
TEST_P(FdctTest,SignBiasCheck)87*fb1b10abSAndroid Build Coastguard Worker TEST_P(FdctTest, SignBiasCheck) {
88*fb1b10abSAndroid Build Coastguard Worker int16_t test_input_block[16];
89*fb1b10abSAndroid Build Coastguard Worker DECLARE_ALIGNED(16, int16_t, test_output_block[16]);
90*fb1b10abSAndroid Build Coastguard Worker const int pitch = 8;
91*fb1b10abSAndroid Build Coastguard Worker int count_sign_block[16][2];
92*fb1b10abSAndroid Build Coastguard Worker const int count_test_block = 1000000;
93*fb1b10abSAndroid Build Coastguard Worker
94*fb1b10abSAndroid Build Coastguard Worker memset(count_sign_block, 0, sizeof(count_sign_block));
95*fb1b10abSAndroid Build Coastguard Worker
96*fb1b10abSAndroid Build Coastguard Worker for (int i = 0; i < count_test_block; ++i) {
97*fb1b10abSAndroid Build Coastguard Worker // Initialize a test block with input range [-255, 255].
98*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
99*fb1b10abSAndroid Build Coastguard Worker test_input_block[j] = rnd_.Rand8() - rnd_.Rand8();
100*fb1b10abSAndroid Build Coastguard Worker }
101*fb1b10abSAndroid Build Coastguard Worker
102*fb1b10abSAndroid Build Coastguard Worker fdct_func_(test_input_block, test_output_block, pitch);
103*fb1b10abSAndroid Build Coastguard Worker
104*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
105*fb1b10abSAndroid Build Coastguard Worker if (test_output_block[j] < 0) {
106*fb1b10abSAndroid Build Coastguard Worker ++count_sign_block[j][0];
107*fb1b10abSAndroid Build Coastguard Worker } else if (test_output_block[j] > 0) {
108*fb1b10abSAndroid Build Coastguard Worker ++count_sign_block[j][1];
109*fb1b10abSAndroid Build Coastguard Worker }
110*fb1b10abSAndroid Build Coastguard Worker }
111*fb1b10abSAndroid Build Coastguard Worker }
112*fb1b10abSAndroid Build Coastguard Worker
113*fb1b10abSAndroid Build Coastguard Worker bool bias_acceptable = true;
114*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
115*fb1b10abSAndroid Build Coastguard Worker bias_acceptable =
116*fb1b10abSAndroid Build Coastguard Worker bias_acceptable &&
117*fb1b10abSAndroid Build Coastguard Worker (abs(count_sign_block[j][0] - count_sign_block[j][1]) < 10000);
118*fb1b10abSAndroid Build Coastguard Worker }
119*fb1b10abSAndroid Build Coastguard Worker
120*fb1b10abSAndroid Build Coastguard Worker EXPECT_EQ(true, bias_acceptable)
121*fb1b10abSAndroid Build Coastguard Worker << "Error: 4x4 FDCT has a sign bias > 1% for input range [-255, 255]";
122*fb1b10abSAndroid Build Coastguard Worker
123*fb1b10abSAndroid Build Coastguard Worker memset(count_sign_block, 0, sizeof(count_sign_block));
124*fb1b10abSAndroid Build Coastguard Worker
125*fb1b10abSAndroid Build Coastguard Worker for (int i = 0; i < count_test_block; ++i) {
126*fb1b10abSAndroid Build Coastguard Worker // Initialize a test block with input range [-15, 15].
127*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
128*fb1b10abSAndroid Build Coastguard Worker test_input_block[j] = (rnd_.Rand8() >> 4) - (rnd_.Rand8() >> 4);
129*fb1b10abSAndroid Build Coastguard Worker }
130*fb1b10abSAndroid Build Coastguard Worker
131*fb1b10abSAndroid Build Coastguard Worker fdct_func_(test_input_block, test_output_block, pitch);
132*fb1b10abSAndroid Build Coastguard Worker
133*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
134*fb1b10abSAndroid Build Coastguard Worker if (test_output_block[j] < 0) {
135*fb1b10abSAndroid Build Coastguard Worker ++count_sign_block[j][0];
136*fb1b10abSAndroid Build Coastguard Worker } else if (test_output_block[j] > 0) {
137*fb1b10abSAndroid Build Coastguard Worker ++count_sign_block[j][1];
138*fb1b10abSAndroid Build Coastguard Worker }
139*fb1b10abSAndroid Build Coastguard Worker }
140*fb1b10abSAndroid Build Coastguard Worker }
141*fb1b10abSAndroid Build Coastguard Worker
142*fb1b10abSAndroid Build Coastguard Worker bias_acceptable = true;
143*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
144*fb1b10abSAndroid Build Coastguard Worker bias_acceptable =
145*fb1b10abSAndroid Build Coastguard Worker bias_acceptable &&
146*fb1b10abSAndroid Build Coastguard Worker (abs(count_sign_block[j][0] - count_sign_block[j][1]) < 100000);
147*fb1b10abSAndroid Build Coastguard Worker }
148*fb1b10abSAndroid Build Coastguard Worker
149*fb1b10abSAndroid Build Coastguard Worker EXPECT_EQ(true, bias_acceptable)
150*fb1b10abSAndroid Build Coastguard Worker << "Error: 4x4 FDCT has a sign bias > 10% for input range [-15, 15]";
151*fb1b10abSAndroid Build Coastguard Worker }
152*fb1b10abSAndroid Build Coastguard Worker
TEST_P(FdctTest,RoundTripErrorCheck)153*fb1b10abSAndroid Build Coastguard Worker TEST_P(FdctTest, RoundTripErrorCheck) {
154*fb1b10abSAndroid Build Coastguard Worker int max_error = 0;
155*fb1b10abSAndroid Build Coastguard Worker double total_error = 0;
156*fb1b10abSAndroid Build Coastguard Worker const int count_test_block = 1000000;
157*fb1b10abSAndroid Build Coastguard Worker for (int i = 0; i < count_test_block; ++i) {
158*fb1b10abSAndroid Build Coastguard Worker int16_t test_input_block[16];
159*fb1b10abSAndroid Build Coastguard Worker int16_t test_output_block[16];
160*fb1b10abSAndroid Build Coastguard Worker DECLARE_ALIGNED(16, int16_t, test_temp_block[16]);
161*fb1b10abSAndroid Build Coastguard Worker
162*fb1b10abSAndroid Build Coastguard Worker // Initialize a test block with input range [-255, 255].
163*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
164*fb1b10abSAndroid Build Coastguard Worker test_input_block[j] = rnd_.Rand8() - rnd_.Rand8();
165*fb1b10abSAndroid Build Coastguard Worker }
166*fb1b10abSAndroid Build Coastguard Worker
167*fb1b10abSAndroid Build Coastguard Worker const int pitch = 8;
168*fb1b10abSAndroid Build Coastguard Worker fdct_func_(test_input_block, test_temp_block, pitch);
169*fb1b10abSAndroid Build Coastguard Worker reference_idct4x4(test_temp_block, test_output_block);
170*fb1b10abSAndroid Build Coastguard Worker
171*fb1b10abSAndroid Build Coastguard Worker for (int j = 0; j < 16; ++j) {
172*fb1b10abSAndroid Build Coastguard Worker const int diff = test_input_block[j] - test_output_block[j];
173*fb1b10abSAndroid Build Coastguard Worker const int error = diff * diff;
174*fb1b10abSAndroid Build Coastguard Worker if (max_error < error) max_error = error;
175*fb1b10abSAndroid Build Coastguard Worker total_error += error;
176*fb1b10abSAndroid Build Coastguard Worker }
177*fb1b10abSAndroid Build Coastguard Worker }
178*fb1b10abSAndroid Build Coastguard Worker
179*fb1b10abSAndroid Build Coastguard Worker EXPECT_GE(1, max_error)
180*fb1b10abSAndroid Build Coastguard Worker << "Error: FDCT/IDCT has an individual roundtrip error > 1";
181*fb1b10abSAndroid Build Coastguard Worker
182*fb1b10abSAndroid Build Coastguard Worker EXPECT_GE(count_test_block, total_error)
183*fb1b10abSAndroid Build Coastguard Worker << "Error: FDCT/IDCT has average roundtrip error > 1 per block";
184*fb1b10abSAndroid Build Coastguard Worker }
185*fb1b10abSAndroid Build Coastguard Worker
186*fb1b10abSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(C, FdctTest, ::testing::Values(vp8_short_fdct4x4_c));
187*fb1b10abSAndroid Build Coastguard Worker
188*fb1b10abSAndroid Build Coastguard Worker #if HAVE_NEON
189*fb1b10abSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(NEON, FdctTest,
190*fb1b10abSAndroid Build Coastguard Worker ::testing::Values(vp8_short_fdct4x4_neon));
191*fb1b10abSAndroid Build Coastguard Worker #endif // HAVE_NEON
192*fb1b10abSAndroid Build Coastguard Worker
193*fb1b10abSAndroid Build Coastguard Worker #if HAVE_SSE2
194*fb1b10abSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(SSE2, FdctTest,
195*fb1b10abSAndroid Build Coastguard Worker ::testing::Values(vp8_short_fdct4x4_sse2));
196*fb1b10abSAndroid Build Coastguard Worker #endif // HAVE_SSE2
197*fb1b10abSAndroid Build Coastguard Worker
198*fb1b10abSAndroid Build Coastguard Worker #if HAVE_MSA
199*fb1b10abSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(MSA, FdctTest,
200*fb1b10abSAndroid Build Coastguard Worker ::testing::Values(vp8_short_fdct4x4_msa));
201*fb1b10abSAndroid Build Coastguard Worker #endif // HAVE_MSA
202*fb1b10abSAndroid Build Coastguard Worker #if HAVE_MMI
203*fb1b10abSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(MMI, FdctTest,
204*fb1b10abSAndroid Build Coastguard Worker ::testing::Values(vp8_short_fdct4x4_mmi));
205*fb1b10abSAndroid Build Coastguard Worker #endif // HAVE_MMI
206*fb1b10abSAndroid Build Coastguard Worker
207*fb1b10abSAndroid Build Coastguard Worker #if HAVE_LSX
208*fb1b10abSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(LSX, FdctTest,
209*fb1b10abSAndroid Build Coastguard Worker ::testing::Values(vp8_short_fdct4x4_lsx));
210*fb1b10abSAndroid Build Coastguard Worker #endif // HAVE_LSX
211*fb1b10abSAndroid Build Coastguard Worker } // namespace
212