blob: f050718bb0071374797f2e283a8287dd9eb94aef [file] [log] [blame]
Deb Mukherjee931ed512014-09-17 16:55:05 -07001/*
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Deb Mukherjee931ed512014-09-17 16:55:05 -07003 *
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07004 * 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.
10*/
Deb Mukherjee931ed512014-09-17 16:55:05 -070011
12#include <cmath>
13#include <cstdlib>
14#include <string>
15
Tom Finegan7a07ece2017-02-07 17:14:05 -080016#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
Jingning Han097d59c2015-07-29 14:51:36 -070017
Yaowu Xuf883b422016-08-30 14:01:10 -070018#include "./aom_config.h"
19#include "./aom_dsp_rtcd.h"
Deb Mukherjee931ed512014-09-17 16:55:05 -070020#include "test/acm_random.h"
21#include "test/clear_system_state.h"
22#include "test/register_state_check.h"
23#include "test/util.h"
Tom Finegan17ce8b12017-02-08 12:46:31 -080024#include "av1/common/av1_loopfilter.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070025#include "av1/common/entropy.h"
Yaowu Xuf883b422016-08-30 14:01:10 -070026#include "aom/aom_integer.h"
Deb Mukherjee931ed512014-09-17 16:55:05 -070027
Yaowu Xuc27fc142016-08-22 16:08:15 -070028using libaom_test::ACMRandom;
Deb Mukherjee931ed512014-09-17 16:55:05 -070029
30namespace {
31// Horizontally and Vertically need 32x32: 8 Coeffs preceeding filtered section
32// 16 Coefs within filtered section
33// 8 Coeffs following filtered section
34const int kNumCoeffs = 1024;
35
36const int number_of_iterations = 10000;
37
Sebastien Alaiwan71e87842017-04-12 16:03:28 +020038#if CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -070039typedef void (*loop_op_t)(uint16_t *s, int p, const uint8_t *blimit,
clang-format3a826f12016-08-11 17:46:05 -070040 const uint8_t *limit, const uint8_t *thresh, int bd);
Deb Mukherjee931ed512014-09-17 16:55:05 -070041typedef void (*dual_loop_op_t)(uint16_t *s, int p, const uint8_t *blimit0,
42 const uint8_t *limit0, const uint8_t *thresh0,
43 const uint8_t *blimit1, const uint8_t *limit1,
44 const uint8_t *thresh1, int bd);
45#else
46typedef void (*loop_op_t)(uint8_t *s, int p, const uint8_t *blimit,
James Zern3ea537c2016-02-13 11:05:24 -080047 const uint8_t *limit, const uint8_t *thresh);
Deb Mukherjee931ed512014-09-17 16:55:05 -070048typedef void (*dual_loop_op_t)(uint8_t *s, int p, const uint8_t *blimit0,
49 const uint8_t *limit0, const uint8_t *thresh0,
50 const uint8_t *blimit1, const uint8_t *limit1,
51 const uint8_t *thresh1);
Sebastien Alaiwan71e87842017-04-12 16:03:28 +020052#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -070053
James Zern3ea537c2016-02-13 11:05:24 -080054typedef std::tr1::tuple<loop_op_t, loop_op_t, int> loop8_param_t;
Deb Mukherjee931ed512014-09-17 16:55:05 -070055typedef std::tr1::tuple<dual_loop_op_t, dual_loop_op_t, int> dualloop8_param_t;
56
Deb Mukherjee931ed512014-09-17 16:55:05 -070057class Loop8Test6Param : public ::testing::TestWithParam<loop8_param_t> {
58 public:
59 virtual ~Loop8Test6Param() {}
60 virtual void SetUp() {
61 loopfilter_op_ = GET_PARAM(0);
62 ref_loopfilter_op_ = GET_PARAM(1);
63 bit_depth_ = GET_PARAM(2);
64 mask_ = (1 << bit_depth_) - 1;
65 }
66
Yaowu Xuc27fc142016-08-22 16:08:15 -070067 virtual void TearDown() { libaom_test::ClearSystemState(); }
Deb Mukherjee931ed512014-09-17 16:55:05 -070068
69 protected:
70 int bit_depth_;
71 int mask_;
72 loop_op_t loopfilter_op_;
73 loop_op_t ref_loopfilter_op_;
74};
75
76class Loop8Test9Param : public ::testing::TestWithParam<dualloop8_param_t> {
77 public:
78 virtual ~Loop8Test9Param() {}
79 virtual void SetUp() {
80 loopfilter_op_ = GET_PARAM(0);
81 ref_loopfilter_op_ = GET_PARAM(1);
82 bit_depth_ = GET_PARAM(2);
83 mask_ = (1 << bit_depth_) - 1;
84 }
85
Yaowu Xuc27fc142016-08-22 16:08:15 -070086 virtual void TearDown() { libaom_test::ClearSystemState(); }
Deb Mukherjee931ed512014-09-17 16:55:05 -070087
88 protected:
89 int bit_depth_;
90 int mask_;
91 dual_loop_op_t loopfilter_op_;
92 dual_loop_op_t ref_loopfilter_op_;
93};
94
95TEST_P(Loop8Test6Param, OperationCheck) {
96 ACMRandom rnd(ACMRandom::DeterministicSeed());
97 const int count_test_block = number_of_iterations;
Sebastien Alaiwan71e87842017-04-12 16:03:28 +020098#if CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -070099 int32_t bd = bit_depth_;
James Zernfd3658b2015-05-02 13:24:16 -0700100 DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
101 DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700102#else
James Zernfd3658b2015-05-02 13:24:16 -0700103 DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
104 DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200105#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700106 int err_count_total = 0;
107 int first_failure = -1;
108 for (int i = 0; i < count_test_block; ++i) {
109 int err_count = 0;
Deb Mukherjee072ed172014-12-03 16:26:48 -0800110 uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
clang-format3a826f12016-08-11 17:46:05 -0700111 DECLARE_ALIGNED(16, const uint8_t,
112 blimit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
113 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800114 tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
clang-format3a826f12016-08-11 17:46:05 -0700115 DECLARE_ALIGNED(16, const uint8_t,
116 limit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
117 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700118 tmp = rnd.Rand8();
clang-format3a826f12016-08-11 17:46:05 -0700119 DECLARE_ALIGNED(16, const uint8_t,
120 thresh[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
121 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
122 int32_t p = kNumCoeffs / 32;
Deb Mukherjee931ed512014-09-17 16:55:05 -0700123
124 uint16_t tmp_s[kNumCoeffs];
125 int j = 0;
126 while (j < kNumCoeffs) {
127 uint8_t val = rnd.Rand8();
128 if (val & 0x80) { // 50% chance to choose a new value.
129 tmp_s[j] = rnd.Rand16();
130 j++;
131 } else { // 50% chance to repeat previous value in row X times
132 int k = 0;
133 while (k++ < ((val & 0x1f) + 1) && j < kNumCoeffs) {
134 if (j < 1) {
135 tmp_s[j] = rnd.Rand16();
136 } else if (val & 0x20) { // Increment by an value within the limit
137 tmp_s[j] = (tmp_s[j - 1] + (*limit - 1));
138 } else { // Decrement by an value within the limit
139 tmp_s[j] = (tmp_s[j - 1] - (*limit - 1));
140 }
141 j++;
142 }
143 }
144 }
145 for (j = 0; j < kNumCoeffs; j++) {
146 if (i % 2) {
147 s[j] = tmp_s[j] & mask_;
148 } else {
149 s[j] = tmp_s[p * (j % p) + j / p] & mask_;
150 }
151 ref_s[j] = s[j];
152 }
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200153#if CONFIG_HIGHBITDEPTH
James Zern3ea537c2016-02-13 11:05:24 -0800154 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh, bd);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700155 ASM_REGISTER_STATE_CHECK(
James Zern3ea537c2016-02-13 11:05:24 -0800156 loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, bd));
Deb Mukherjee931ed512014-09-17 16:55:05 -0700157#else
clang-format3a826f12016-08-11 17:46:05 -0700158 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700159 ASM_REGISTER_STATE_CHECK(
James Zern3ea537c2016-02-13 11:05:24 -0800160 loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh));
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200161#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700162
Urvang Joshi88a03bb2016-10-17 14:34:48 -0700163 for (j = 0; j < kNumCoeffs; ++j) {
Deb Mukherjee931ed512014-09-17 16:55:05 -0700164 err_count += ref_s[j] != s[j];
165 }
166 if (err_count && !err_count_total) {
167 first_failure = i;
168 }
169 err_count_total += err_count;
170 }
171 EXPECT_EQ(0, err_count_total)
172 << "Error: Loop8Test6Param, C output doesn't match SSE2 "
173 "loopfilter output. "
174 << "First failed at test case " << first_failure;
175}
176
177TEST_P(Loop8Test6Param, ValueCheck) {
178 ACMRandom rnd(ACMRandom::DeterministicSeed());
179 const int count_test_block = number_of_iterations;
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200180#if CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700181 const int32_t bd = bit_depth_;
James Zernfd3658b2015-05-02 13:24:16 -0700182 DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
183 DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700184#else
James Zernfd3658b2015-05-02 13:24:16 -0700185 DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
186 DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200187#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700188 int err_count_total = 0;
189 int first_failure = -1;
Deb Mukherjee072ed172014-12-03 16:26:48 -0800190
Yaowu Xuf883b422016-08-30 14:01:10 -0700191 // NOTE: The code in av1_loopfilter.c:update_sharpness computes mblim as a
Deb Mukherjee072ed172014-12-03 16:26:48 -0800192 // function of sharpness_lvl and the loopfilter lvl as:
193 // block_inside_limit = lvl >> ((sharpness_lvl > 0) + (sharpness_lvl > 4));
194 // ...
James Zernf58011a2015-04-23 20:47:40 -0700195 // memset(lfi->lfthr[lvl].mblim, (2 * (lvl + 2) + block_inside_limit),
196 // SIMD_WIDTH);
Deb Mukherjee072ed172014-12-03 16:26:48 -0800197 // This means that the largest value for mblim will occur when sharpness_lvl
198 // is equal to 0, and lvl is equal to its greatest value (MAX_LOOP_FILTER).
199 // In this case block_inside_limit will be equal to MAX_LOOP_FILTER and
200 // therefore mblim will be equal to (2 * (lvl + 2) + block_inside_limit) =
201 // 2 * (MAX_LOOP_FILTER + 2) + MAX_LOOP_FILTER = 3 * MAX_LOOP_FILTER + 4
202
Deb Mukherjee931ed512014-09-17 16:55:05 -0700203 for (int i = 0; i < count_test_block; ++i) {
204 int err_count = 0;
Deb Mukherjee072ed172014-12-03 16:26:48 -0800205 uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
clang-format3a826f12016-08-11 17:46:05 -0700206 DECLARE_ALIGNED(16, const uint8_t,
207 blimit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
208 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800209 tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
clang-format3a826f12016-08-11 17:46:05 -0700210 DECLARE_ALIGNED(16, const uint8_t,
211 limit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
212 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700213 tmp = rnd.Rand8();
clang-format3a826f12016-08-11 17:46:05 -0700214 DECLARE_ALIGNED(16, const uint8_t,
215 thresh[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
216 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700217 int32_t p = kNumCoeffs / 32;
Deb Mukherjee931ed512014-09-17 16:55:05 -0700218 for (int j = 0; j < kNumCoeffs; ++j) {
219 s[j] = rnd.Rand16() & mask_;
220 ref_s[j] = s[j];
221 }
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200222#if CONFIG_HIGHBITDEPTH
James Zern3ea537c2016-02-13 11:05:24 -0800223 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh, bd);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700224 ASM_REGISTER_STATE_CHECK(
James Zern3ea537c2016-02-13 11:05:24 -0800225 loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, bd));
Deb Mukherjee931ed512014-09-17 16:55:05 -0700226#else
clang-format3a826f12016-08-11 17:46:05 -0700227 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700228 ASM_REGISTER_STATE_CHECK(
James Zern3ea537c2016-02-13 11:05:24 -0800229 loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh));
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200230#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700231 for (int j = 0; j < kNumCoeffs; ++j) {
232 err_count += ref_s[j] != s[j];
233 }
234 if (err_count && !err_count_total) {
235 first_failure = i;
236 }
237 err_count_total += err_count;
238 }
239 EXPECT_EQ(0, err_count_total)
240 << "Error: Loop8Test6Param, C output doesn't match SSE2 "
241 "loopfilter output. "
242 << "First failed at test case " << first_failure;
243}
244
245TEST_P(Loop8Test9Param, OperationCheck) {
246 ACMRandom rnd(ACMRandom::DeterministicSeed());
247 const int count_test_block = number_of_iterations;
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200248#if CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700249 const int32_t bd = bit_depth_;
James Zernfd3658b2015-05-02 13:24:16 -0700250 DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
251 DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700252#else
clang-format3a826f12016-08-11 17:46:05 -0700253 DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
254 DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200255#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700256 int err_count_total = 0;
257 int first_failure = -1;
258 for (int i = 0; i < count_test_block; ++i) {
259 int err_count = 0;
Deb Mukherjee072ed172014-12-03 16:26:48 -0800260 uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
clang-format3a826f12016-08-11 17:46:05 -0700261 DECLARE_ALIGNED(16, const uint8_t,
262 blimit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
263 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800264 tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
clang-format3a826f12016-08-11 17:46:05 -0700265 DECLARE_ALIGNED(16, const uint8_t,
266 limit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
267 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700268 tmp = rnd.Rand8();
clang-format3a826f12016-08-11 17:46:05 -0700269 DECLARE_ALIGNED(16, const uint8_t,
270 thresh0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
271 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800272 tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
clang-format3a826f12016-08-11 17:46:05 -0700273 DECLARE_ALIGNED(16, const uint8_t,
274 blimit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
275 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800276 tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
clang-format3a826f12016-08-11 17:46:05 -0700277 DECLARE_ALIGNED(16, const uint8_t,
278 limit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
279 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700280 tmp = rnd.Rand8();
clang-format3a826f12016-08-11 17:46:05 -0700281 DECLARE_ALIGNED(16, const uint8_t,
282 thresh1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
283 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700284 int32_t p = kNumCoeffs / 32;
285 uint16_t tmp_s[kNumCoeffs];
286 int j = 0;
287 const uint8_t limit = *limit0 < *limit1 ? *limit0 : *limit1;
288 while (j < kNumCoeffs) {
289 uint8_t val = rnd.Rand8();
290 if (val & 0x80) { // 50% chance to choose a new value.
291 tmp_s[j] = rnd.Rand16();
292 j++;
293 } else { // 50% chance to repeat previous value in row X times.
294 int k = 0;
295 while (k++ < ((val & 0x1f) + 1) && j < kNumCoeffs) {
296 if (j < 1) {
297 tmp_s[j] = rnd.Rand16();
298 } else if (val & 0x20) { // Increment by a value within the limit.
299 tmp_s[j] = (tmp_s[j - 1] + (limit - 1));
300 } else { // Decrement by an value within the limit.
301 tmp_s[j] = (tmp_s[j - 1] - (limit - 1));
302 }
303 j++;
304 }
305 }
306 }
307 for (j = 0; j < kNumCoeffs; j++) {
308 if (i % 2) {
309 s[j] = tmp_s[j] & mask_;
310 } else {
311 s[j] = tmp_s[p * (j % p) + j / p] & mask_;
312 }
313 ref_s[j] = s[j];
314 }
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200315#if CONFIG_HIGHBITDEPTH
clang-format3a826f12016-08-11 17:46:05 -0700316 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1,
317 limit1, thresh1, bd);
318 ASM_REGISTER_STATE_CHECK(loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0,
319 thresh0, blimit1, limit1, thresh1,
320 bd));
Deb Mukherjee931ed512014-09-17 16:55:05 -0700321#else
clang-format3a826f12016-08-11 17:46:05 -0700322 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1,
323 limit1, thresh1);
324 ASM_REGISTER_STATE_CHECK(loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0,
325 thresh0, blimit1, limit1, thresh1));
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200326#endif // CONFIG_HIGHBITDEPTH
Urvang Joshi88a03bb2016-10-17 14:34:48 -0700327 for (j = 0; j < kNumCoeffs; ++j) {
Deb Mukherjee931ed512014-09-17 16:55:05 -0700328 err_count += ref_s[j] != s[j];
329 }
330 if (err_count && !err_count_total) {
331 first_failure = i;
332 }
333 err_count_total += err_count;
334 }
335 EXPECT_EQ(0, err_count_total)
336 << "Error: Loop8Test9Param, C output doesn't match SSE2 "
337 "loopfilter output. "
338 << "First failed at test case " << first_failure;
339}
340
341TEST_P(Loop8Test9Param, ValueCheck) {
342 ACMRandom rnd(ACMRandom::DeterministicSeed());
343 const int count_test_block = number_of_iterations;
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200344#if CONFIG_HIGHBITDEPTH
James Zernfd3658b2015-05-02 13:24:16 -0700345 DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
346 DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
Deb Mukherjee931ed512014-09-17 16:55:05 -0700347#else
clang-format3a826f12016-08-11 17:46:05 -0700348 DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
349 DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200350#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700351 int err_count_total = 0;
352 int first_failure = -1;
353 for (int i = 0; i < count_test_block; ++i) {
354 int err_count = 0;
Deb Mukherjee072ed172014-12-03 16:26:48 -0800355 uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
clang-format3a826f12016-08-11 17:46:05 -0700356 DECLARE_ALIGNED(16, const uint8_t,
357 blimit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
358 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800359 tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
clang-format3a826f12016-08-11 17:46:05 -0700360 DECLARE_ALIGNED(16, const uint8_t,
361 limit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
362 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700363 tmp = rnd.Rand8();
clang-format3a826f12016-08-11 17:46:05 -0700364 DECLARE_ALIGNED(16, const uint8_t,
365 thresh0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
366 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800367 tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
clang-format3a826f12016-08-11 17:46:05 -0700368 DECLARE_ALIGNED(16, const uint8_t,
369 blimit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
370 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee072ed172014-12-03 16:26:48 -0800371 tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
clang-format3a826f12016-08-11 17:46:05 -0700372 DECLARE_ALIGNED(16, const uint8_t,
373 limit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
374 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700375 tmp = rnd.Rand8();
clang-format3a826f12016-08-11 17:46:05 -0700376 DECLARE_ALIGNED(16, const uint8_t,
377 thresh1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
378 tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp };
Deb Mukherjee931ed512014-09-17 16:55:05 -0700379 int32_t p = kNumCoeffs / 32; // TODO(pdlf) can we have non-square here?
380 for (int j = 0; j < kNumCoeffs; ++j) {
381 s[j] = rnd.Rand16() & mask_;
382 ref_s[j] = s[j];
383 }
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200384#if CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700385 const int32_t bd = bit_depth_;
clang-format3a826f12016-08-11 17:46:05 -0700386 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1,
387 limit1, thresh1, bd);
388 ASM_REGISTER_STATE_CHECK(loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0,
389 thresh0, blimit1, limit1, thresh1,
390 bd));
Deb Mukherjee931ed512014-09-17 16:55:05 -0700391#else
clang-format3a826f12016-08-11 17:46:05 -0700392 ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1,
393 limit1, thresh1);
394 ASM_REGISTER_STATE_CHECK(loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0,
395 thresh0, blimit1, limit1, thresh1));
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200396#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700397 for (int j = 0; j < kNumCoeffs; ++j) {
398 err_count += ref_s[j] != s[j];
399 }
400 if (err_count && !err_count_total) {
401 first_failure = i;
402 }
403 err_count_total += err_count;
404 }
405 EXPECT_EQ(0, err_count_total)
406 << "Error: Loop8Test9Param, C output doesn't match SSE2"
407 "loopfilter output. "
408 << "First failed at test case " << first_failure;
409}
410
411using std::tr1::make_tuple;
412
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700413#if HAVE_SSE2 && (!CONFIG_PARALLEL_DEBLOCKING)
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200414#if CONFIG_HIGHBITDEPTH
Yaowu Xu1fd71052017-06-19 15:59:00 -0700415
416const loop8_param_t kHbdLoop8Test6[] = {
417 make_tuple(&aom_highbd_lpf_horizontal_4_sse2, &aom_highbd_lpf_horizontal_4_c,
418 8),
419 make_tuple(&aom_highbd_lpf_vertical_4_sse2, &aom_highbd_lpf_vertical_4_c, 8),
420 make_tuple(&aom_highbd_lpf_horizontal_8_sse2, &aom_highbd_lpf_horizontal_8_c,
421 8),
422 make_tuple(&aom_highbd_lpf_horizontal_edge_8_sse2,
423 &aom_highbd_lpf_horizontal_edge_8_c, 8),
424 make_tuple(&aom_highbd_lpf_horizontal_edge_16_sse2,
425 &aom_highbd_lpf_horizontal_edge_16_c, 8),
426 make_tuple(&aom_highbd_lpf_vertical_8_sse2, &aom_highbd_lpf_vertical_8_c, 8),
427 make_tuple(&aom_highbd_lpf_vertical_16_sse2, &aom_highbd_lpf_vertical_16_c,
428 8),
429 make_tuple(&aom_highbd_lpf_horizontal_4_sse2, &aom_highbd_lpf_horizontal_4_c,
430 10),
431 make_tuple(&aom_highbd_lpf_vertical_4_sse2, &aom_highbd_lpf_vertical_4_c, 10),
432 make_tuple(&aom_highbd_lpf_horizontal_8_sse2, &aom_highbd_lpf_horizontal_8_c,
433 10),
434 make_tuple(&aom_highbd_lpf_horizontal_edge_8_sse2,
435 &aom_highbd_lpf_horizontal_edge_8_c, 10),
436 make_tuple(&aom_highbd_lpf_horizontal_edge_16_sse2,
437 &aom_highbd_lpf_horizontal_edge_16_c, 10),
438 make_tuple(&aom_highbd_lpf_vertical_8_sse2, &aom_highbd_lpf_vertical_8_c, 10),
439 make_tuple(&aom_highbd_lpf_vertical_16_sse2, &aom_highbd_lpf_vertical_16_c,
440 10),
441 make_tuple(&aom_highbd_lpf_horizontal_4_sse2, &aom_highbd_lpf_horizontal_4_c,
442 12),
443 make_tuple(&aom_highbd_lpf_vertical_4_sse2, &aom_highbd_lpf_vertical_4_c, 12),
444 make_tuple(&aom_highbd_lpf_horizontal_8_sse2, &aom_highbd_lpf_horizontal_8_c,
445 12),
446 make_tuple(&aom_highbd_lpf_horizontal_edge_8_sse2,
447 &aom_highbd_lpf_horizontal_edge_8_c, 12),
448 make_tuple(&aom_highbd_lpf_horizontal_edge_16_sse2,
449 &aom_highbd_lpf_horizontal_edge_16_c, 12),
450 make_tuple(&aom_highbd_lpf_vertical_8_sse2, &aom_highbd_lpf_vertical_8_c, 12),
451 make_tuple(&aom_highbd_lpf_vertical_16_sse2, &aom_highbd_lpf_vertical_16_c,
452 12),
453 make_tuple(&aom_highbd_lpf_vertical_16_dual_sse2,
454 &aom_highbd_lpf_vertical_16_dual_c, 8),
455 make_tuple(&aom_highbd_lpf_vertical_16_dual_sse2,
456 &aom_highbd_lpf_vertical_16_dual_c, 10),
457 make_tuple(&aom_highbd_lpf_vertical_16_dual_sse2,
458 &aom_highbd_lpf_vertical_16_dual_c, 12)
459};
460
461INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test6Param,
462 ::testing::ValuesIn(kHbdLoop8Test6));
Deb Mukherjee931ed512014-09-17 16:55:05 -0700463#else
Yaowu Xu1fd71052017-06-19 15:59:00 -0700464const loop8_param_t kLoop8Test6[] = {
465 make_tuple(&aom_lpf_horizontal_4_sse2, &aom_lpf_horizontal_4_c, 8),
466 make_tuple(&aom_lpf_horizontal_8_sse2, &aom_lpf_horizontal_8_c, 8),
467 make_tuple(&aom_lpf_horizontal_edge_8_sse2, &aom_lpf_horizontal_edge_8_c, 8),
468 make_tuple(&aom_lpf_horizontal_edge_16_sse2, &aom_lpf_horizontal_edge_16_c,
469 8),
470 make_tuple(&aom_lpf_vertical_4_sse2, &aom_lpf_vertical_4_c, 8),
471 make_tuple(&aom_lpf_vertical_8_sse2, &aom_lpf_vertical_8_c, 8),
472 make_tuple(&aom_lpf_vertical_16_sse2, &aom_lpf_vertical_16_c, 8),
473 make_tuple(&aom_lpf_vertical_16_dual_sse2, &aom_lpf_vertical_16_dual_c, 8)
474};
475
476INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test6Param,
477 ::testing::ValuesIn(kLoop8Test6));
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200478#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee27dce0f2014-11-07 10:19:46 -0800479#endif
480
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700481#if HAVE_AVX2 && (!CONFIG_HIGHBITDEPTH) && (!CONFIG_PARALLEL_DEBLOCKING)
Deb Mukherjee27dce0f2014-11-07 10:19:46 -0800482INSTANTIATE_TEST_CASE_P(
Deb Mukherjee072ed172014-12-03 16:26:48 -0800483 AVX2, Loop8Test6Param,
Yaowu Xuf883b422016-08-30 14:01:10 -0700484 ::testing::Values(make_tuple(&aom_lpf_horizontal_edge_8_avx2,
485 &aom_lpf_horizontal_edge_8_c, 8),
486 make_tuple(&aom_lpf_horizontal_edge_16_avx2,
487 &aom_lpf_horizontal_edge_16_c, 8)));
Deb Mukherjee27dce0f2014-11-07 10:19:46 -0800488#endif
Deb Mukherjee931ed512014-09-17 16:55:05 -0700489
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700490#if HAVE_SSE2 && (!CONFIG_PARALLEL_DEBLOCKING)
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200491#if CONFIG_HIGHBITDEPTH
Yaowu Xu1fd71052017-06-19 15:59:00 -0700492const dualloop8_param_t kHbdLoop8Test9[] = {
493 make_tuple(&aom_highbd_lpf_horizontal_4_dual_sse2,
494 &aom_highbd_lpf_horizontal_4_dual_c, 8),
495 make_tuple(&aom_highbd_lpf_horizontal_8_dual_sse2,
496 &aom_highbd_lpf_horizontal_8_dual_c, 8),
497 make_tuple(&aom_highbd_lpf_vertical_4_dual_sse2,
498 &aom_highbd_lpf_vertical_4_dual_c, 8),
499 make_tuple(&aom_highbd_lpf_vertical_8_dual_sse2,
500 &aom_highbd_lpf_vertical_8_dual_c, 8),
501 make_tuple(&aom_highbd_lpf_horizontal_4_dual_sse2,
502 &aom_highbd_lpf_horizontal_4_dual_c, 10),
503 make_tuple(&aom_highbd_lpf_horizontal_8_dual_sse2,
504 &aom_highbd_lpf_horizontal_8_dual_c, 10),
505 make_tuple(&aom_highbd_lpf_vertical_4_dual_sse2,
506 &aom_highbd_lpf_vertical_4_dual_c, 10),
507 make_tuple(&aom_highbd_lpf_vertical_8_dual_sse2,
508 &aom_highbd_lpf_vertical_8_dual_c, 10),
509 make_tuple(&aom_highbd_lpf_horizontal_4_dual_sse2,
510 &aom_highbd_lpf_horizontal_4_dual_c, 12),
511 make_tuple(&aom_highbd_lpf_horizontal_8_dual_sse2,
512 &aom_highbd_lpf_horizontal_8_dual_c, 12),
513 make_tuple(&aom_highbd_lpf_vertical_4_dual_sse2,
514 &aom_highbd_lpf_vertical_4_dual_c, 12),
515 make_tuple(&aom_highbd_lpf_vertical_8_dual_sse2,
516 &aom_highbd_lpf_vertical_8_dual_c, 12)
517};
518
519INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test9Param,
520 ::testing::ValuesIn(kHbdLoop8Test9));
Deb Mukherjee931ed512014-09-17 16:55:05 -0700521#else
Yaowu Xu1fd71052017-06-19 15:59:00 -0700522const dualloop8_param_t kLoop8Test9[] = {
523 make_tuple(&aom_lpf_horizontal_4_dual_sse2, &aom_lpf_horizontal_4_dual_c, 8),
524 make_tuple(&aom_lpf_horizontal_8_dual_sse2, &aom_lpf_horizontal_8_dual_c, 8),
525 make_tuple(&aom_lpf_vertical_4_dual_sse2, &aom_lpf_vertical_4_dual_c, 8),
526 make_tuple(&aom_lpf_vertical_8_dual_sse2, &aom_lpf_vertical_8_dual_c, 8)
527};
528
529INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test9Param,
530 ::testing::ValuesIn(kLoop8Test9));
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200531#endif // CONFIG_HIGHBITDEPTH
Deb Mukherjee931ed512014-09-17 16:55:05 -0700532#endif
levytamar8286175a52014-10-16 16:56:37 -0700533
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700534#if HAVE_NEON && (!CONFIG_PARALLEL_DEBLOCKING)
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200535#if CONFIG_HIGHBITDEPTH
Johannfca00372015-01-06 14:13:41 -0800536// No neon high bitdepth functions.
537#else
James Yu5b098b12014-01-21 09:43:29 +0800538INSTANTIATE_TEST_CASE_P(
539 NEON, Loop8Test6Param,
540 ::testing::Values(
541#if HAVE_NEON_ASM
clang-format3a826f12016-08-11 17:46:05 -0700542 // Using #if inside the macro is unsupported on MSVS but the tests are
543 // not
544 // currently built for MSVS with ARM and NEON.
Yaowu Xuf883b422016-08-30 14:01:10 -0700545 make_tuple(&aom_lpf_horizontal_edge_8_neon,
546 &aom_lpf_horizontal_edge_8_c, 8),
547 make_tuple(&aom_lpf_horizontal_edge_16_neon,
548 &aom_lpf_horizontal_edge_16_c, 8),
549 make_tuple(&aom_lpf_vertical_16_neon, &aom_lpf_vertical_16_c, 8),
550 make_tuple(&aom_lpf_vertical_16_dual_neon, &aom_lpf_vertical_16_dual_c,
clang-format3a826f12016-08-11 17:46:05 -0700551 8),
Jingning Han50adfdf2015-07-15 19:14:54 -0700552#endif // HAVE_NEON_ASM
Yaowu Xuf883b422016-08-30 14:01:10 -0700553 make_tuple(&aom_lpf_horizontal_8_neon, &aom_lpf_horizontal_8_c, 8),
554 make_tuple(&aom_lpf_vertical_8_neon, &aom_lpf_vertical_8_c, 8),
555 make_tuple(&aom_lpf_horizontal_4_neon, &aom_lpf_horizontal_4_c, 8),
556 make_tuple(&aom_lpf_vertical_4_neon, &aom_lpf_vertical_4_c, 8)));
clang-format3a826f12016-08-11 17:46:05 -0700557INSTANTIATE_TEST_CASE_P(NEON, Loop8Test9Param,
558 ::testing::Values(
Johann377b6682014-12-19 15:00:04 -0800559#if HAVE_NEON_ASM
Yaowu Xuf883b422016-08-30 14:01:10 -0700560 make_tuple(&aom_lpf_horizontal_8_dual_neon,
561 &aom_lpf_horizontal_8_dual_c, 8),
562 make_tuple(&aom_lpf_vertical_8_dual_neon,
563 &aom_lpf_vertical_8_dual_c, 8),
Johann377b6682014-12-19 15:00:04 -0800564#endif // HAVE_NEON_ASM
Yaowu Xuf883b422016-08-30 14:01:10 -0700565 make_tuple(&aom_lpf_horizontal_4_dual_neon,
566 &aom_lpf_horizontal_4_dual_c, 8),
567 make_tuple(&aom_lpf_vertical_4_dual_neon,
568 &aom_lpf_vertical_4_dual_c, 8)));
Sebastien Alaiwan71e87842017-04-12 16:03:28 +0200569#endif // CONFIG_HIGHBITDEPTH
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700570#endif // HAVE_NEON && (!CONFIG_PARALLEL_DEBLOCKING)
James Yu5b098b12014-01-21 09:43:29 +0800571
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700572#if HAVE_DSPR2 && !CONFIG_HIGHBITDEPTH && (!CONFIG_PARALLEL_DEBLOCKING)
James Zern47dee372016-02-13 10:24:26 -0800573INSTANTIATE_TEST_CASE_P(
574 DSPR2, Loop8Test6Param,
575 ::testing::Values(
Yaowu Xuf883b422016-08-30 14:01:10 -0700576 make_tuple(&aom_lpf_horizontal_4_dspr2, &aom_lpf_horizontal_4_c, 8),
577 make_tuple(&aom_lpf_horizontal_8_dspr2, &aom_lpf_horizontal_8_c, 8),
578 make_tuple(&aom_lpf_horizontal_edge_8, &aom_lpf_horizontal_edge_8, 8),
579 make_tuple(&aom_lpf_horizontal_edge_16, &aom_lpf_horizontal_edge_16, 8),
580 make_tuple(&aom_lpf_vertical_4_dspr2, &aom_lpf_vertical_4_c, 8),
581 make_tuple(&aom_lpf_vertical_8_dspr2, &aom_lpf_vertical_8_c, 8),
582 make_tuple(&aom_lpf_vertical_16_dspr2, &aom_lpf_vertical_16_c, 8),
583 make_tuple(&aom_lpf_vertical_16_dual_dspr2, &aom_lpf_vertical_16_dual_c,
clang-format3a826f12016-08-11 17:46:05 -0700584 8)));
James Zern47dee372016-02-13 10:24:26 -0800585
586INSTANTIATE_TEST_CASE_P(
587 DSPR2, Loop8Test9Param,
Yaowu Xuf883b422016-08-30 14:01:10 -0700588 ::testing::Values(make_tuple(&aom_lpf_horizontal_4_dual_dspr2,
589 &aom_lpf_horizontal_4_dual_c, 8),
590 make_tuple(&aom_lpf_horizontal_8_dual_dspr2,
591 &aom_lpf_horizontal_8_dual_c, 8),
592 make_tuple(&aom_lpf_vertical_4_dual_dspr2,
593 &aom_lpf_vertical_4_dual_c, 8),
594 make_tuple(&aom_lpf_vertical_8_dual_dspr2,
595 &aom_lpf_vertical_8_dual_c, 8)));
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700596#endif // HAVE_DSPR2 && !CONFIG_HIGHBITDEPTH && (!CONFIG_PARALLEL_DEBLOCKING)
James Zern47dee372016-02-13 10:24:26 -0800597
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700598#if HAVE_MSA && (!CONFIG_HIGHBITDEPTH) && (!CONFIG_PARALLEL_DEBLOCKING)
Parag Salasakar914f8f92015-06-04 11:50:41 +0530599INSTANTIATE_TEST_CASE_P(
600 MSA, Loop8Test6Param,
601 ::testing::Values(
Yaowu Xuf883b422016-08-30 14:01:10 -0700602 make_tuple(&aom_lpf_horizontal_4_msa, &aom_lpf_horizontal_4_c, 8),
603 make_tuple(&aom_lpf_horizontal_8_msa, &aom_lpf_horizontal_8_c, 8),
604 make_tuple(&aom_lpf_horizontal_edge_8_msa, &aom_lpf_horizontal_edge_8_c,
clang-format3a826f12016-08-11 17:46:05 -0700605 8),
Yaowu Xuf883b422016-08-30 14:01:10 -0700606 make_tuple(&aom_lpf_horizontal_edge_16_msa,
607 &aom_lpf_horizontal_edge_16_c, 8),
608 make_tuple(&aom_lpf_vertical_4_msa, &aom_lpf_vertical_4_c, 8),
609 make_tuple(&aom_lpf_vertical_8_msa, &aom_lpf_vertical_8_c, 8),
610 make_tuple(&aom_lpf_vertical_16_msa, &aom_lpf_vertical_16_c, 8)));
Parag Salasakard43fd992015-06-05 07:52:40 +0530611
612INSTANTIATE_TEST_CASE_P(
613 MSA, Loop8Test9Param,
Yaowu Xuf883b422016-08-30 14:01:10 -0700614 ::testing::Values(make_tuple(&aom_lpf_horizontal_4_dual_msa,
615 &aom_lpf_horizontal_4_dual_c, 8),
616 make_tuple(&aom_lpf_horizontal_8_dual_msa,
617 &aom_lpf_horizontal_8_dual_c, 8),
618 make_tuple(&aom_lpf_vertical_4_dual_msa,
619 &aom_lpf_vertical_4_dual_c, 8),
620 make_tuple(&aom_lpf_vertical_8_dual_msa,
621 &aom_lpf_vertical_8_dual_c, 8)));
Ryan Lei2c6ca5f2017-07-11 17:31:28 -0700622#endif // HAVE_MSA && (!CONFIG_HIGHBITDEPTH) && (!CONFIG_PARALLEL_DEBLOCKING)
Parag Salasakar914f8f92015-06-04 11:50:41 +0530623
Deb Mukherjee931ed512014-09-17 16:55:05 -0700624} // namespace