1 // Copyright 2020 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/average_blend.h"
16
17 #include <cassert>
18 #include <cstdint>
19 #include <ostream>
20 #include <string>
21 #include <type_traits>
22
23 #include "absl/strings/match.h"
24 #include "absl/strings/string_view.h"
25 #include "absl/time/clock.h"
26 #include "absl/time/time.h"
27 #include "gtest/gtest.h"
28 #include "src/dsp/constants.h"
29 #include "src/dsp/distance_weighted_blend.h"
30 #include "src/dsp/dsp.h"
31 #include "src/utils/common.h"
32 #include "src/utils/constants.h"
33 #include "src/utils/cpu.h"
34 #include "src/utils/memory.h"
35 #include "tests/block_utils.h"
36 #include "tests/third_party/libvpx/acm_random.h"
37 #include "tests/utils.h"
38
39 namespace libgav1 {
40 namespace dsp {
41 namespace {
42
43 constexpr int kNumSpeedTests = 5e8;
44 constexpr char kAverageBlend[] = "AverageBlend";
45 // average_blend is applied to compound prediction values. This implies a range
46 // far exceeding that of pixel values.
47 // The ranges include kCompoundOffset in 10bpp and 12bpp.
48 // see: src/dsp/convolve.cc & src/dsp/warp.cc.
49 constexpr int kCompoundPredictionRange[3][2] = {
50 // 8bpp
51 {-5132, 9212},
52 // 10bpp
53 {3988, 61532},
54 // 12bpp
55 {3974, 61559},
56 };
57
58 template <int bitdepth, typename Pixel>
59 class AverageBlendTest : public testing::TestWithParam<BlockSize>,
60 public test_utils::MaxAlignedAllocable {
61 public:
62 static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
63 AverageBlendTest() = default;
64 ~AverageBlendTest() override = default;
65
SetUp()66 void SetUp() override {
67 test_utils::ResetDspTable(bitdepth);
68 AverageBlendInit_C();
69 DistanceWeightedBlendInit_C();
70 const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
71 ASSERT_NE(dsp, nullptr);
72 base_func_ = dsp->average_blend;
73 const testing::TestInfo* const test_info =
74 testing::UnitTest::GetInstance()->current_test_info();
75 const absl::string_view test_case = test_info->test_suite_name();
76 if (absl::StartsWith(test_case, "C/")) {
77 base_func_ = nullptr;
78 } else if (absl::StartsWith(test_case, "SSE41/")) {
79 if ((GetCpuInfo() & kSSE4_1) == 0) GTEST_SKIP() << "No SSE4.1 support!";
80 AverageBlendInit_SSE4_1();
81 } else if (absl::StartsWith(test_case, "NEON/")) {
82 AverageBlendInit_NEON();
83 } else {
84 FAIL() << "Unrecognized architecture prefix in test case name: "
85 << test_case;
86 }
87 func_ = dsp->average_blend;
88 dist_blend_func_ = dsp->distance_weighted_blend;
89 }
90
91 protected:
92 void Test(const char* digest, int num_tests, bool debug);
93
94 private:
95 using PredType =
96 typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
97 static constexpr int kDestStride = kMaxSuperBlockSizeInPixels;
98 const int width_ = kBlockWidthPixels[GetParam()];
99 const int height_ = kBlockHeightPixels[GetParam()];
100 alignas(kMaxAlignment) PredType
101 source1_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
102 alignas(kMaxAlignment) PredType
103 source2_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
104 Pixel dest_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] = {};
105 Pixel reference_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] =
106 {};
107 dsp::AverageBlendFunc base_func_;
108 dsp::AverageBlendFunc func_;
109 dsp::DistanceWeightedBlendFunc dist_blend_func_;
110 };
111
112 template <int bitdepth, typename Pixel>
Test(const char * digest,int num_tests,bool debug)113 void AverageBlendTest<bitdepth, Pixel>::Test(const char* digest, int num_tests,
114 bool debug) {
115 if (func_ == nullptr) return;
116 libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
117 PredType* src_1 = source1_;
118 PredType* src_2 = source2_;
119 for (int y = 0; y < height_; ++y) {
120 for (int x = 0; x < width_; ++x) {
121 constexpr int bitdepth_index = (bitdepth - 8) >> 1;
122 const int min_val = kCompoundPredictionRange[bitdepth_index][0];
123 const int max_val = kCompoundPredictionRange[bitdepth_index][1];
124 src_1[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
125 src_2[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
126 }
127 src_1 += width_;
128 src_2 += width_;
129 }
130 absl::Duration elapsed_time;
131 for (int i = 0; i < num_tests; ++i) {
132 const absl::Time start = absl::Now();
133 func_(source1_, source2_, width_, height_, dest_,
134 sizeof(dest_[0]) * kDestStride);
135 elapsed_time += absl::Now() - start;
136 }
137 if (debug) {
138 if (base_func_ != nullptr) {
139 base_func_(source1_, source2_, width_, height_, reference_,
140 sizeof(reference_[0]) * kDestStride);
141 } else {
142 // Use dist_blend_func_ as the base for C tests.
143 const int8_t weight = 8;
144 dist_blend_func_(source1_, source2_, weight, weight, width_, height_,
145 reference_, sizeof(reference_[0]) * kDestStride);
146 }
147 EXPECT_TRUE(test_utils::CompareBlocks(dest_, reference_, width_, height_,
148 kDestStride, kDestStride, false));
149 }
150
151 test_utils::CheckMd5Digest(kAverageBlend, ToString(GetParam()), digest, dest_,
152 sizeof(dest_[0]) * kDestStride * height_,
153 elapsed_time);
154 }
155
156 const BlockSize kTestParam[] = {
157 kBlock4x4, kBlock4x8, kBlock4x16, kBlock8x4, kBlock8x8,
158 kBlock8x16, kBlock8x32, kBlock16x4, kBlock16x8, kBlock16x16,
159 kBlock16x32, kBlock16x64, kBlock32x8, kBlock32x16, kBlock32x32,
160 kBlock32x64, kBlock64x16, kBlock64x32, kBlock64x64, kBlock64x128,
161 kBlock128x64, kBlock128x128,
162 };
163
164 using AverageBlendTest8bpp = AverageBlendTest<8, uint8_t>;
165
GetAverageBlendDigest8bpp(const BlockSize block_size)166 const char* GetAverageBlendDigest8bpp(const BlockSize block_size) {
167 static const char* const kDigests[kMaxBlockSizes] = {
168 // 4xN
169 "152bcc35946900b1ed16369b3e7a81b7",
170 "c23e9b5698f7384eaae30a3908118b77",
171 "f2da31d940f62490c368c03d32d3ede8",
172 // 8xN
173 "73c95485ef956e1d9ab914e88e6a202b",
174 "d90d3abd368e58c513070a88b34649ba",
175 "77f7d53d0edeffb3537afffd9ff33a4a",
176 "460b9b1e6b83f65f013cfcaf67ec0122",
177 // 16xN
178 "96454a56de940174ff92e9bb686d6d38",
179 "a50e268e93b48ae39cc2a47d377410e2",
180 "65c8502ff6d78065d466f9911ed6bb3e",
181 "bc2c873b9f5d74b396e1df705e87f699",
182 "b4dae656484b2d255d1e09b7f34e12c1",
183 // 32xN
184 "7e1e5db92b22a96e5226a23de883d766",
185 "ca40d46d89773e7f858b15fcecd43cc0",
186 "bfdc894707323f4dc43d1326309f8368",
187 "f4733417621719b7feba3166ec0da5b9",
188 // 64xN
189 "378fa0594d22f01c8e8931c2a908d7c4",
190 "db38fe2e082bd4a09acb3bb1d52ee11e",
191 "3ad44401cc731215c46c9b7d96f7e4ae",
192 "6c43267be5ed03d204a05fe36090f870",
193 // 128xN
194 "c8cfe46ebf166c1cbf08e8804206aadb",
195 "b0557b5156d2334c8ce4a7ee12f9d6b4",
196 };
197 assert(block_size < kMaxBlockSizes);
198 return kDigests[block_size];
199 }
200
TEST_P(AverageBlendTest8bpp,Blending)201 TEST_P(AverageBlendTest8bpp, Blending) {
202 Test(GetAverageBlendDigest8bpp(GetParam()), 1, false);
203 }
204
TEST_P(AverageBlendTest8bpp,DISABLED_Speed)205 TEST_P(AverageBlendTest8bpp, DISABLED_Speed) {
206 Test(GetAverageBlendDigest8bpp(GetParam()),
207 kNumSpeedTests /
208 (kBlockHeightPixels[GetParam()] * kBlockWidthPixels[GetParam()]),
209 false);
210 }
211
212 INSTANTIATE_TEST_SUITE_P(C, AverageBlendTest8bpp,
213 testing::ValuesIn(kTestParam));
214 #if LIBGAV1_ENABLE_SSE4_1
215 INSTANTIATE_TEST_SUITE_P(SSE41, AverageBlendTest8bpp,
216 testing::ValuesIn(kTestParam));
217 #endif
218 #if LIBGAV1_ENABLE_NEON
219 INSTANTIATE_TEST_SUITE_P(NEON, AverageBlendTest8bpp,
220 testing::ValuesIn(kTestParam));
221 #endif
222
223 #if LIBGAV1_MAX_BITDEPTH >= 10
224 using AverageBlendTest10bpp = AverageBlendTest<10, uint16_t>;
225
GetAverageBlendDigest10bpp(const BlockSize block_size)226 const char* GetAverageBlendDigest10bpp(const BlockSize block_size) {
227 static const char* const kDigests[kMaxBlockSizes] = {
228 // 4xN
229 "98c0671c092b4288adcaaa17362cc4a3",
230 "7083f3def8bfb63ab3a985ef5616a923",
231 "a7211ee2eaa6f88e08875b377d17b0f1",
232 // 8xN
233 "11f9ab881700f2ef0f82d8d4662868c6",
234 "3bee144b9ea6f4288b860c24f88a22f3",
235 "27113bd17bf95034f100e9046c7b59d2",
236 "c42886a5e16e23a81e43833d34467558",
237 // 16xN
238 "b0ac2eb0a7a6596d6d1339074c7f8771",
239 "24c9e079b9a8647a6ee03f5441f2cdd9",
240 "dd05777751ccdb4356856c90e1176e53",
241 "27b1d69d035b1525c013b7373cfe3875",
242 "08c46403afe19e6b008ccc8f56633da9",
243 // 32xN
244 "36d434db11298aba76166df06e9b8125",
245 "efd24dd7b555786bff1a482e51170ea3",
246 "3b37ddac87de443cd18784f02c2d1dd5",
247 "80d8070939a743a20689a65bf5dc0a68",
248 // 64xN
249 "88e747246237c6408d0bd4cc3ecc8396",
250 "af1fe8c52487c9f2951c3ea516828abb",
251 "ea6f18ff56b053748c18032b7e048e83",
252 "af0cb87fe27d24c2e0afd2c90a8533a6",
253 // 128xN
254 "16a83b19911d6dc7278a694b8baa9901",
255 "bd22e77ce6fa727267ff63eeb4dcb19c",
256 };
257 assert(block_size < kMaxBlockSizes);
258 return kDigests[block_size];
259 }
260
TEST_P(AverageBlendTest10bpp,Blending)261 TEST_P(AverageBlendTest10bpp, Blending) {
262 Test(GetAverageBlendDigest10bpp(GetParam()), 1, false);
263 }
264
TEST_P(AverageBlendTest10bpp,DISABLED_Speed)265 TEST_P(AverageBlendTest10bpp, DISABLED_Speed) {
266 Test(GetAverageBlendDigest10bpp(GetParam()),
267 kNumSpeedTests /
268 (kBlockHeightPixels[GetParam()] * kBlockHeightPixels[GetParam()]) /
269 2,
270 false);
271 }
272
273 INSTANTIATE_TEST_SUITE_P(C, AverageBlendTest10bpp,
274 testing::ValuesIn(kTestParam));
275 #if LIBGAV1_ENABLE_SSE4_1
276 INSTANTIATE_TEST_SUITE_P(SSE41, AverageBlendTest10bpp,
277 testing::ValuesIn(kTestParam));
278 #endif
279 #if LIBGAV1_ENABLE_NEON
280 INSTANTIATE_TEST_SUITE_P(NEON, AverageBlendTest10bpp,
281 testing::ValuesIn(kTestParam));
282 #endif
283 #endif // LIBGAV1_MAX_BITDEPTH >= 10
284
285 #if LIBGAV1_MAX_BITDEPTH == 12
286 using AverageBlendTest12bpp = AverageBlendTest<12, uint16_t>;
287
GetAverageBlendDigest12bpp(const BlockSize block_size)288 const char* GetAverageBlendDigest12bpp(const BlockSize block_size) {
289 static const char* const kDigests[kMaxBlockSizes] = {
290 // 4xN
291 "8f5ad8fba61a0f1cb6b77f5460c241be",
292 "3a9d017848fdb4162315c689b4449ac6",
293 "bb97029fff021b168b98b209dcee5123",
294 // 8xN
295 "a7ff1b199965b8856499ae3f1b2c48eb",
296 "05220c72835fc4662d261183df0a57cf",
297 "97de8c325f1475c44e1afc44183e55ad",
298 "60d820c46cad14d9d934da238bb79707",
299 // 16xN
300 "f3e4863121819bc28f7c1f453898650c",
301 "5f5f68d21269d7df546c848921e8f2cd",
302 "17efe0b0fce1f8d4c7bc6eacf769063e",
303 "3da591e201f44511cdd6c465692ace1e",
304 "5a0ca6c88664d2e918a032b5fcf66070",
305 // 32xN
306 "efe236bee8a9fef90b99d8012006f985",
307 "d6ff3aacbbbadff6d0ccb0873fb9fa2a",
308 "38801f7361052873423d57b574aabddc",
309 "55c76772ecdc1721e92ca04d2fc7c089",
310 // 64xN
311 "4261ecdde34eedc4e5066a93e0f64881",
312 "fe82e012efab872672193316d670fd82",
313 "6c698bc2d4acf4444a64ac55ae9641de",
314 "98626e25101cff69019d1b7e6e439404",
315 // 128xN
316 "fe0f3c89dd39786df1c952a2470d680d",
317 "af7e166fc3d8c9ce85789acf3467ed9d",
318 };
319 assert(block_size < kMaxBlockSizes);
320 return kDigests[block_size];
321 }
322
TEST_P(AverageBlendTest12bpp,Blending)323 TEST_P(AverageBlendTest12bpp, Blending) {
324 Test(GetAverageBlendDigest12bpp(GetParam()), 1, false);
325 }
326
TEST_P(AverageBlendTest12bpp,DISABLED_Speed)327 TEST_P(AverageBlendTest12bpp, DISABLED_Speed) {
328 Test(GetAverageBlendDigest12bpp(GetParam()),
329 kNumSpeedTests /
330 (kBlockHeightPixels[GetParam()] * kBlockHeightPixels[GetParam()]) /
331 2,
332 false);
333 }
334
335 INSTANTIATE_TEST_SUITE_P(C, AverageBlendTest12bpp,
336 testing::ValuesIn(kTestParam));
337 #endif // LIBGAV1_MAX_BITDEPTH == 12
338
339 } // namespace
340 } // namespace dsp
341
operator <<(std::ostream & os,const BlockSize param)342 static std::ostream& operator<<(std::ostream& os, const BlockSize param) {
343 return os << ToString(param);
344 }
345
346 } // namespace libgav1
347