xref: /aosp_15_r20/external/libgav1/src/dsp/loop_restoration_test.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1 // Copyright 2021 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/dsp/loop_restoration.h"
16 
17 #include <algorithm>
18 #include <cstdint>
19 #include <cstring>
20 #include <string>
21 
22 #include "absl/strings/match.h"
23 #include "absl/time/clock.h"
24 #include "absl/time/time.h"
25 #include "gtest/gtest.h"
26 #include "src/dsp/common.h"
27 #include "src/dsp/dsp.h"
28 #include "src/utils/common.h"
29 #include "src/utils/constants.h"
30 #include "src/utils/cpu.h"
31 #include "src/utils/memory.h"
32 #include "tests/block_utils.h"
33 #include "tests/third_party/libvpx/acm_random.h"
34 #include "tests/utils.h"
35 
36 namespace libgav1 {
37 namespace dsp {
38 namespace {
39 
40 // in unit of Pixel.
41 constexpr int kBorder = 16;
42 constexpr int kWidth = 256;
43 constexpr int kHeight = 255;
44 constexpr int kStride = kWidth + 2 * kBorder;
45 constexpr int kOffset = kBorder * kStride + kBorder;
46 constexpr int kMaxBlockSize = 288 * kStride;
47 constexpr int kUnitWidths[] = {32, 64, 128, 256};
48 
49 constexpr int kNumRadiusTypes = 3;
50 constexpr int kNumWienerOrders = 4;
51 constexpr int kWienerOrders[] = {7, 5, 3, 1};
52 constexpr int kWienerOrderIdLookup[] = {0, 3, 0, 2, 0, 1, 0, 0};
53 
54 template <int bitdepth, typename Pixel>
55 class SelfGuidedFilterTest : public testing::TestWithParam<int>,
56                              public test_utils::MaxAlignedAllocable {
57  public:
58   static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
59   SelfGuidedFilterTest() = default;
60   SelfGuidedFilterTest(const SelfGuidedFilterTest&) = delete;
61   SelfGuidedFilterTest& operator=(const SelfGuidedFilterTest&) = delete;
62   ~SelfGuidedFilterTest() override = default;
63 
SetUp()64   void SetUp() override {
65     test_utils::ResetDspTable(bitdepth);
66     LoopRestorationInit_C();
67     const testing::TestInfo* const test_info =
68         testing::UnitTest::GetInstance()->current_test_info();
69     const char* const test_case = test_info->test_suite_name();
70     if (absl::StartsWith(test_case, "C/")) {
71     } else if (absl::StartsWith(test_case, "AVX2/")) {
72       if ((GetCpuInfo() & kAVX2) == 0) GTEST_SKIP() << "No AVX2 support!";
73       LoopRestorationInit_AVX2();
74 #if LIBGAV1_MAX_BITDEPTH >= 10
75       LoopRestorationInit10bpp_AVX2();
76 #endif
77     } else if (absl::StartsWith(test_case, "SSE41/")) {
78       if ((GetCpuInfo() & kSSE4_1) == 0) GTEST_SKIP() << "No SSE4.1 support!";
79       LoopRestorationInit_SSE4_1();
80 #if LIBGAV1_MAX_BITDEPTH >= 10
81       LoopRestorationInit10bpp_SSE4_1();
82 #endif
83     } else if (absl::StartsWith(test_case, "NEON/")) {
84       LoopRestorationInit_NEON();
85 #if LIBGAV1_MAX_BITDEPTH >= 10
86       LoopRestorationInit10bpp_NEON();
87 #endif
88     } else {
89       FAIL() << "Unrecognized architecture prefix in test case name: "
90              << test_case;
91     }
92     const Dsp* const dsp = GetDspTable(bitdepth);
93     ASSERT_NE(dsp, nullptr);
94     target_self_guided_filter_func_ = dsp->loop_restorations[1];
95     restoration_info_.type = kLoopRestorationTypeSgrProj;
96     memset(dst_, 0, sizeof(dst_));
97   }
98 
99   void SetInputData(int type, Pixel value, int radius_index,
100                     libvpx_test::ACMRandom* rnd);
101   void TestFixedValues(int test_index, Pixel value);
102   void TestRandomValues(bool speed);
103 
104  protected:
105   const int unit_width_ = GetParam();
106   const int unit_height_ = kRestorationUnitHeight;
107 
108  private:
109   alignas(kMaxAlignment) Pixel src_[kMaxBlockSize];
110   alignas(kMaxAlignment) Pixel dst_[kMaxBlockSize];
111   RestorationUnitInfo restoration_info_;
112   RestorationBuffer restoration_buffer_;
113   LoopRestorationFunc target_self_guided_filter_func_;
114 };
115 
116 template <int bitdepth, typename Pixel>
SetInputData(int type,Pixel value,int radius_index,libvpx_test::ACMRandom * const rnd)117 void SelfGuidedFilterTest<bitdepth, Pixel>::SetInputData(
118     int type, Pixel value, int radius_index,
119     libvpx_test::ACMRandom* const rnd) {
120   const int mask = (1 << bitdepth) - 1;
121   if (type == 0) {  // Set fixed values
122     for (auto& s : src_) s = value;
123   } else {  // Set random values
124     for (auto& s : src_) s = rnd->Rand16() & mask;
125   }
126   for (auto& d : dst_) d = rnd->Rand16() & mask;
127   restoration_info_.sgr_proj_info.multiplier[0] =
128       kSgrProjMultiplierMin[0] +
129       rnd->PseudoUniform(kSgrProjMultiplierMax[0] - kSgrProjMultiplierMin[0] +
130                          1);
131   restoration_info_.sgr_proj_info.multiplier[1] =
132       kSgrProjMultiplierMin[1] +
133       rnd->PseudoUniform(kSgrProjMultiplierMax[1] - kSgrProjMultiplierMin[1] +
134                          1);
135   // regulate multiplier so that it matches libaom.
136   // Valid self-guided filter doesn't allow r0 and r1 to be 0 at the same time.
137   // When r0 or r1 is zero, its corresponding multiplier is set to zero in
138   // libaom.
139   int index;
140   if (radius_index == 0) {
141     index = 0;  // r0 = 2, r1 = 1
142   } else if (radius_index == 1) {
143     index = 10;  // r0 = 0, r1 = 1
144   } else /* if (radius_index == 2) */ {
145     index = 14;  // r0 = 2, r1 = 0
146   }
147   const uint8_t r0 = kSgrProjParams[index][0];
148   const uint8_t r1 = kSgrProjParams[index][2];
149   static constexpr int kMultiplier[2] = {0, 95};
150   restoration_info_.sgr_proj_info.index = index;
151   if (r0 == 0) {
152     restoration_info_.sgr_proj_info.multiplier[0] = kMultiplier[0];
153   } else if (r1 == 0) {
154     restoration_info_.sgr_proj_info.multiplier[1] = kMultiplier[1];
155   }
156 }
157 
158 template <int bitdepth, typename Pixel>
TestFixedValues(int test_index,Pixel value)159 void SelfGuidedFilterTest<bitdepth, Pixel>::TestFixedValues(int test_index,
160                                                             Pixel value) {
161   static const char* const kDigest[][3][kNumRadiusTypes] = {
162       {{"7b78783ff4f03625a50c2ebfd574adca", "4faa0810639016f11a9f761ce28c38b0",
163         "a03314fc210bee68c7adbb44d2bbdac7"},
164        {"fce031d1339cfef5016e76a643538a71", "d439e1060de3f07b5b29c9b0b7c08e54",
165         "a6583fe9359877f4a259c81d900fc4fb"},
166        {"8f9b6944c8965f34d444a667da3b0ebe", "84fa62c491c67c3a435fd5140e7a4f82",
167         "d04b62d97228789e5c6928d40d5d900e"}},
168       {{"948ea16a90c4cefef87ce5b0ee105fc6", "76740629877b721432b84dbbdb4e352a",
169         "27100f37b3e42a5f2a051e1566edb6f8"},
170        {"dd320de3bc82f4ba69738b2190ea9f85", "bf82f271e30a1aca91e53b086e133fb3",
171         "69c274ac59c99999e1bfbf2fc4586ebd"},
172        {"86ff2318bf8a584b8d5edd710681d621", "f6e1c104a764d6766cc278d5b216855a",
173         "6d928703526ab114efba865ff5b11886"}},
174       {{"9fbf1b246011250f38532a543cc6dd74", "d5c1e0142390ebb51b075c49f8ee9ff4",
175         "92f31086ba2f9e1508983b22d93a4e5c"},
176        {"2198321e6b95e7199738e60f5ddc6966", "34f74626027ffca010c824ddf0942b13",
177         "43dd7df2c2a601262c68cd8af1c61b82"},
178        {"1ab6138c3a82ac8ccd840f0553fdfb58", "be3bf92633f7165d3ad9c327d2dd53fe",
179         "41115efff3adeb541e04db23faa22f23"}},
180       {{"42364ff8dbdbd6706fa3b8855a4258be", "a7843fdfd4d3c0d80ba812b353b4d6b4",
181         "f8a6a025827f29f857bed3e28ba3ea33"},
182        {"b83c1f8d7712e37f9b21b033822e37ed", "589daf2e3e6f8715873920515cfc1b42",
183         "20dcbe8e317a4373bebf11d56adc5f02"},
184        {"7971a60337fcdb662c92db051bd0bb41", "75f89f346c2a37bf0c6695c0482531e6",
185         "1595eeacd62cdce4d2fb094534c22c1e"}}};
186   if (target_self_guided_filter_func_ == nullptr) return;
187   ASSERT_LT(value, 1 << bitdepth);
188   constexpr int bd_index = (bitdepth - 8) / 2;
189   libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
190   const Pixel* const src = src_ + kOffset;
191   Pixel* const dst = dst_ + kOffset;
192   for (int radius_index = 0; radius_index < kNumRadiusTypes; ++radius_index) {
193     SetInputData(0, value, radius_index, &rnd);
194     const absl::Time start = absl::Now();
195     for (int y = 0; y < kHeight; y += unit_height_) {
196       const int height = std::min(unit_height_, kHeight - y);
197       for (int x = 0; x < kWidth; x += unit_width_) {
198         const int width = std::min(unit_width_, kWidth - x);
199         const Pixel* const source = src + y * kStride + x;
200         target_self_guided_filter_func_(
201             restoration_info_, source, kStride,
202             source - kRestorationVerticalBorder * kStride, kStride,
203             source + height * kStride, kStride, width, height,
204             &restoration_buffer_, dst + y * kStride + x);
205       }
206     }
207     const absl::Duration elapsed_time = absl::Now() - start;
208     test_utils::CheckMd5Digest(
209         "kLoopRestorationTypeSgrProj", std::to_string(GetParam()).c_str(),
210         kDigest[test_index][bd_index][radius_index], dst_ + kBorder * kStride,
211         kHeight * kStride * sizeof(*dst_), elapsed_time);
212   }
213 }
214 
215 template <int bitdepth, typename Pixel>
TestRandomValues(bool speed)216 void SelfGuidedFilterTest<bitdepth, Pixel>::TestRandomValues(bool speed) {
217   static const char* const kDigest[][3][kNumRadiusTypes] = {
218       {{"9f8358ed820943fa0abe3a8ebb5887db", "fb5d48870165522341843bcbfa8674fb",
219         "ca67159cd29475ac5d52ca4a0df3ea10"},
220        {"a78641886ea0cf8757057d1d91e01434", "1b95172a5f2f9c514c78afa4cf8e5678",
221         "a8ba988283d9e1ad1f0dcdbf6bbdaade"},
222        {"d95e98d031f9ba290e5183777d1e4905", "f806853cfadb50e6dbd4898412b92934",
223         "741fbfdb79cda695afedda3d51dbb27f"}},
224       {{"f219b445e5c80ffb5dd0359cc2cb4dd4", "699b2c9ddca1cbb0d4fc24cbcbe951e9",
225         "a4005899fa8d3c3c4669910f93ff1290"},
226        {"10a75cab3c78b891c8c6d92d55f685d1", "d46f158f57c628136f6f298ee8ca6e0e",
227         "07203ad761775d5d317f2b7884afd9fe"},
228        {"76b9ef906090fa81af64cce3bba0a54a", "8eecc59acdef8953aa9a96648c0ccd2c",
229         "6e45a0ef60e0475f470dc93552047f07"}},
230       {{"000d4e382be4003b514c9135893d0a37", "8fb082dca975be363bfc9c2d317ae084",
231         "475bcb6a58f87da7723f6227bc2aca0e"},
232        {"4d589683f69ccc5b416149dcc5c835d5", "986b6832df1f6020d50be61ae121e42f",
233         "7cb5c5dbdb3d1c54cfa00def450842dc"},
234        {"0e3dc23150d18c9d366d15e174727311", "8495122917770d822f1842ceff987b03",
235         "4aeb9db902072cefd6af0aff8aaabd24"}},
236       {{"fd43bfe34d63614554dd29fb24b12173", "5c1ba74ba3062c769d5c3c86a85ac9b9",
237         "f1eda6d15b37172199d9949c2315832f"},
238        {"a11be3117fb77e8fe113581b06f98bd1", "df94d12b774ad5cf744c871e707c36c8",
239         "b23dc0b54c3500248d53377030428a61"},
240        {"9c331f2b9410354685fe904f6c022dfa", "b540b0045b7723fbe962fd675db4b077",
241         "3cecd1158126c9c9cc2873ecc8c1a135"}},
242       {{"f3079b3b21d8dc6fce7bb1fd104be359", "c6fcbc686cfb97ab3a64f445d73aad36",
243         "23966cba3e0e7803eeb951905861e0dd"},
244        {"7210391a6fe26e5ca5ea205bc38aa035", "4c3e6eccad3ea152d320ecd1077169de",
245         "dcee48f94126a2132963e86e93dd4903"},
246        {"beb3dd8a2dbc5f83ef171b0ffcead3ab", "c373bd9c46bdb89a3d1e41759c315025",
247         "cd407b212ab46fd4a451d5dc93a0ce4a"}}};
248   if (target_self_guided_filter_func_ == nullptr) return;
249   constexpr int bd_index = (bitdepth - 8) / 2;
250   const int num_inputs = speed ? 1 : 5;
251 #if LIBGAV1_ENABLE_NEON
252   const int num_tests = speed ? 4000 : 1;
253 #else
254   const int num_tests = speed ? 10000 : 1;
255 #endif
256   libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
257   const Pixel* const src = src_ + kOffset;
258   Pixel* const dst = dst_ + kOffset;
259   for (int i = 0; i < num_inputs; ++i) {
260     for (int radius_index = 0; radius_index < kNumRadiusTypes; ++radius_index) {
261       SetInputData(1, 0, radius_index, &rnd);
262       const absl::Time start = absl::Now();
263       for (int k = 0; k < num_tests; ++k) {
264         for (int y = 0; y < kHeight; y += unit_height_) {
265           const int height = std::min(unit_height_, kHeight - y);
266           for (int x = 0; x < kWidth; x += unit_width_) {
267             const int width = std::min(unit_width_, kWidth - x);
268             const Pixel* const source = src + y * kStride + x;
269             target_self_guided_filter_func_(
270                 restoration_info_, source, kStride,
271                 source - kRestorationVerticalBorder * kStride, kStride,
272                 source + height * kStride, kStride, width, height,
273                 &restoration_buffer_, dst + y * kStride + x);
274           }
275         }
276       }
277       const absl::Duration elapsed_time = absl::Now() - start;
278       test_utils::CheckMd5Digest(
279           "kLoopRestorationTypeSgrProj", std::to_string(GetParam()).c_str(),
280           kDigest[i][bd_index][radius_index], dst_ + kBorder * kStride,
281           kHeight * kStride * sizeof(*dst_), elapsed_time);
282     }
283   }
284 }
285 
286 using SelfGuidedFilterTest8bpp = SelfGuidedFilterTest<8, uint8_t>;
287 
TEST_P(SelfGuidedFilterTest8bpp,Correctness)288 TEST_P(SelfGuidedFilterTest8bpp, Correctness) {
289   TestFixedValues(0, 0);
290   TestFixedValues(1, 1);
291   TestFixedValues(2, 128);
292   TestFixedValues(3, 255);
293   TestRandomValues(false);
294 }
295 
TEST_P(SelfGuidedFilterTest8bpp,DISABLED_Speed)296 TEST_P(SelfGuidedFilterTest8bpp, DISABLED_Speed) { TestRandomValues(true); }
297 
298 INSTANTIATE_TEST_SUITE_P(C, SelfGuidedFilterTest8bpp,
299                          testing::ValuesIn(kUnitWidths));
300 #if LIBGAV1_ENABLE_AVX2
301 INSTANTIATE_TEST_SUITE_P(AVX2, SelfGuidedFilterTest8bpp,
302                          testing::ValuesIn(kUnitWidths));
303 #endif
304 #if LIBGAV1_ENABLE_SSE4_1
305 INSTANTIATE_TEST_SUITE_P(SSE41, SelfGuidedFilterTest8bpp,
306                          testing::ValuesIn(kUnitWidths));
307 #endif
308 #if LIBGAV1_ENABLE_NEON
309 INSTANTIATE_TEST_SUITE_P(NEON, SelfGuidedFilterTest8bpp,
310                          testing::ValuesIn(kUnitWidths));
311 #endif
312 
313 #if LIBGAV1_MAX_BITDEPTH >= 10
314 using SelfGuidedFilterTest10bpp = SelfGuidedFilterTest<10, uint16_t>;
315 
TEST_P(SelfGuidedFilterTest10bpp,Correctness)316 TEST_P(SelfGuidedFilterTest10bpp, Correctness) {
317   TestFixedValues(0, 0);
318   TestFixedValues(1, 1);
319   TestFixedValues(2, 512);
320   TestFixedValues(3, 1023);
321   TestRandomValues(false);
322 }
323 
TEST_P(SelfGuidedFilterTest10bpp,DISABLED_Speed)324 TEST_P(SelfGuidedFilterTest10bpp, DISABLED_Speed) { TestRandomValues(true); }
325 
326 INSTANTIATE_TEST_SUITE_P(C, SelfGuidedFilterTest10bpp,
327                          testing::ValuesIn(kUnitWidths));
328 
329 #if LIBGAV1_ENABLE_AVX2
330 INSTANTIATE_TEST_SUITE_P(AVX2, SelfGuidedFilterTest10bpp,
331                          testing::ValuesIn(kUnitWidths));
332 #endif
333 #if LIBGAV1_ENABLE_SSE4_1
334 INSTANTIATE_TEST_SUITE_P(SSE41, SelfGuidedFilterTest10bpp,
335                          testing::ValuesIn(kUnitWidths));
336 #endif
337 #if LIBGAV1_ENABLE_NEON
338 INSTANTIATE_TEST_SUITE_P(NEON, SelfGuidedFilterTest10bpp,
339                          testing::ValuesIn(kUnitWidths));
340 #endif
341 
342 #endif  // LIBGAV1_MAX_BITDEPTH >= 10
343 
344 #if LIBGAV1_MAX_BITDEPTH == 12
345 using SelfGuidedFilterTest12bpp = SelfGuidedFilterTest<12, uint16_t>;
346 
TEST_P(SelfGuidedFilterTest12bpp,Correctness)347 TEST_P(SelfGuidedFilterTest12bpp, Correctness) {
348   TestFixedValues(0, 0);
349   TestFixedValues(1, 1);
350   TestFixedValues(2, 2048);
351   TestFixedValues(3, 4095);
352   TestRandomValues(false);
353 }
354 
TEST_P(SelfGuidedFilterTest12bpp,DISABLED_Speed)355 TEST_P(SelfGuidedFilterTest12bpp, DISABLED_Speed) { TestRandomValues(true); }
356 
357 INSTANTIATE_TEST_SUITE_P(C, SelfGuidedFilterTest12bpp,
358                          testing::ValuesIn(kUnitWidths));
359 #endif  // LIBGAV1_MAX_BITDEPTH == 12
360 
361 template <int bitdepth, typename Pixel>
362 class WienerFilterTest : public testing::TestWithParam<int>,
363                          public test_utils::MaxAlignedAllocable {
364  public:
365   static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
366   WienerFilterTest() = default;
367   WienerFilterTest(const WienerFilterTest&) = delete;
368   WienerFilterTest& operator=(const WienerFilterTest&) = delete;
369   ~WienerFilterTest() override = default;
370 
SetUp()371   void SetUp() override {
372     test_utils::ResetDspTable(bitdepth);
373     LoopRestorationInit_C();
374     const Dsp* const dsp = GetDspTable(bitdepth);
375     ASSERT_NE(dsp, nullptr);
376     base_wiener_filter_func_ = dsp->loop_restorations[0];
377     const testing::TestInfo* const test_info =
378         testing::UnitTest::GetInstance()->current_test_info();
379     const char* const test_case = test_info->test_suite_name();
380     if (absl::StartsWith(test_case, "C/")) {
381     } else if (absl::StartsWith(test_case, "AVX2/")) {
382       if ((GetCpuInfo() & kAVX2) == 0) GTEST_SKIP() << "No AVX2 support!";
383       LoopRestorationInit_AVX2();
384 #if LIBGAV1_MAX_BITDEPTH >= 10
385       LoopRestorationInit10bpp_AVX2();
386 #endif
387     } else if (absl::StartsWith(test_case, "SSE41/")) {
388       if ((GetCpuInfo() & kSSE4_1) == 0) GTEST_SKIP() << "No SSE4.1 support!";
389       LoopRestorationInit_SSE4_1();
390 #if LIBGAV1_MAX_BITDEPTH >= 10
391       LoopRestorationInit10bpp_SSE4_1();
392 #endif
393     } else if (absl::StartsWith(test_case, "NEON/")) {
394       LoopRestorationInit_NEON();
395 #if LIBGAV1_MAX_BITDEPTH >= 10
396       LoopRestorationInit10bpp_NEON();
397 #endif
398     } else {
399       FAIL() << "Unrecognized architecture prefix in test case name: "
400              << test_case;
401     }
402     target_wiener_filter_func_ = dsp->loop_restorations[0];
403     restoration_info_.type = kLoopRestorationTypeWiener;
404     memset(dst_, 0, sizeof(dst_));
405     memset(tmp_, 0, sizeof(tmp_));
406     memset(buffer_, 0, sizeof(buffer_));
407   }
408 
CleanFilterByOrder(const int order,int16_t filter[kWienerFilterTaps])409   static void CleanFilterByOrder(const int order,
410                                  int16_t filter[kWienerFilterTaps]) {
411     if (order <= 5) filter[0] = 0;
412     if (order <= 3) filter[1] = 0;
413     if (order <= 1) filter[2] = 0;
414   }
415 
416   void SetInputData(int type, Pixel value, int vertical_order,
417                     int horizontal_order);
418   void TestFixedValues(int digest_id, Pixel value);
419   void TestRandomValues(bool speed);
420   void TestCompare2C();
421 
422  protected:
423   const int unit_width_ = GetParam();
424   const int unit_height_ = kRestorationUnitHeight;
425 
426  private:
427   alignas(kMaxAlignment)
428       uint16_t buffer_[(kRestorationUnitWidth + kWienerFilterTaps - 1) *
429                        kRestorationUnitHeight];
430   alignas(kMaxAlignment) Pixel src_[kMaxBlockSize];
431   alignas(kMaxAlignment) Pixel dst_[kMaxBlockSize];
432   alignas(kMaxAlignment) Pixel tmp_[kMaxBlockSize];
433   RestorationUnitInfo restoration_info_;
434   RestorationBuffer restoration_buffer_;
435   LoopRestorationFunc base_wiener_filter_func_;
436   LoopRestorationFunc target_wiener_filter_func_;
437 };
438 
439 template <int bitdepth, typename Pixel>
SetInputData(int type,Pixel value,const int vertical_order,const int horizontal_order)440 void WienerFilterTest<bitdepth, Pixel>::SetInputData(
441     int type, Pixel value, const int vertical_order,
442     const int horizontal_order) {
443   const int mask = (1 << bitdepth) - 1;
444   libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
445   if (type == 0) {
446     for (auto& s : src_) s = value;
447   } else {
448     for (auto& s : src_) s = rnd.Rand16() & mask;
449   }
450   int order = vertical_order;
451   for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) {
452     auto& filter = restoration_info_.wiener_info.filter[i];
453     filter[3] = 128;
454     for (int j = 0; j < 3; ++j) {
455       filter[j] = kWienerTapsMin[j] +
456                   rnd.PseudoUniform(kWienerTapsMax[j] - kWienerTapsMin[j] + 1);
457     }
458     CleanFilterByOrder(order, filter);
459     filter[3] -= 2 * (filter[0] + filter[1] + filter[2]);
460     restoration_info_.wiener_info.number_leading_zero_coefficients[i] =
461         (kWienerFilterTaps - order) / 2;
462     order = horizontal_order;
463   }
464 }
465 
466 template <int bitdepth, typename Pixel>
TestFixedValues(int digest_id,Pixel value)467 void WienerFilterTest<bitdepth, Pixel>::TestFixedValues(int digest_id,
468                                                         Pixel value) {
469   static const char* const kDigest[3][4] = {
470       {"74fc90760a14b13340cb718f200ba350", "5bacaca0128cd36f4805330b3787771d",
471        "1109e17545cc4fbd5810b8b77e19fc36", "e7f914ec9d065aba92338016e17a526c"},
472       {"c8cc38790ceb0bea1eb989686755e1e5", "70f573b7e8875262c638a68d2f317916",
473        "193b19065899c835cb513149eb36d135", "f1dff65e3e53558b303ef0a2e3f3ba98"},
474       {"c8cc38790ceb0bea1eb989686755e1e5", "70f573b7e8875262c638a68d2f317916",
475        "961eeb92bd9d85eb47e3961ee93d279a", "039a279232bc90eebc0ec2fe3e18a7e1"},
476   };
477   if (target_wiener_filter_func_ == nullptr) return;
478   ASSERT_LT(value, 1 << bitdepth);
479   constexpr int bd_index = (bitdepth - 8) / 2;
480   const Pixel* const src = src_ + kOffset;
481   Pixel* const dst = dst_ + kOffset;
482   for (const auto vertical_order : kWienerOrders) {
483     for (const auto horizontal_order : kWienerOrders) {
484       SetInputData(0, value, vertical_order, horizontal_order);
485       memset(dst_, 0, sizeof(dst_));
486       const absl::Time start = absl::Now();
487       for (int y = 0; y < kHeight; y += unit_height_) {
488         const int height = std::min(unit_height_, kHeight - y);
489         for (int x = 0; x < kWidth; x += unit_width_) {
490           const int width = std::min(unit_width_, kWidth - x);
491           const Pixel* const source = src + y * kStride + x;
492           target_wiener_filter_func_(
493               restoration_info_, source, kStride,
494               source - kRestorationVerticalBorder * kStride, kStride,
495               source + height * kStride, kStride, width, height,
496               &restoration_buffer_, dst + y * kStride + x);
497         }
498       }
499       const absl::Duration elapsed_time = absl::Now() - start;
500       test_utils::CheckMd5Digest(
501           "kLoopRestorationTypeWiener", std::to_string(GetParam()).c_str(),
502           kDigest[bd_index][digest_id], dst_, sizeof(dst_), elapsed_time);
503     }
504   }
505 }
506 
507 template <int bitdepth, typename Pixel>
TestRandomValues(bool speed)508 void WienerFilterTest<bitdepth, Pixel>::TestRandomValues(bool speed) {
509   static const char* const kDigest[3][kNumWienerOrders][kNumWienerOrders] = {
510       {{"40d0cf56d2ffb4f581e68b0fc97f547f", "5c04745209b684ba98004ebb0f64e70b",
511         "545ed7d3f7e7ca3b86b4ada31f7aaee7", "0d6b2967f1bd1d99b720e563fe0cf03f"},
512        {"44b37076f0cf27f6eb506aca50c1d3e4", "e927d64dc9249e05a65e10ee75baa7d9",
513         "6136ecb4e29b17c9566504148943fd47", "c5ee2da81d44dc8cb2ac8021f724eb7a"},
514        {"125cbb227313ec91a2683f26e6f049d1", "77671b6529c806d23b749f304b548f59",
515         "28d53a1b486881895b8f73fa64486df1", "f5e32165bafe575d7ee7a6fbae75f36d"},
516        {"e832c41f2566ab542b32abba9d4f27bd", "ab1336ee6b85cba651f35ee5d3b3cc5c",
517         "52a673b6d14fbdca5ebdb1a34ee3326f",
518         "ebb42c7c9111f2e39f21e2158e801d9e"}},
519       {{"8cd9c6bd9983bd49564a58ed4af9098a", "f71f333c9d71237ed4e46f0ef2283196",
520         "375b43abc1d6682d62f91c1841b8b0fc", "71e2444822ae9c697ddfc96e07c6e8a1"},
521        {"d9ed3a66ceef405c08c87f6e91b71059", "c171fcff5fb7bb919f13ead7a4917a4c",
522         "8fbd1edb82fcd78d4d286886f65a700a", "fe14a143e6b261c5bb07b179d40be5a2"},
523        {"1c995f4e7f117857de73211b81093bd0", "5ab1ee3bb14adcd66d66802d58bee068",
524         "d77430783e173ebd1b30e5d9336c8b69", "e159a3620747458dff7ed3d20da1a4b7"},
525        {"5346fa07d195c257548a332753b057a3", "c77674bc0a638abc4d38d58e494fc7cf",
526         "7cbc1562a9dd08e1973b3b9ac1afc765",
527         "3c91bf1a34672cd40bf261c5820d3ec3"}},
528       {{"501b57370c781372b514accd03d161af", "a4569b5eff7f7e8b696934d192619be5",
529         "24eb2aa43118a8822f7a6a7384ab9ea7", "edd7ac227733b5a4496bfdbdf4eb34d7"},
530        {"77624cf73299a1bd928eae3eb8945dbe", "b3f311cacbf45fa892761462d31b2598",
531         "977c063d93a4b95cb365363763faa4da", "02313c9d360a1e0180ed05d3e4444c3d"},
532        {"f499655ecdcbe0ac48553f1eee758589", "a009c83c03e47cbd05c1243e28579bd9",
533         "d5f0b4fd761ff51efce949e6c5ec4833", "e3a9a57aacd2e6cfe0f792a885b3e0e3"},
534        {"b4cf906e9bb02ffca15c1e9575962ca2", "d0ca9f933978c0c31175ba1b28a44ae8",
535         "81ac1475530ffbd1c8d3ce7da87ffe6b",
536         "b96412949c2e31b29388222ac8914fa2"}},
537   };
538   if (target_wiener_filter_func_ == nullptr) return;
539   constexpr int bd_index = (bitdepth - 8) / 2;
540 #if LIBGAV1_ENABLE_NEON
541   const int num_tests = speed ? 5000 : 1;
542 #else
543   const int num_tests = speed ? 10000 : 1;
544 #endif
545   const Pixel* const src = src_ + kOffset;
546   Pixel* const dst = dst_ + kOffset;
547   for (const auto vertical_order : kWienerOrders) {
548     for (const auto horizontal_order : kWienerOrders) {
549       SetInputData(1, (1 << bitdepth) - 1, vertical_order, horizontal_order);
550       memset(dst_, 0, sizeof(dst_));
551       const absl::Time start = absl::Now();
552       for (int i = 0; i < num_tests; ++i) {
553         for (int y = 0; y < kHeight; y += unit_height_) {
554           const int height = std::min(unit_height_, kHeight - y);
555           for (int x = 0; x < kWidth; x += unit_width_) {
556             const int width = std::min(unit_width_, kWidth - x);
557             const Pixel* const source = src + y * kStride + x;
558             target_wiener_filter_func_(
559                 restoration_info_, source, kStride,
560                 source - kRestorationVerticalBorder * kStride, kStride,
561                 source + height * kStride, kStride, width, height,
562                 &restoration_buffer_, dst + y * kStride + x);
563           }
564         }
565       }
566       const absl::Duration elapsed_time = absl::Now() - start;
567       test_utils::CheckMd5Digest(
568           "kLoopRestorationTypeWiener", std::to_string(GetParam()).c_str(),
569           kDigest[bd_index][kWienerOrderIdLookup[vertical_order]]
570                  [kWienerOrderIdLookup[horizontal_order]],
571           dst_, sizeof(dst_), elapsed_time);
572     }
573   }
574 }
575 
576 template <int bitdepth, typename Pixel>
TestCompare2C()577 void WienerFilterTest<bitdepth, Pixel>::TestCompare2C() {
578   if (base_wiener_filter_func_ == nullptr) return;
579   if (target_wiener_filter_func_ == nullptr) return;
580   if (base_wiener_filter_func_ == target_wiener_filter_func_) return;
581   const Pixel* const src = src_ + kOffset;
582   Pixel* const dst = dst_ + kOffset;
583   Pixel* const tmp = tmp_ + kOffset;
584   for (const auto vertical_order : kWienerOrders) {
585     for (const auto horizontal_order : kWienerOrders) {
586       SetInputData(1, (1 << bitdepth) - 1, vertical_order, horizontal_order);
587       for (int x = 0; x < 2; ++x) {
588         // Prepare min/max filter coefficients.
589         int order = vertical_order;
590         for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) {
591           auto& filter = restoration_info_.wiener_info.filter[i];
592           for (int j = 0; j < 3; ++j) {
593             filter[j] = (x == 0) ? kWienerTapsMin[j] : kWienerTapsMax[j];
594           }
595           CleanFilterByOrder(order, filter);
596           filter[3] = 128 - 2 * (filter[0] + filter[1] + filter[2]);
597           restoration_info_.wiener_info.number_leading_zero_coefficients[i] =
598               (kWienerFilterTaps - order) / 2;
599           order = horizontal_order;
600         }
601         base_wiener_filter_func_(restoration_info_, src, kStride,
602                                  src - kRestorationVerticalBorder * kStride,
603                                  kStride, src + unit_height_ * kStride, kStride,
604                                  unit_width_, unit_height_,
605                                  &restoration_buffer_, dst);
606         target_wiener_filter_func_(restoration_info_, src, kStride,
607                                    src - kRestorationVerticalBorder * kStride,
608                                    kStride, src + unit_height_ * kStride,
609                                    kStride, unit_width_, unit_height_,
610                                    &restoration_buffer_, tmp);
611         if (!test_utils::CompareBlocks(dst, tmp, unit_width_, unit_height_,
612                                        kStride, kStride, false, true)) {
613           ADD_FAILURE() << "Mismatch -- wiener taps min/max";
614         }
615       }
616     }
617   }
618 }
619 
620 using WienerFilterTest8bpp = WienerFilterTest<8, uint8_t>;
621 
TEST_P(WienerFilterTest8bpp,Correctness)622 TEST_P(WienerFilterTest8bpp, Correctness) {
623   TestFixedValues(0, 0);
624   TestFixedValues(1, 1);
625   TestFixedValues(2, 128);
626   TestFixedValues(3, 255);
627   TestRandomValues(false);
628 }
629 
TEST_P(WienerFilterTest8bpp,DISABLED_Speed)630 TEST_P(WienerFilterTest8bpp, DISABLED_Speed) { TestRandomValues(true); }
631 
TEST_P(WienerFilterTest8bpp,TestCompare2C)632 TEST_P(WienerFilterTest8bpp, TestCompare2C) { TestCompare2C(); }
633 
634 INSTANTIATE_TEST_SUITE_P(C, WienerFilterTest8bpp,
635                          testing::ValuesIn(kUnitWidths));
636 #if LIBGAV1_ENABLE_AVX2
637 INSTANTIATE_TEST_SUITE_P(AVX2, WienerFilterTest8bpp,
638                          testing::ValuesIn(kUnitWidths));
639 #endif
640 #if LIBGAV1_ENABLE_SSE4_1
641 INSTANTIATE_TEST_SUITE_P(SSE41, WienerFilterTest8bpp,
642                          testing::ValuesIn(kUnitWidths));
643 #endif
644 #if LIBGAV1_ENABLE_NEON
645 INSTANTIATE_TEST_SUITE_P(NEON, WienerFilterTest8bpp,
646                          testing::ValuesIn(kUnitWidths));
647 #endif
648 
649 #if LIBGAV1_MAX_BITDEPTH >= 10
650 using WienerFilterTest10bpp = WienerFilterTest<10, uint16_t>;
651 
TEST_P(WienerFilterTest10bpp,Correctness)652 TEST_P(WienerFilterTest10bpp, Correctness) {
653   TestFixedValues(0, 0);
654   TestFixedValues(1, 1);
655   TestFixedValues(2, 512);
656   TestFixedValues(3, 1023);
657   TestRandomValues(false);
658 }
659 
TEST_P(WienerFilterTest10bpp,DISABLED_Speed)660 TEST_P(WienerFilterTest10bpp, DISABLED_Speed) { TestRandomValues(true); }
661 
TEST_P(WienerFilterTest10bpp,TestCompare2C)662 TEST_P(WienerFilterTest10bpp, TestCompare2C) { TestCompare2C(); }
663 
664 INSTANTIATE_TEST_SUITE_P(C, WienerFilterTest10bpp,
665                          testing::ValuesIn(kUnitWidths));
666 
667 #if LIBGAV1_ENABLE_AVX2
668 INSTANTIATE_TEST_SUITE_P(AVX2, WienerFilterTest10bpp,
669                          testing::ValuesIn(kUnitWidths));
670 #endif
671 #if LIBGAV1_ENABLE_SSE4_1
672 INSTANTIATE_TEST_SUITE_P(SSE41, WienerFilterTest10bpp,
673                          testing::ValuesIn(kUnitWidths));
674 #endif
675 #if LIBGAV1_ENABLE_NEON
676 INSTANTIATE_TEST_SUITE_P(NEON, WienerFilterTest10bpp,
677                          testing::ValuesIn(kUnitWidths));
678 #endif
679 #endif  // LIBGAV1_MAX_BITDEPTH >= 10
680 
681 #if LIBGAV1_MAX_BITDEPTH == 12
682 using WienerFilterTest12bpp = WienerFilterTest<12, uint16_t>;
683 
TEST_P(WienerFilterTest12bpp,Correctness)684 TEST_P(WienerFilterTest12bpp, Correctness) {
685   TestFixedValues(0, 0);
686   TestFixedValues(1, 1);
687   TestFixedValues(2, 2048);
688   TestFixedValues(3, 4095);
689   TestRandomValues(false);
690 }
691 
TEST_P(WienerFilterTest12bpp,DISABLED_Speed)692 TEST_P(WienerFilterTest12bpp, DISABLED_Speed) { TestRandomValues(true); }
693 
TEST_P(WienerFilterTest12bpp,TestCompare2C)694 TEST_P(WienerFilterTest12bpp, TestCompare2C) { TestCompare2C(); }
695 
696 INSTANTIATE_TEST_SUITE_P(C, WienerFilterTest12bpp,
697                          testing::ValuesIn(kUnitWidths));
698 #endif  // LIBGAV1_MAX_BITDEPTH == 12
699 
700 }  // namespace
701 }  // namespace dsp
702 }  // namespace libgav1
703