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/distance_weighted_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/dsp.h"
30 #include "src/utils/common.h"
31 #include "src/utils/constants.h"
32 #include "src/utils/cpu.h"
33 #include "src/utils/memory.h"
34 #include "tests/third_party/libvpx/acm_random.h"
35 #include "tests/utils.h"
36
37 namespace libgav1 {
38 namespace dsp {
39 namespace {
40
41 constexpr int kNumSpeedTests = 500000;
42
43 constexpr int kQuantizedDistanceLookup[4][2] = {
44 {9, 7}, {11, 5}, {12, 4}, {13, 3}};
45
46 template <int bitdepth, typename Pixel>
47 class DistanceWeightedBlendTest : public testing::TestWithParam<BlockSize>,
48 public test_utils::MaxAlignedAllocable {
49 public:
50 static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
51 DistanceWeightedBlendTest() = default;
52 ~DistanceWeightedBlendTest() override = default;
53
SetUp()54 void SetUp() override {
55 test_utils::ResetDspTable(bitdepth);
56 DistanceWeightedBlendInit_C();
57 const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
58 ASSERT_NE(dsp, nullptr);
59 base_func_ = dsp->distance_weighted_blend;
60 const testing::TestInfo* const test_info =
61 testing::UnitTest::GetInstance()->current_test_info();
62 const absl::string_view test_case = test_info->test_suite_name();
63 if (absl::StartsWith(test_case, "C/")) {
64 base_func_ = nullptr;
65 } else if (absl::StartsWith(test_case, "SSE41/")) {
66 if ((GetCpuInfo() & kSSE4_1) == 0) GTEST_SKIP() << "No SSE4.1 support!";
67 DistanceWeightedBlendInit_SSE4_1();
68 } else if (absl::StartsWith(test_case, "NEON/")) {
69 DistanceWeightedBlendInit_NEON();
70 } else {
71 FAIL() << "Unrecognized architecture prefix in test case name: "
72 << test_case;
73 }
74 func_ = dsp->distance_weighted_blend;
75 }
76
77 protected:
78 void Test(const char* digest, int num_tests);
79
80 private:
81 using PredType =
82 typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
83 static constexpr int kDestStride = kMaxSuperBlockSizeInPixels;
84 const int width_ = kBlockWidthPixels[GetParam()];
85 const int height_ = kBlockHeightPixels[GetParam()];
86 alignas(kMaxAlignment) PredType
87 source1_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
88 alignas(kMaxAlignment) PredType
89 source2_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
90 Pixel dest_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] = {};
91 Pixel reference_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] =
92 {};
93 dsp::DistanceWeightedBlendFunc base_func_;
94 dsp::DistanceWeightedBlendFunc func_;
95 };
96
97 template <int bitdepth, typename Pixel>
Test(const char * digest,int num_tests)98 void DistanceWeightedBlendTest<bitdepth, Pixel>::Test(const char* digest,
99 int num_tests) {
100 if (func_ == nullptr) return;
101 libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
102 PredType* src_1 = source1_;
103 PredType* src_2 = source2_;
104
105 const int index = rnd.Rand8() & 3;
106 const uint8_t weight_0 = kQuantizedDistanceLookup[index][0];
107 const uint8_t weight_1 = kQuantizedDistanceLookup[index][1];
108 // In libgav1, predictors have an offset which are later subtracted and
109 // clipped in distance weighted blending. Therefore we add the offset
110 // here to match libaom's implementation.
111 for (int y = 0; y < height_; ++y) {
112 for (int x = 0; x < width_; ++x) {
113 // distance_weighted_blend is applied to compound prediction values. This
114 // implies a range far exceeding that of pixel values.
115 // The ranges include kCompoundOffset in 10bpp and 12bpp.
116 // see: src/dsp/convolve.cc & src/dsp/warp.cc.
117 static constexpr int kCompoundPredictionRange[3][2] = {
118 // 8bpp
119 {-5132, 9212},
120 // 10bpp
121 {3988, 61532},
122 // 12bpp
123 {3974, 61559},
124 };
125 constexpr int bitdepth_index = (bitdepth - 8) >> 1;
126 const int min_val = kCompoundPredictionRange[bitdepth_index][0];
127 const int max_val = kCompoundPredictionRange[bitdepth_index][1];
128 src_1[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
129 src_2[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
130 }
131 src_1 += width_;
132 src_2 += width_;
133 }
134 absl::Duration elapsed_time;
135 for (int i = 0; i < num_tests; ++i) {
136 const absl::Time start = absl::Now();
137 func_(source1_, source2_, weight_0, weight_1, width_, height_, dest_,
138 sizeof(Pixel) * kDestStride);
139 elapsed_time += absl::Now() - start;
140 }
141
142 test_utils::CheckMd5Digest("DistanceWeightedBlend", ToString(GetParam()),
143 digest, dest_, sizeof(dest_), elapsed_time);
144 }
145
146 const BlockSize kTestParam[] = {
147 kBlock4x4, kBlock4x8, kBlock4x16, kBlock8x4, kBlock8x8,
148 kBlock8x16, kBlock8x32, kBlock16x4, kBlock16x8, kBlock16x16,
149 kBlock16x32, kBlock16x64, kBlock32x8, kBlock32x16, kBlock32x32,
150 kBlock32x64, kBlock64x16, kBlock64x32, kBlock64x64, kBlock64x128,
151 kBlock128x64, kBlock128x128,
152 };
153
GetDistanceWeightedBlendDigest8bpp(const BlockSize block_size)154 const char* GetDistanceWeightedBlendDigest8bpp(const BlockSize block_size) {
155 static const char* const kDigests[kMaxBlockSizes] = {
156 // 4xN
157 "ebf389f724f8ab46a2cac895e4e073ca",
158 "09acd567b6b12c8cf8eb51d8b86eb4bf",
159 "57bb4d65695d8ec6752f2bd8686b64fd",
160 // 8xN
161 "270905ac76f9a2cba8a552eb0bf7c8c1",
162 "f0801c8574d2c271ef2bbea77a1d7352",
163 "e761b580e3312be33a227492a233ce72",
164 "ff214dab1a7e98e2285961d6421720c6",
165 // 16xN
166 "4f712609a36e817f9752326d58562ff8",
167 "14243f5c5f7c7104160c1f2cef0a0fbc",
168 "3ac3f3161b7c8dd8436b02abfdde104a",
169 "81a00b704e0e41a5dbe6436ac70c098d",
170 "af8fd02017c7acdff788be742d700baa",
171 // 32xN
172 "ee34332c66a6d6ed8ce64031aafe776c",
173 "b5e3d22bd2dbdb624c8b86a1afb5ce6d",
174 "607ffc22098d81b7e37a7bf62f4af5d3",
175 "3823dbf043b4682f56d5ca698e755ea5",
176 // 64xN
177 "4acf556b921956c2bc24659cd5128401",
178 "a298c544c9c3b27924b4c23cc687ea5a",
179 "539e2df267782ce61c70103b23b7d922",
180 "3b0cb2a0b5d384efee4d81401025bec1",
181 // 128xN
182 "8b56b636dd712c2f8d138badb7219991",
183 "8cfc8836908902b8f915639b7bff45b3",
184 };
185 assert(block_size < kMaxBlockSizes);
186 return kDigests[block_size];
187 }
188
189 using DistanceWeightedBlendTest8bpp = DistanceWeightedBlendTest<8, uint8_t>;
190
TEST_P(DistanceWeightedBlendTest8bpp,Blending)191 TEST_P(DistanceWeightedBlendTest8bpp, Blending) {
192 Test(GetDistanceWeightedBlendDigest8bpp(GetParam()), 1);
193 }
194
TEST_P(DistanceWeightedBlendTest8bpp,DISABLED_Speed)195 TEST_P(DistanceWeightedBlendTest8bpp, DISABLED_Speed) {
196 Test(GetDistanceWeightedBlendDigest8bpp(GetParam()), kNumSpeedTests);
197 }
198
199 INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest8bpp,
200 testing::ValuesIn(kTestParam));
201
202 #if LIBGAV1_ENABLE_NEON
203 INSTANTIATE_TEST_SUITE_P(NEON, DistanceWeightedBlendTest8bpp,
204 testing::ValuesIn(kTestParam));
205 #endif
206
207 #if LIBGAV1_ENABLE_SSE4_1
208 INSTANTIATE_TEST_SUITE_P(SSE41, DistanceWeightedBlendTest8bpp,
209 testing::ValuesIn(kTestParam));
210 #endif
211
212 #if LIBGAV1_MAX_BITDEPTH >= 10
GetDistanceWeightedBlendDigest10bpp(const BlockSize block_size)213 const char* GetDistanceWeightedBlendDigest10bpp(const BlockSize block_size) {
214 static const char* const kDigests[] = {
215 // 4xN
216 "55f594b56e16d5c401274affebbcc3d3",
217 "69df14da4bb33a8f7d7087921008e919",
218 "1b61f33604c54015794198a13bfebf46",
219 // 8xN
220 "825a938185b152f7cf09bf1c0723ce2b",
221 "85ea315c51d979bc9b45834d6b40ec6f",
222 "92ebde208e8c39f7ec6de2de82182dbb",
223 "520f84716db5b43684dbb703806383fe",
224 // 16xN
225 "12ca23e3e2930005a0511646e8c83da4",
226 "6208694a6744f4a3906f58c1add670e3",
227 "a33d63889df989a3bbf84ff236614267",
228 "34830846ecb0572a98bbd192fed02b16",
229 "34bb2f79c0bd7f9a80691b8af597f2a8",
230 // 32xN
231 "fa97f2d0e3143f1f44d3ac018b0d696d",
232 "3df4a22456c9ab6ed346ab1b9750ae7d",
233 "6276a058b35c6131bc0c94a4b4a37ebc",
234 "9ca42da5d2d5eb339df03ae2c7a26914",
235 // 64xN
236 "800e692c520f99223bc24c1ac95a0166",
237 "818b6d20426585ef7fe844015a03aaf5",
238 "fb48691ccfff083e01d74826e88e613f",
239 "0bd350bc5bc604a224d77a5f5a422698",
240 // 128xN
241 "a130840813cd6bd69d09bcf5f8d0180f",
242 "6ece1846bea55e8f8f2ed7fbf73718de",
243 };
244 assert(block_size < kMaxBlockSizes);
245 return kDigests[block_size];
246 }
247
248 using DistanceWeightedBlendTest10bpp = DistanceWeightedBlendTest<10, uint16_t>;
249
TEST_P(DistanceWeightedBlendTest10bpp,Blending)250 TEST_P(DistanceWeightedBlendTest10bpp, Blending) {
251 Test(GetDistanceWeightedBlendDigest10bpp(GetParam()), 1);
252 }
253
TEST_P(DistanceWeightedBlendTest10bpp,DISABLED_Speed)254 TEST_P(DistanceWeightedBlendTest10bpp, DISABLED_Speed) {
255 Test(GetDistanceWeightedBlendDigest10bpp(GetParam()), kNumSpeedTests);
256 }
257
258 INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest10bpp,
259 testing::ValuesIn(kTestParam));
260
261 #if LIBGAV1_ENABLE_SSE4_1
262 INSTANTIATE_TEST_SUITE_P(SSE41, DistanceWeightedBlendTest10bpp,
263 testing::ValuesIn(kTestParam));
264 #endif
265 #if LIBGAV1_ENABLE_NEON
266 INSTANTIATE_TEST_SUITE_P(NEON, DistanceWeightedBlendTest10bpp,
267 testing::ValuesIn(kTestParam));
268 #endif
269 #endif // LIBGAV1_MAX_BITDEPTH >= 10
270
271 #if LIBGAV1_MAX_BITDEPTH == 12
GetDistanceWeightedBlendDigest12bpp(const BlockSize block_size)272 const char* GetDistanceWeightedBlendDigest12bpp(const BlockSize block_size) {
273 static const char* const kDigests[] = {
274 // 4xN
275 "e30bf8f5f294206ad1dd79bd10a20827",
276 "f0cfb60134562d9c5f2ec6ad106e01ef",
277 "ad0876244e1b769203266a9c75b74afc",
278 // 8xN
279 "5265b954479c15a80f427561c5f36ff4",
280 "7f157457d1671e4ecce7a0884e9e3f76",
281 "d2cef5cf217f2d1f787c8951b7fe7cb2",
282 "6d23059008adbbb84ac941c8b4968f5b",
283 // 16xN
284 "ae521a5656ed3440d1fa950c20d90a79",
285 "935bec0e12b5dd3e0c34b3de8ba51476",
286 "0334bafcdcd7ddddb673ded492bca25a",
287 "c5360f08d0be77c79dc19fb55a0c5fe0",
288 "c2d1e7a4244a8aaaac041aed0cefc148",
289 // 32xN
290 "ce7f3cf78ae4f836cf69763137f7f6a6",
291 "800e52ebb14d5831c047d391cd760f95",
292 "74aa2b412b42165f1967daf3042b4f17",
293 "140d4cc600944b629b1991e88a9fe97c",
294 // 64xN
295 "3d206f93229ee2cea5c5da4e0ac6445a",
296 "3d13028f8fffe79fd35752c0177291ca",
297 "e7a7669acb5979dc7b15a19eed09cd4c",
298 "599368f4971c203fc5fa32989fe8cb44",
299 // 128xN
300 "54b46af2e2c8d2081e26fa0315b4ffd7",
301 "602e769bb2104e78223e68e50e7e86a0",
302 };
303 assert(block_size < kMaxBlockSizes);
304 return kDigests[block_size];
305 }
306
307 using DistanceWeightedBlendTest12bpp = DistanceWeightedBlendTest<12, uint16_t>;
308
TEST_P(DistanceWeightedBlendTest12bpp,Blending)309 TEST_P(DistanceWeightedBlendTest12bpp, Blending) {
310 Test(GetDistanceWeightedBlendDigest12bpp(GetParam()), 1);
311 }
312
TEST_P(DistanceWeightedBlendTest12bpp,DISABLED_Speed)313 TEST_P(DistanceWeightedBlendTest12bpp, DISABLED_Speed) {
314 Test(GetDistanceWeightedBlendDigest12bpp(GetParam()), kNumSpeedTests);
315 }
316
317 INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest12bpp,
318 testing::ValuesIn(kTestParam));
319 #endif // LIBGAV1_MAX_BITDEPTH == 12
320
321 } // namespace
322 } // namespace dsp
323
operator <<(std::ostream & os,const BlockSize param)324 static std::ostream& operator<<(std::ostream& os, const BlockSize param) {
325 return os << ToString(param);
326 }
327
328 } // namespace libgav1
329