Backed out 3 changesets (bug 1790375) for causing wd failures on fetch_error.py....
[gecko.git] / third_party / aom / test / warp_filter_test_util.cc
blob69b2ed4afe51180f0168e2f0494688ddf7e3c336
1 /*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
4 * 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.
11 #include "aom_ports/aom_timer.h"
12 #include "test/warp_filter_test_util.h"
14 using ::testing::make_tuple;
15 using ::testing::tuple;
17 namespace libaom_test {
19 int32_t random_warped_param(libaom_test::ACMRandom *rnd, int bits) {
20 // 1 in 8 chance of generating zero (arbitrarily chosen)
21 if (((rnd->Rand8()) & 7) == 0) return 0;
22 // Otherwise, enerate uniform values in the range
23 // [-(1 << bits), 1] U [1, 1<<bits]
24 int32_t v = 1 + (rnd->Rand16() & ((1 << bits) - 1));
25 if ((rnd->Rand8()) & 1) return -v;
26 return v;
29 void generate_warped_model(libaom_test::ACMRandom *rnd, int32_t *mat,
30 int16_t *alpha, int16_t *beta, int16_t *gamma,
31 int16_t *delta, const int is_alpha_zero,
32 const int is_beta_zero, const int is_gamma_zero,
33 const int is_delta_zero) {
34 while (1) {
35 int rnd8 = rnd->Rand8() & 3;
36 mat[0] = random_warped_param(rnd, WARPEDMODEL_PREC_BITS + 6);
37 mat[1] = random_warped_param(rnd, WARPEDMODEL_PREC_BITS + 6);
38 mat[2] = (random_warped_param(rnd, WARPEDMODEL_PREC_BITS - 3)) +
39 (1 << WARPEDMODEL_PREC_BITS);
40 mat[3] = random_warped_param(rnd, WARPEDMODEL_PREC_BITS - 3);
42 if (rnd8 <= 1) {
43 // AFFINE
44 mat[4] = random_warped_param(rnd, WARPEDMODEL_PREC_BITS - 3);
45 mat[5] = (random_warped_param(rnd, WARPEDMODEL_PREC_BITS - 3)) +
46 (1 << WARPEDMODEL_PREC_BITS);
47 } else if (rnd8 == 2) {
48 mat[4] = -mat[3];
49 mat[5] = mat[2];
50 } else {
51 mat[4] = random_warped_param(rnd, WARPEDMODEL_PREC_BITS - 3);
52 mat[5] = (random_warped_param(rnd, WARPEDMODEL_PREC_BITS - 3)) +
53 (1 << WARPEDMODEL_PREC_BITS);
54 if (is_alpha_zero == 1) mat[2] = 1 << WARPEDMODEL_PREC_BITS;
55 if (is_beta_zero == 1) mat[3] = 0;
56 if (is_gamma_zero == 1) mat[4] = 0;
57 if (is_delta_zero == 1)
58 mat[5] = (((int64_t)mat[3] * mat[4] + (mat[2] / 2)) / mat[2]) +
59 (1 << WARPEDMODEL_PREC_BITS);
62 // Calculate the derived parameters and check that they are suitable
63 // for the warp filter.
64 assert(mat[2] != 0);
66 *alpha = clamp(mat[2] - (1 << WARPEDMODEL_PREC_BITS), INT16_MIN, INT16_MAX);
67 *beta = clamp(mat[3], INT16_MIN, INT16_MAX);
68 *gamma = clamp(((int64_t)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) / mat[2],
69 INT16_MIN, INT16_MAX);
70 *delta =
71 clamp(mat[5] - (((int64_t)mat[3] * mat[4] + (mat[2] / 2)) / mat[2]) -
72 (1 << WARPEDMODEL_PREC_BITS),
73 INT16_MIN, INT16_MAX);
75 if ((4 * abs(*alpha) + 7 * abs(*beta) >= (1 << WARPEDMODEL_PREC_BITS)) ||
76 (4 * abs(*gamma) + 4 * abs(*delta) >= (1 << WARPEDMODEL_PREC_BITS)))
77 continue;
79 *alpha = ROUND_POWER_OF_TWO_SIGNED(*alpha, WARP_PARAM_REDUCE_BITS) *
80 (1 << WARP_PARAM_REDUCE_BITS);
81 *beta = ROUND_POWER_OF_TWO_SIGNED(*beta, WARP_PARAM_REDUCE_BITS) *
82 (1 << WARP_PARAM_REDUCE_BITS);
83 *gamma = ROUND_POWER_OF_TWO_SIGNED(*gamma, WARP_PARAM_REDUCE_BITS) *
84 (1 << WARP_PARAM_REDUCE_BITS);
85 *delta = ROUND_POWER_OF_TWO_SIGNED(*delta, WARP_PARAM_REDUCE_BITS) *
86 (1 << WARP_PARAM_REDUCE_BITS);
88 // We have a valid model, so finish
89 return;
93 namespace AV1WarpFilter {
94 ::testing::internal::ParamGenerator<WarpTestParams> BuildParams(
95 warp_affine_func filter) {
96 WarpTestParam params[] = {
97 make_tuple(4, 4, 50000, filter), make_tuple(8, 8, 50000, filter),
98 make_tuple(64, 64, 1000, filter), make_tuple(4, 16, 20000, filter),
99 make_tuple(32, 8, 10000, filter),
101 return ::testing::Combine(::testing::ValuesIn(params),
102 ::testing::Values(0, 1), ::testing::Values(0, 1),
103 ::testing::Values(0, 1), ::testing::Values(0, 1));
106 AV1WarpFilterTest::~AV1WarpFilterTest() {}
107 void AV1WarpFilterTest::SetUp() { rnd_.Reset(ACMRandom::DeterministicSeed()); }
109 void AV1WarpFilterTest::TearDown() { libaom_test::ClearSystemState(); }
111 void AV1WarpFilterTest::RunSpeedTest(warp_affine_func test_impl) {
112 const int w = 128, h = 128;
113 const int border = 16;
114 const int stride = w + 2 * border;
115 WarpTestParam params = GET_PARAM(0);
116 const int out_w = ::testing::get<0>(params),
117 out_h = ::testing::get<1>(params);
118 const int is_alpha_zero = GET_PARAM(1);
119 const int is_beta_zero = GET_PARAM(2);
120 const int is_gamma_zero = GET_PARAM(3);
121 const int is_delta_zero = GET_PARAM(4);
122 int sub_x, sub_y;
123 const int bd = 8;
125 uint8_t *input_ = new uint8_t[h * stride];
126 uint8_t *input = input_ + border;
128 // The warp functions always write rows with widths that are multiples of 8.
129 // So to avoid a buffer overflow, we may need to pad rows to a multiple of 8.
130 int output_n = ((out_w + 7) & ~7) * out_h;
131 uint8_t *output = new uint8_t[output_n];
132 int32_t mat[8];
133 int16_t alpha, beta, gamma, delta;
134 ConvolveParams conv_params = get_conv_params(0, 0, bd);
135 CONV_BUF_TYPE *dsta = new CONV_BUF_TYPE[output_n];
136 generate_warped_model(&rnd_, mat, &alpha, &beta, &gamma, &delta,
137 is_alpha_zero, is_beta_zero, is_gamma_zero,
138 is_delta_zero);
140 for (int r = 0; r < h; ++r)
141 for (int c = 0; c < w; ++c) input[r * stride + c] = rnd_.Rand8();
142 for (int r = 0; r < h; ++r) {
143 memset(input + r * stride - border, input[r * stride], border);
144 memset(input + r * stride + w, input[r * stride + (w - 1)], border);
147 sub_x = 0;
148 sub_y = 0;
149 int do_average = 0;
151 conv_params = get_conv_params_no_round(do_average, 0, dsta, out_w, 1, bd);
152 conv_params.use_jnt_comp_avg = 0;
154 const int num_loops = 1000000000 / (out_w + out_h);
155 aom_usec_timer timer;
156 aom_usec_timer_start(&timer);
157 for (int i = 0; i < num_loops; ++i)
158 test_impl(mat, input, w, h, stride, output, 32, 32, out_w, out_h, out_w,
159 sub_x, sub_y, &conv_params, alpha, beta, gamma, delta);
161 aom_usec_timer_mark(&timer);
162 const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
163 printf("warp %3dx%-3d: %7.2f ns\n", out_w, out_h,
164 1000.0 * elapsed_time / num_loops);
166 delete[] input_;
167 delete[] output;
168 delete[] dsta;
171 void AV1WarpFilterTest::RunCheckOutput(warp_affine_func test_impl) {
172 const int w = 128, h = 128;
173 const int border = 16;
174 const int stride = w + 2 * border;
175 WarpTestParam params = GET_PARAM(0);
176 const int is_alpha_zero = GET_PARAM(1);
177 const int is_beta_zero = GET_PARAM(2);
178 const int is_gamma_zero = GET_PARAM(3);
179 const int is_delta_zero = GET_PARAM(4);
180 const int out_w = ::testing::get<0>(params),
181 out_h = ::testing::get<1>(params);
182 const int num_iters = ::testing::get<2>(params);
183 int i, j, sub_x, sub_y;
184 const int bd = 8;
186 // The warp functions always write rows with widths that are multiples of 8.
187 // So to avoid a buffer overflow, we may need to pad rows to a multiple of 8.
188 int output_n = ((out_w + 7) & ~7) * out_h;
189 uint8_t *input_ = new uint8_t[h * stride];
190 uint8_t *input = input_ + border;
191 uint8_t *output = new uint8_t[output_n];
192 uint8_t *output2 = new uint8_t[output_n];
193 int32_t mat[8];
194 int16_t alpha, beta, gamma, delta;
195 ConvolveParams conv_params = get_conv_params(0, 0, bd);
196 CONV_BUF_TYPE *dsta = new CONV_BUF_TYPE[output_n];
197 CONV_BUF_TYPE *dstb = new CONV_BUF_TYPE[output_n];
198 for (int i = 0; i < output_n; ++i) output[i] = output2[i] = rnd_.Rand8();
200 for (i = 0; i < num_iters; ++i) {
201 // Generate an input block and extend its borders horizontally
202 for (int r = 0; r < h; ++r)
203 for (int c = 0; c < w; ++c) input[r * stride + c] = rnd_.Rand8();
204 for (int r = 0; r < h; ++r) {
205 memset(input + r * stride - border, input[r * stride], border);
206 memset(input + r * stride + w, input[r * stride + (w - 1)], border);
208 const int use_no_round = rnd_.Rand8() & 1;
209 for (sub_x = 0; sub_x < 2; ++sub_x)
210 for (sub_y = 0; sub_y < 2; ++sub_y) {
211 generate_warped_model(&rnd_, mat, &alpha, &beta, &gamma, &delta,
212 is_alpha_zero, is_beta_zero, is_gamma_zero,
213 is_delta_zero);
215 for (int ii = 0; ii < 2; ++ii) {
216 for (int jj = 0; jj < 5; ++jj) {
217 for (int do_average = 0; do_average <= 1; ++do_average) {
218 if (use_no_round) {
219 conv_params =
220 get_conv_params_no_round(do_average, 0, dsta, out_w, 1, bd);
221 } else {
222 conv_params = get_conv_params(0, 0, bd);
224 if (jj >= 4) {
225 conv_params.use_jnt_comp_avg = 0;
226 } else {
227 conv_params.use_jnt_comp_avg = 1;
228 conv_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
229 conv_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
231 av1_warp_affine_c(mat, input, w, h, stride, output, 32, 32, out_w,
232 out_h, out_w, sub_x, sub_y, &conv_params, alpha,
233 beta, gamma, delta);
234 if (use_no_round) {
235 conv_params =
236 get_conv_params_no_round(do_average, 0, dstb, out_w, 1, bd);
238 if (jj >= 4) {
239 conv_params.use_jnt_comp_avg = 0;
240 } else {
241 conv_params.use_jnt_comp_avg = 1;
242 conv_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
243 conv_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
245 test_impl(mat, input, w, h, stride, output2, 32, 32, out_w, out_h,
246 out_w, sub_x, sub_y, &conv_params, alpha, beta, gamma,
247 delta);
248 if (use_no_round) {
249 for (j = 0; j < out_w * out_h; ++j)
250 ASSERT_EQ(dsta[j], dstb[j])
251 << "Pixel mismatch at index " << j << " = ("
252 << (j % out_w) << ", " << (j / out_w) << ") on iteration "
253 << i;
254 for (j = 0; j < out_w * out_h; ++j)
255 ASSERT_EQ(output[j], output2[j])
256 << "Pixel mismatch at index " << j << " = ("
257 << (j % out_w) << ", " << (j / out_w) << ") on iteration "
258 << i;
259 } else {
260 for (j = 0; j < out_w * out_h; ++j)
261 ASSERT_EQ(output[j], output2[j])
262 << "Pixel mismatch at index " << j << " = ("
263 << (j % out_w) << ", " << (j / out_w) << ") on iteration "
264 << i;
271 delete[] input_;
272 delete[] output;
273 delete[] output2;
274 delete[] dsta;
275 delete[] dstb;
277 } // namespace AV1WarpFilter
279 namespace AV1HighbdWarpFilter {
280 ::testing::internal::ParamGenerator<HighbdWarpTestParams> BuildParams(
281 highbd_warp_affine_func filter) {
282 const HighbdWarpTestParam params[] = {
283 make_tuple(4, 4, 100, 8, filter), make_tuple(8, 8, 100, 8, filter),
284 make_tuple(64, 64, 100, 8, filter), make_tuple(4, 16, 100, 8, filter),
285 make_tuple(32, 8, 100, 8, filter), make_tuple(4, 4, 100, 10, filter),
286 make_tuple(8, 8, 100, 10, filter), make_tuple(64, 64, 100, 10, filter),
287 make_tuple(4, 16, 100, 10, filter), make_tuple(32, 8, 100, 10, filter),
288 make_tuple(4, 4, 100, 12, filter), make_tuple(8, 8, 100, 12, filter),
289 make_tuple(64, 64, 100, 12, filter), make_tuple(4, 16, 100, 12, filter),
290 make_tuple(32, 8, 100, 12, filter),
292 return ::testing::Combine(::testing::ValuesIn(params),
293 ::testing::Values(0, 1), ::testing::Values(0, 1),
294 ::testing::Values(0, 1), ::testing::Values(0, 1));
297 AV1HighbdWarpFilterTest::~AV1HighbdWarpFilterTest() {}
298 void AV1HighbdWarpFilterTest::SetUp() {
299 rnd_.Reset(ACMRandom::DeterministicSeed());
302 void AV1HighbdWarpFilterTest::TearDown() { libaom_test::ClearSystemState(); }
304 void AV1HighbdWarpFilterTest::RunSpeedTest(highbd_warp_affine_func test_impl) {
305 const int w = 128, h = 128;
306 const int border = 16;
307 const int stride = w + 2 * border;
308 HighbdWarpTestParam param = GET_PARAM(0);
309 const int is_alpha_zero = GET_PARAM(1);
310 const int is_beta_zero = GET_PARAM(2);
311 const int is_gamma_zero = GET_PARAM(3);
312 const int is_delta_zero = GET_PARAM(4);
313 const int out_w = ::testing::get<0>(param), out_h = ::testing::get<1>(param);
314 const int bd = ::testing::get<3>(param);
315 const int mask = (1 << bd) - 1;
316 int sub_x, sub_y;
318 // The warp functions always write rows with widths that are multiples of 8.
319 // So to avoid a buffer overflow, we may need to pad rows to a multiple of 8.
320 int output_n = ((out_w + 7) & ~7) * out_h;
321 uint16_t *input_ = new uint16_t[h * stride];
322 uint16_t *input = input_ + border;
323 uint16_t *output = new uint16_t[output_n];
324 int32_t mat[8];
325 int16_t alpha, beta, gamma, delta;
326 ConvolveParams conv_params = get_conv_params(0, 0, bd);
327 CONV_BUF_TYPE *dsta = new CONV_BUF_TYPE[output_n];
329 generate_warped_model(&rnd_, mat, &alpha, &beta, &gamma, &delta,
330 is_alpha_zero, is_beta_zero, is_gamma_zero,
331 is_delta_zero);
332 // Generate an input block and extend its borders horizontally
333 for (int r = 0; r < h; ++r)
334 for (int c = 0; c < w; ++c) input[r * stride + c] = rnd_.Rand16() & mask;
335 for (int r = 0; r < h; ++r) {
336 for (int c = 0; c < border; ++c) {
337 input[r * stride - border + c] = input[r * stride];
338 input[r * stride + w + c] = input[r * stride + (w - 1)];
342 sub_x = 0;
343 sub_y = 0;
344 int do_average = 0;
345 conv_params.use_jnt_comp_avg = 0;
346 conv_params = get_conv_params_no_round(do_average, 0, dsta, out_w, 1, bd);
348 const int num_loops = 1000000000 / (out_w + out_h);
349 aom_usec_timer timer;
350 aom_usec_timer_start(&timer);
352 for (int i = 0; i < num_loops; ++i)
353 test_impl(mat, input, w, h, stride, output, 32, 32, out_w, out_h, out_w,
354 sub_x, sub_y, bd, &conv_params, alpha, beta, gamma, delta);
356 aom_usec_timer_mark(&timer);
357 const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
358 printf("highbd warp %3dx%-3d: %7.2f ns\n", out_w, out_h,
359 1000.0 * elapsed_time / num_loops);
361 delete[] input_;
362 delete[] output;
363 delete[] dsta;
366 void AV1HighbdWarpFilterTest::RunCheckOutput(
367 highbd_warp_affine_func test_impl) {
368 const int w = 128, h = 128;
369 const int border = 16;
370 const int stride = w + 2 * border;
371 HighbdWarpTestParam param = GET_PARAM(0);
372 const int is_alpha_zero = GET_PARAM(1);
373 const int is_beta_zero = GET_PARAM(2);
374 const int is_gamma_zero = GET_PARAM(3);
375 const int is_delta_zero = GET_PARAM(4);
376 const int out_w = ::testing::get<0>(param), out_h = ::testing::get<1>(param);
377 const int bd = ::testing::get<3>(param);
378 const int num_iters = ::testing::get<2>(param);
379 const int mask = (1 << bd) - 1;
380 int i, j, sub_x, sub_y;
382 // The warp functions always write rows with widths that are multiples of 8.
383 // So to avoid a buffer overflow, we may need to pad rows to a multiple of 8.
384 int output_n = ((out_w + 7) & ~7) * out_h;
385 uint16_t *input_ = new uint16_t[h * stride];
386 uint16_t *input = input_ + border;
387 uint16_t *output = new uint16_t[output_n];
388 uint16_t *output2 = new uint16_t[output_n];
389 int32_t mat[8];
390 int16_t alpha, beta, gamma, delta;
391 ConvolveParams conv_params = get_conv_params(0, 0, bd);
392 CONV_BUF_TYPE *dsta = new CONV_BUF_TYPE[output_n];
393 CONV_BUF_TYPE *dstb = new CONV_BUF_TYPE[output_n];
394 for (int i = 0; i < output_n; ++i) output[i] = output2[i] = rnd_.Rand16();
396 for (i = 0; i < num_iters; ++i) {
397 // Generate an input block and extend its borders horizontally
398 for (int r = 0; r < h; ++r)
399 for (int c = 0; c < w; ++c) input[r * stride + c] = rnd_.Rand16() & mask;
400 for (int r = 0; r < h; ++r) {
401 for (int c = 0; c < border; ++c) {
402 input[r * stride - border + c] = input[r * stride];
403 input[r * stride + w + c] = input[r * stride + (w - 1)];
406 const int use_no_round = rnd_.Rand8() & 1;
407 for (sub_x = 0; sub_x < 2; ++sub_x)
408 for (sub_y = 0; sub_y < 2; ++sub_y) {
409 generate_warped_model(&rnd_, mat, &alpha, &beta, &gamma, &delta,
410 is_alpha_zero, is_beta_zero, is_gamma_zero,
411 is_delta_zero);
412 for (int ii = 0; ii < 2; ++ii) {
413 for (int jj = 0; jj < 5; ++jj) {
414 for (int do_average = 0; do_average <= 1; ++do_average) {
415 if (use_no_round) {
416 conv_params =
417 get_conv_params_no_round(do_average, 0, dsta, out_w, 1, bd);
418 } else {
419 conv_params = get_conv_params(0, 0, bd);
421 if (jj >= 4) {
422 conv_params.use_jnt_comp_avg = 0;
423 } else {
424 conv_params.use_jnt_comp_avg = 1;
425 conv_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
426 conv_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
429 av1_highbd_warp_affine_c(mat, input, w, h, stride, output, 32, 32,
430 out_w, out_h, out_w, sub_x, sub_y, bd,
431 &conv_params, alpha, beta, gamma, delta);
432 if (use_no_round) {
433 // TODO(angiebird): Change this to test_impl once we have SIMD
434 // implementation
435 conv_params =
436 get_conv_params_no_round(do_average, 0, dstb, out_w, 1, bd);
438 if (jj >= 4) {
439 conv_params.use_jnt_comp_avg = 0;
440 } else {
441 conv_params.use_jnt_comp_avg = 1;
442 conv_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
443 conv_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
445 test_impl(mat, input, w, h, stride, output2, 32, 32, out_w, out_h,
446 out_w, sub_x, sub_y, bd, &conv_params, alpha, beta,
447 gamma, delta);
449 if (use_no_round) {
450 for (j = 0; j < out_w * out_h; ++j)
451 ASSERT_EQ(dsta[j], dstb[j])
452 << "Pixel mismatch at index " << j << " = ("
453 << (j % out_w) << ", " << (j / out_w) << ") on iteration "
454 << i;
455 for (j = 0; j < out_w * out_h; ++j)
456 ASSERT_EQ(output[j], output2[j])
457 << "Pixel mismatch at index " << j << " = ("
458 << (j % out_w) << ", " << (j / out_w) << ") on iteration "
459 << i;
460 } else {
461 for (j = 0; j < out_w * out_h; ++j)
462 ASSERT_EQ(output[j], output2[j])
463 << "Pixel mismatch at index " << j << " = ("
464 << (j % out_w) << ", " << (j / out_w) << ") on iteration "
465 << i;
473 delete[] input_;
474 delete[] output;
475 delete[] output2;
476 delete[] dsta;
477 delete[] dstb;
479 } // namespace AV1HighbdWarpFilter
480 } // namespace libaom_test