blob: d5b0ce3255fae999797487d50ba5d618cc6c31ec [file] [log] [blame]
Angie Chiang716f1bd2016-05-11 16:41:36 -07001/*
Yaowu Xubde4ac82016-11-28 15:26:06 -08002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Angie Chiang716f1bd2016-05-11 16:41:36 -07003 *
Yaowu Xubde4ac82016-11-28 15:26:06 -08004 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Angie Chiang716f1bd2016-05-11 16:41:36 -070010 */
11
12#include <stdio.h>
Yaowu Xuf883b422016-08-30 14:01:10 -070013#include "test/av1_txfm_test.h"
Angie Chiang716f1bd2016-05-11 16:41:36 -070014
Yaowu Xuc27fc142016-08-22 16:08:15 -070015namespace libaom_test {
Angie Chiang716f1bd2016-05-11 16:41:36 -070016
Jingning Han7e32a4c2017-04-12 10:43:17 -070017int get_txfm1d_size(TX_SIZE tx_size) { return tx_size_wide[tx_size]; }
Angie Chiang716f1bd2016-05-11 16:41:36 -070018
clang-format3a826f12016-08-11 17:46:05 -070019void get_txfm1d_type(TX_TYPE txfm2d_type, TYPE_TXFM *type0, TYPE_TXFM *type1) {
Angie Chiang716f1bd2016-05-11 16:41:36 -070020 switch (txfm2d_type) {
21 case DCT_DCT:
22 *type0 = TYPE_DCT;
23 *type1 = TYPE_DCT;
24 break;
25 case ADST_DCT:
26 *type0 = TYPE_ADST;
27 *type1 = TYPE_DCT;
28 break;
29 case DCT_ADST:
30 *type0 = TYPE_DCT;
31 *type1 = TYPE_ADST;
32 break;
33 case ADST_ADST:
34 *type0 = TYPE_ADST;
35 *type1 = TYPE_ADST;
36 break;
Angie Chiang6a752532016-05-11 18:50:47 -070037 case FLIPADST_DCT:
38 *type0 = TYPE_ADST;
39 *type1 = TYPE_DCT;
40 break;
41 case DCT_FLIPADST:
42 *type0 = TYPE_DCT;
43 *type1 = TYPE_ADST;
44 break;
45 case FLIPADST_FLIPADST:
46 *type0 = TYPE_ADST;
47 *type1 = TYPE_ADST;
48 break;
49 case ADST_FLIPADST:
50 *type0 = TYPE_ADST;
51 *type1 = TYPE_ADST;
52 break;
53 case FLIPADST_ADST:
54 *type0 = TYPE_ADST;
55 *type1 = TYPE_ADST;
56 break;
Debargha Mukherjeeaa84f3e2018-01-04 12:45:10 -080057 case IDTX:
58 *type0 = TYPE_IDTX;
59 *type1 = TYPE_IDTX;
60 break;
61 case H_DCT:
62 *type0 = TYPE_IDTX;
63 *type1 = TYPE_DCT;
64 break;
65 case V_DCT:
66 *type0 = TYPE_DCT;
67 *type1 = TYPE_IDTX;
68 break;
69 case H_ADST:
70 *type0 = TYPE_IDTX;
71 *type1 = TYPE_ADST;
72 break;
73 case V_ADST:
74 *type0 = TYPE_ADST;
75 *type1 = TYPE_IDTX;
76 break;
77 case H_FLIPADST:
78 *type0 = TYPE_IDTX;
79 *type1 = TYPE_ADST;
80 break;
81 case V_FLIPADST:
82 *type0 = TYPE_ADST;
83 *type1 = TYPE_IDTX;
84 break;
Angie Chiang716f1bd2016-05-11 16:41:36 -070085 default:
86 *type0 = TYPE_DCT;
87 *type1 = TYPE_DCT;
88 assert(0);
89 break;
90 }
91}
92
Debargha Mukherjeeaa84f3e2018-01-04 12:45:10 -080093double Sqrt2 = pow(2, 0.5);
Angie Chiang716f1bd2016-05-11 16:41:36 -070094double invSqrt2 = 1 / pow(2, 0.5);
95
Sebastien Alaiwanbdb7e9c2017-07-10 12:58:30 +020096double dct_matrix(double n, double k, int size) {
97 return cos(M_PI * (2 * n + 1) * k / (2 * size));
98}
99
clang-format3a826f12016-08-11 17:46:05 -0700100void reference_dct_1d(const double *in, double *out, int size) {
Angie Chiang716f1bd2016-05-11 16:41:36 -0700101 for (int k = 0; k < size; ++k) {
102 out[k] = 0;
103 for (int n = 0; n < size; ++n) {
Sebastien Alaiwanbdb7e9c2017-07-10 12:58:30 +0200104 out[k] += in[n] * dct_matrix(n, k, size);
Angie Chiang716f1bd2016-05-11 16:41:36 -0700105 }
106 if (k == 0) out[k] = out[k] * invSqrt2;
107 }
108}
109
Sebastien Alaiwand02642f2017-07-10 11:41:44 +0200110void reference_idct_1d(const double *in, double *out, int size) {
Sebastien Alaiwanbdb7e9c2017-07-10 12:58:30 +0200111 for (int k = 0; k < size; ++k) {
112 out[k] = 0;
113 for (int n = 0; n < size; ++n) {
114 if (n == 0)
115 out[k] += invSqrt2 * in[n] * dct_matrix(k, n, size);
Sebastien Alaiwand02642f2017-07-10 11:41:44 +0200116 else
Sebastien Alaiwanbdb7e9c2017-07-10 12:58:30 +0200117 out[k] += in[n] * dct_matrix(k, n, size);
Sebastien Alaiwand02642f2017-07-10 11:41:44 +0200118 }
119 }
120}
121
Urvang Joshi8207b912018-05-07 14:37:51 -0700122// TODO(any): Copied from the old 'fadst4' (same as the new 'av1_fadst4_new'
123// function). Should be replaced by a proper reference function that takes
124// 'double' input & output.
125static void fadst4_new(const tran_low_t *input, tran_low_t *output) {
Sarah Parker95f52602017-10-04 12:45:14 -0700126 tran_high_t x0, x1, x2, x3;
127 tran_high_t s0, s1, s2, s3, s4, s5, s6, s7;
128
129 x0 = input[0];
130 x1 = input[1];
131 x2 = input[2];
132 x3 = input[3];
133
134 if (!(x0 | x1 | x2 | x3)) {
135 output[0] = output[1] = output[2] = output[3] = 0;
136 return;
137 }
138
139 s0 = sinpi_1_9 * x0;
140 s1 = sinpi_4_9 * x0;
141 s2 = sinpi_2_9 * x1;
142 s3 = sinpi_1_9 * x1;
143 s4 = sinpi_3_9 * x2;
144 s5 = sinpi_4_9 * x3;
145 s6 = sinpi_2_9 * x3;
146 s7 = x0 + x1 - x3;
147
148 x0 = s0 + s2 + s5;
149 x1 = sinpi_3_9 * s7;
150 x2 = s1 - s3 + s6;
151 x3 = s4;
152
153 s0 = x0 + x3;
154 s1 = x1;
155 s2 = x2 - x3;
156 s3 = x2 - x0 + x3;
157
158 // 1-D transform scaling factor is sqrt(2).
159 output[0] = (tran_low_t)fdct_round_shift(s0);
160 output[1] = (tran_low_t)fdct_round_shift(s1);
161 output[2] = (tran_low_t)fdct_round_shift(s2);
162 output[3] = (tran_low_t)fdct_round_shift(s3);
163}
164
clang-format3a826f12016-08-11 17:46:05 -0700165void reference_adst_1d(const double *in, double *out, int size) {
Sarah Parker95f52602017-10-04 12:45:14 -0700166 if (size == 4) { // Special case.
167 tran_low_t int_input[4];
168 for (int i = 0; i < 4; ++i) {
169 int_input[i] = static_cast<tran_low_t>(round(in[i]));
170 }
171 tran_low_t int_output[4];
Urvang Joshi8207b912018-05-07 14:37:51 -0700172 fadst4_new(int_input, int_output);
Sarah Parker95f52602017-10-04 12:45:14 -0700173 for (int i = 0; i < 4; ++i) {
174 out[i] = int_output[i];
175 }
176 return;
177 }
178
Angie Chiang716f1bd2016-05-11 16:41:36 -0700179 for (int k = 0; k < size; ++k) {
180 out[k] = 0;
181 for (int n = 0; n < size; ++n) {
182 out[k] += in[n] * sin(M_PI * (2 * n + 1) * (2 * k + 1) / (4 * size));
183 }
184 }
185}
186
Debargha Mukherjeeaa84f3e2018-01-04 12:45:10 -0800187void reference_idtx_1d(const double *in, double *out, int size) {
188 double scale = 0;
189 if (size == 4)
190 scale = Sqrt2;
191 else if (size == 8)
192 scale = 2;
193 else if (size == 16)
194 scale = 2 * Sqrt2;
195 else if (size == 32)
196 scale = 4;
197 else if (size == 64)
198 scale = 4 * Sqrt2;
199 for (int k = 0; k < size; ++k) {
200 out[k] = in[k] * scale;
201 }
202}
203
clang-format3a826f12016-08-11 17:46:05 -0700204void reference_hybrid_1d(double *in, double *out, int size, int type) {
Angie Chiang716f1bd2016-05-11 16:41:36 -0700205 if (type == TYPE_DCT)
206 reference_dct_1d(in, out, size);
Debargha Mukherjeeaa84f3e2018-01-04 12:45:10 -0800207 else if (type == TYPE_ADST)
Angie Chiang716f1bd2016-05-11 16:41:36 -0700208 reference_adst_1d(in, out, size);
Debargha Mukherjeeaa84f3e2018-01-04 12:45:10 -0800209 else
210 reference_idtx_1d(in, out, size);
Angie Chiang716f1bd2016-05-11 16:41:36 -0700211}
212
Urvang Joshiec6acb22017-12-13 18:54:51 -0800213double get_amplification_factor(TX_TYPE tx_type, TX_SIZE tx_size) {
214 TXFM_2D_FLIP_CFG fwd_txfm_flip_cfg;
215 av1_get_fwd_txfm_cfg(tx_type, tx_size, &fwd_txfm_flip_cfg);
Angie Chiang0c7b8d82018-01-23 19:20:44 -0800216 const int tx_width = tx_size_wide[fwd_txfm_flip_cfg.tx_size];
217 const int tx_height = tx_size_high[fwd_txfm_flip_cfg.tx_size];
Angie Chiang4a75b5a2018-01-10 17:19:06 -0800218 const int8_t *shift = fwd_txfm_flip_cfg.shift;
Urvang Joshiec6acb22017-12-13 18:54:51 -0800219 const int amplify_bit = shift[0] + shift[1] + shift[2];
220 double amplify_factor =
221 amplify_bit >= 0 ? (1 << amplify_bit) : (1.0 / (1 << -amplify_bit));
222
223 // For rectangular transforms, we need to multiply by an extra factor.
224 const int rect_type = get_rect_tx_log_ratio(tx_width, tx_height);
225 if (abs(rect_type) == 1) {
226 amplify_factor *= pow(2, 0.5);
Urvang Joshiec6acb22017-12-13 18:54:51 -0800227 }
228 return amplify_factor;
229}
230
231void reference_hybrid_2d(double *in, double *out, TX_TYPE tx_type,
232 TX_SIZE tx_size) {
233 // Get transform type and size of each dimension.
234 TYPE_TXFM type0;
235 TYPE_TXFM type1;
236 get_txfm1d_type(tx_type, &type0, &type1);
237 const int tx_width = tx_size_wide[tx_size];
238 const int tx_height = tx_size_high[tx_size];
239
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800240 double *const temp_in = new double[AOMMAX(tx_width, tx_height)];
241 double *const temp_out = new double[AOMMAX(tx_width, tx_height)];
242 double *const out_interm = new double[tx_width * tx_height];
243 const int stride = tx_width;
Angie Chiang716f1bd2016-05-11 16:41:36 -0700244
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800245 // Transform columns.
246 for (int c = 0; c < tx_width; ++c) {
247 for (int r = 0; r < tx_height; ++r) {
248 temp_in[r] = in[r * stride + c];
249 }
250 reference_hybrid_1d(temp_in, temp_out, tx_height, type0);
251 for (int r = 0; r < tx_height; ++r) {
252 out_interm[r * stride + c] = temp_out[r];
Angie Chiang716f1bd2016-05-11 16:41:36 -0700253 }
254 }
255
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800256 // Transform rows.
257 for (int r = 0; r < tx_height; ++r) {
258 reference_hybrid_1d(out_interm + r * stride, out + r * stride, tx_width,
259 type1);
Angie Chiang716f1bd2016-05-11 16:41:36 -0700260 }
261
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800262 delete[] temp_in;
263 delete[] temp_out;
264 delete[] out_interm;
Urvang Joshi72359922017-12-11 17:17:40 -0800265
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800266 // These transforms use an approximate 2D DCT transform, by only keeping the
267 // top-left quarter of the coefficients, and repacking them in the first
268 // quarter indices.
269 // TODO(urvang): Refactor this code.
270 if (tx_width == 64 && tx_height == 64) { // tx_size == TX_64X64
Urvang Joshi72359922017-12-11 17:17:40 -0800271 // Zero out top-right 32x32 area.
272 for (int row = 0; row < 32; ++row) {
273 memset(out + row * 64 + 32, 0, 32 * sizeof(*out));
274 }
275 // Zero out the bottom 64x32 area.
276 memset(out + 32 * 64, 0, 32 * 64 * sizeof(*out));
277 // Re-pack non-zero coeffs in the first 32x32 indices.
278 for (int row = 1; row < 32; ++row) {
279 memcpy(out + row * 32, out + row * 64, 32 * sizeof(*out));
280 }
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800281 } else if (tx_width == 32 && tx_height == 64) { // tx_size == TX_32X64
282 // Zero out the bottom 32x32 area.
283 memset(out + 32 * 32, 0, 32 * 32 * sizeof(*out));
284 // Note: no repacking needed here.
285 } else if (tx_width == 64 && tx_height == 32) { // tx_size == TX_64X32
286 // Zero out right 32x32 area.
287 for (int row = 0; row < 32; ++row) {
288 memset(out + row * 64 + 32, 0, 32 * sizeof(*out));
289 }
290 // Re-pack non-zero coeffs in the first 32x32 indices.
291 for (int row = 1; row < 32; ++row) {
292 memcpy(out + row * 32, out + row * 64, 32 * sizeof(*out));
293 }
294 } else if (tx_width == 16 && tx_height == 64) { // tx_size == TX_16X64
295 // Zero out the bottom 16x32 area.
296 memset(out + 16 * 32, 0, 16 * 32 * sizeof(*out));
297 // Note: no repacking needed here.
298 } else if (tx_width == 64 && tx_height == 16) { // tx_size == TX_64X16
299 // Zero out right 32x16 area.
300 for (int row = 0; row < 16; ++row) {
301 memset(out + row * 64 + 32, 0, 32 * sizeof(*out));
302 }
303 // Re-pack non-zero coeffs in the first 32x16 indices.
304 for (int row = 1; row < 16; ++row) {
305 memcpy(out + row * 32, out + row * 64, 32 * sizeof(*out));
306 }
Urvang Joshi72359922017-12-11 17:17:40 -0800307 }
Urvang Joshiec6acb22017-12-13 18:54:51 -0800308
309 // Apply appropriate scale.
310 const double amplify_factor = get_amplification_factor(tx_type, tx_size);
311 for (int c = 0; c < tx_width; ++c) {
312 for (int r = 0; r < tx_height; ++r) {
313 out[r * stride + c] *= amplify_factor;
314 }
315 }
Angie Chiang716f1bd2016-05-11 16:41:36 -0700316}
Angie Chiang6a752532016-05-11 18:50:47 -0700317
clang-format3a826f12016-08-11 17:46:05 -0700318template <typename Type>
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800319void fliplr(Type *dest, int width, int height, int stride) {
320 for (int r = 0; r < height; ++r) {
321 for (int c = 0; c < width / 2; ++c) {
322 const Type tmp = dest[r * stride + c];
323 dest[r * stride + c] = dest[r * stride + width - 1 - c];
324 dest[r * stride + width - 1 - c] = tmp;
Angie Chiang6a752532016-05-11 18:50:47 -0700325 }
326 }
327}
328
clang-format3a826f12016-08-11 17:46:05 -0700329template <typename Type>
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800330void flipud(Type *dest, int width, int height, int stride) {
331 for (int c = 0; c < width; ++c) {
332 for (int r = 0; r < height / 2; ++r) {
333 const Type tmp = dest[r * stride + c];
334 dest[r * stride + c] = dest[(height - 1 - r) * stride + c];
335 dest[(height - 1 - r) * stride + c] = tmp;
Angie Chiang6a752532016-05-11 18:50:47 -0700336 }
337 }
338}
339
clang-format3a826f12016-08-11 17:46:05 -0700340template <typename Type>
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800341void fliplrud(Type *dest, int width, int height, int stride) {
342 for (int r = 0; r < height / 2; ++r) {
343 for (int c = 0; c < width; ++c) {
344 const Type tmp = dest[r * stride + c];
345 dest[r * stride + c] = dest[(height - 1 - r) * stride + width - 1 - c];
346 dest[(height - 1 - r) * stride + width - 1 - c] = tmp;
Angie Chiang6a752532016-05-11 18:50:47 -0700347 }
348 }
349}
350
Urvang Joshi5fb50f82017-12-12 18:48:55 -0800351template void fliplr<double>(double *dest, int width, int height, int stride);
352template void flipud<double>(double *dest, int width, int height, int stride);
353template void fliplrud<double>(double *dest, int width, int height, int stride);
Angie Chiang6a752532016-05-11 18:50:47 -0700354
Angie Chiang9c7089a2017-08-08 16:21:11 -0700355int bd_arr[BD_NUM] = { 8, 10, 12 };
Urvang Joshiab2b36e2017-10-03 11:01:06 -0700356
Urvang Joshiab2b36e2017-10-03 11:01:06 -0700357int8_t low_range_arr[BD_NUM] = { 18, 32, 32 };
Urvang Joshi09191ca2017-11-14 17:10:25 -0800358int8_t high_range_arr[BD_NUM] = { 32, 32, 32 };
Angie Chiang9c7089a2017-08-08 16:21:11 -0700359
360void txfm_stage_range_check(const int8_t *stage_range, int stage_num,
Angie Chiangd4327bc2018-01-22 20:54:04 -0800361 int8_t cos_bit, int low_range, int high_range) {
Angie Chiang9c7089a2017-08-08 16:21:11 -0700362 for (int i = 0; i < stage_num; ++i) {
363 EXPECT_LE(stage_range[i], low_range);
Angie Chiangd4327bc2018-01-22 20:54:04 -0800364 ASSERT_LE(stage_range[i] + cos_bit, high_range) << "stage = " << i;
Angie Chiang9c7089a2017-08-08 16:21:11 -0700365 }
366 for (int i = 0; i < stage_num - 1; ++i) {
367 // make sure there is no overflow while doing half_btf()
Angie Chiangd4327bc2018-01-22 20:54:04 -0800368 ASSERT_LE(stage_range[i + 1] + cos_bit, high_range) << "stage = " << i;
Angie Chiang9c7089a2017-08-08 16:21:11 -0700369 }
370}
Yaowu Xuc27fc142016-08-22 16:08:15 -0700371} // namespace libaom_test