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/obmc.h"
16
17 #include <algorithm>
18 #include <cassert>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 #include <ostream>
23 #include <string>
24
25 #include "absl/strings/match.h"
26 #include "absl/strings/str_format.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/time/clock.h"
29 #include "absl/time/time.h"
30 #include "gtest/gtest.h"
31 #include "src/dsp/dsp.h"
32 #include "src/utils/common.h"
33 #include "src/utils/constants.h"
34 #include "src/utils/cpu.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 #include "src/dsp/obmc.inc"
44
45 constexpr int kMaxBlendingBlockSize = 64;
46 constexpr int kNumSpeedTests = 2e8;
47
GetDigest8bpp(int id)48 const char* GetDigest8bpp(int id) {
49 static const char* const kDigest[] = {
50 "c8659acd1e8ecdab06be73f0954fa1ae", "e785f31f2723a193fefd534bd6f6c18f",
51 "751fcd8a345fef1c38a25293c9b528c0", "69af412dfa5e96ad43b79c178cb1c58b",
52 "2766a64622e183bb4614f2018f14fa85", "8d98589a5cef6e68ee8fadf19d420e3c",
53 "19eccf31dd8cf1abcee9414128fe4141", "35019f98e30bcbc6ab624682a0628519",
54 "199c551164e73c100045d7ab033ffdcc", "ad5a5eb2906265690c22741b0715f37b",
55 "e2152dea159249149ff4151111b73ed6", "1edd570bec7e63780d83588f6aacda25",
56 "b24ad192e151b1e0f74d1493004cb1b6", "6c1ce7ed3463cc60870e336f990d4f14",
57 "2e6b7a06da21512dfdd9a517d2988655", "971ba1c41ab13bb341c04f936760f546",
58 "55b803239d9f12888c666c5320450937", "3d0838963f8c95dafbfb8e5e25c865d2",
59 "98a9be6245720d4e0da18115c1a1dbd7", "7e7afe3136ad681b5ea05664fe916548",
60 "33971753243f09106173199b7bae1ef5", "65413f33c19a42c112d395121aa4b3b4",
61 };
62 assert(id >= 0);
63 assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
64 return kDigest[id];
65 }
66
GetDigestSpeed8bpp(int id)67 const char* GetDigestSpeed8bpp(int id) {
68 static const char* const kDigest[] = {
69 "5ea519b616cd2998fbb9b25b4c2660cb", "f23d18197a96de48901738d130a147d9",
70 "07b4140c693947a63865f835089766c4", "62547d29bc4dfb2e201e9d907c09e345",
71 "c3988da521be50aeb9944564001b282b", "d5a8ff9ca1bd49f4260bb497c489b06c",
72 "b3e94f1e33c316759ebf47620327168c", "c5e64a34ca7e55f4daed19cbe4c27049",
73 "3b234eb729e8e79db8692c4cbe1b6667", "f9f3060a44c3a575470f9700b3c3a75b",
74 "e3a1960b0a7238db1184a3f9d8e9a4b2", "ba9938553703d520bc0ade427c397140",
75 "31bf64a6ed1e8002d488c0b9dcffb80a", "9ab1f3ae2e7f70cd27452f30cecfd18e",
76 "eaf25ac79ad70fc17ca96d8fcdf0f939", "9aaa88cb5e6b8757e37c3430bd664e70",
77 "8293874b2794df8fd22f5a35c3de7bee", "e9d6ee9106227c2c67ea9e6a4652e4ad",
78 "29f8a6fc2a650f3945a4ea6d3b975b6d", "8f300a257e913a42666b4921b2b0b5c5",
79 "a526265c4b3c8593736a82ddc1fd1603", "76e248f6756ac96343204b0e48d72a9e",
80 };
81 assert(id >= 0);
82 assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
83 return kDigest[id];
84 }
85
86 #if LIBGAV1_MAX_BITDEPTH >= 10
GetDigest10bpp(int id)87 const char* GetDigest10bpp(int id) {
88 static const char* const kDigest[] = {
89 "6f922e4142b644ca3f1eb0f363a1c34e", "84e7c098a9335b36082fec0bc7203075",
90 "40f00ea6884fea23a3b7fae59e3b02c3", "70cb92d08b4fdb6dd9c7d418cb1455d3",
91 "ed550798b56e70439a93cb48c359e873", "55e0d927b984e78cd51a1961e58a431d",
92 "482a6856b87265a82e4ea3fdadb2d95b", "0be46226ff87d74ff2ce68a83eaf9cca",
93 "bb4461f0131a1693a0a76f21d92a480b", "ea24f78d74c7864fb247c9a98c9b97b6",
94 "d2e70b81882aeb3d9fccef89e7552a9d", "f5d882ee6d9ae6f7dfa467ca99301424",
95 "824ddb98eb4129b3d254c0bc7a64cd73", "5eaaafa8ef9b7ba5e2856a947e5b33df",
96 "071de1494e0f1b2f99266b90bdc43ddd", "c33227a96dad506adc32dacfb371ab78",
97 "e8a632f9fff240c439d4ae6e86795046", "26b90d74f18f9df4427b6180d48db1fc",
98 "e4a01e492ddc0398b5c5b60c81468242", "f1b4f7ab5c8b949e51db104f2e33565a",
99 "b1fb9ecc6a552e2b23ee92e2f3e4122a", "a683d20129a91bb20b904aa20c0499b1",
100 };
101 assert(id >= 0);
102 assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
103 return kDigest[id];
104 }
105
GetDigestSpeed10bpp(int id)106 const char* GetDigestSpeed10bpp(int id) {
107 static const char* const kDigest[] = {
108 "80557576299708005111029cef04da53", "24f84f07f53f61cd46bdcfe1e05ff9b5",
109 "4dd6bc62145baa5357a4cbf6d7a6ef15", "0b7aa27cee43b8ae0c02d07887eaa225",
110 "9e28cdae73ca97433499c31ca79e1d07", "1cacd6466a143f88e736fffaf21e2246",
111 "9c7699626660d8965e06a54282a408f3", "eef893efef62b2eb4aaad06fc462819c",
112 "4965d0a3ff750813df85c0082b21bd4b", "ec10fd79fbf552abc595def392e9a863",
113 "a148bbafdc4466fbb700b31acccca8ac", "5da9d960988549f53b817003b93e4d01",
114 "b4c4f88d1fb54869ce7ff452ca7786a6", "d607f785fce62bad85102054539e7089",
115 "b441761ea2817e4618c594aaa11d670a", "1cc5e08e6d5f9315dbc0369b97af941d",
116 "568cc1a3a67ba4e6e77f54602d0ed3e3", "522f14c068f788bc284a7d1e47d623ed",
117 "b543855cbe384b88861c881853c28192", "5faaafc124e94eedc69dc0f5d33dacac",
118 "13ca4d01bd20085459e6126555e1f7b5", "46d46fae3c8a7d9e4725154d8d2b76d8",
119 };
120 assert(id >= 0);
121 assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
122 return kDigest[id];
123 }
124 #endif // LIBGAV1_MAX_BITDEPTH >= 10
125
126 #if LIBGAV1_MAX_BITDEPTH == 12
GetDigest12bpp(int id)127 const char* GetDigest12bpp(int id) {
128 static const char* const kDigest[] = {
129 "eb18c776d7b56280f01cca40b04a9c44", "058d4a6ed025eac5dcf7aec3203c0882",
130 "8355884d7470e9c6af9309ab23bee859", "2ba330551ac58d1d034b947d7ab9b59f",
131 "0d25cd773c81e4c57f82513e3b031f01", "b9075f7c3b9a240dbb015a24454eeb71",
132 "563ed8683723d1e4f2746280bca3db0a", "d7125306bd8c952d0f85fe1515ca16a7",
133 "5bf99c7e4a918c9b6a7e251484ea6527", "38ac9c685e8d2bd2771b6f2b38268301",
134 "abc39dbde7470e08b15417ee97c704b2", "37e12753d23b7a8df92b1d32f3170d9f",
135 "9a609776cfa31f64826225d0a6b7afdd", "ccdd89e70e94f751fd891b124c1c3210",
136 "2bbf7b095e26ed4f27e7d05e20117084", "9a1b403c3a7c00da5686bcb87f1270e8",
137 "701d651e391043ab8ebbd0023a430980", "0047f10bdd8321494e8e82597fe2f969",
138 "f97e662d139b2811e3d3227de95135a2", "852933b90d4a70f9254157381ed641e0",
139 "cfcda707ec8e4361ef741dc716888348", "95e34eab83b3159f61685db248c6a881",
140 };
141 assert(id >= 0);
142 assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
143 return kDigest[id];
144 }
145
GetDigestSpeed12bpp(int id)146 const char* GetDigestSpeed12bpp(int id) {
147 static const char* const kDigest[] = {
148 "6c0f37c41d72ce40d95545ac0f08d88a", "8a8efeb7d8b2f852d76d0176b6c6878f",
149 "5757c88d1cdc0cd29c47c346474161f0", "fef8cf06d16ba7357bfc061e43080cd3",
150 "6bd11582448532bce8b91cc8807ab6a0", "1e6dd42eada2d636e210f4e20a771102",
151 "377a0472f45fcb42f1712243ea845530", "e3760f2b6e69c1b40e71ecde711d227c",
152 "6721638d1a5dadb96ddd0ca067c737ca", "3d3a23210a8496a76991bcec5045808b",
153 "2cbd26ecf7d4e927ab569083d3ddb4ca", "7d61af2d7841d1a39a2e930bac166804",
154 "dd929506442fb1f2e67130fe8cdf487b", "c0e57f8d2546d5bcb646a24d09d83d7c",
155 "2989c6487456c92eb003c8e17e904f45", "5cfb60a3be6ee5c41e0f655a3020f687",
156 "28f37d47cb07aa382659ff556a55a4c6", "b6478ab317b11f592deb60d02ce62f2f",
157 "bc78e7250c101f82e794d4fa0ee55025", "24304ed23d336a46f205206d3c5d48ef",
158 "dc1e71d95d06c1086bb7f9e05e38bf39", "32606ef72985e7de608df2e8760784b7",
159 };
160 assert(id >= 0);
161 assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
162 return kDigest[id];
163 }
164 #endif // LIBGAV1_MAX_BITDEPTH == 12
165
166 struct ObmcTestParam {
ObmcTestParamlibgav1::dsp::__anon353de85d0111::ObmcTestParam167 ObmcTestParam(int width, int height, ObmcDirection blending_direction)
168 : width(width), height(height), blending_direction(blending_direction) {}
169 int width;
170 int height;
171 ObmcDirection blending_direction;
172 };
173
operator <<(std::ostream & os,const ObmcTestParam & param)174 std::ostream& operator<<(std::ostream& os, const ObmcTestParam& param) {
175 return os << "BlockSize" << param.width << "x" << param.height
176 << ", blending_direction: " << ToString(param.blending_direction);
177 }
178
179 template <int bitdepth, typename Pixel>
180 class ObmcBlendTest : public testing::TestWithParam<ObmcTestParam> {
181 public:
182 static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
183 ObmcBlendTest() = default;
184 ~ObmcBlendTest() override = default;
185
SetUp()186 void SetUp() override {
187 test_utils::ResetDspTable(bitdepth);
188 ObmcInit_C();
189 const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
190 ASSERT_NE(dsp, nullptr);
191 const testing::TestInfo* const test_info =
192 testing::UnitTest::GetInstance()->current_test_info();
193 const absl::string_view test_case = test_info->test_suite_name();
194 if (absl::StartsWith(test_case, "C/")) {
195 } else if (absl::StartsWith(test_case, "SSE41/")) {
196 if ((GetCpuInfo() & kSSE4_1) == 0) GTEST_SKIP() << "No SSE4.1 support!";
197 ObmcInit_SSE4_1();
198 } else if (absl::StartsWith(test_case, "NEON/")) {
199 ObmcInit_NEON();
200 } else {
201 FAIL() << "Unrecognized architecture prefix in test case name: "
202 << test_case;
203 }
204 func_ = dsp->obmc_blend[blending_direction_];
205 }
206
207 protected:
GetDigestId() const208 int GetDigestId() const {
209 // blending_direction_ == kObmcDirectionVertical:
210 // (width, height):
211 // (4, 2), id = 0. (4, 4), id = 1. (4, 8), id = 2. (8, 4), id = 3.
212 // ...
213 // blending_direction_ == kObmcDirectionHorizontal: id starts from 11.
214 // Vertical skips (2, 4) while horizontal skips (4, 2) creating a gap after
215 // (2, 4).
216 const int id = (blending_direction_ == kObmcDirectionVertical) ? 0
217 : (width_ == 2) ? 12
218 : 11;
219 if (width_ == height_) return id + 3 * (FloorLog2(width_) - 1) - 2;
220 if (width_ < height_) return id + 3 * (FloorLog2(width_) - 1) - 1;
221 return id + 3 * (FloorLog2(height_) - 1);
222 }
223
224 // Note |digest| is only used when |use_fixed_values| is false.
225 void Test(const char* digest, bool use_fixed_values, int value);
226 void TestSpeed(const char* digest, int num_runs);
227
228 private:
229 const int width_ = GetParam().width;
230 const int height_ = GetParam().height;
231 const ObmcDirection blending_direction_ = GetParam().blending_direction;
232 Pixel source1_[kMaxBlendingBlockSize * kMaxBlendingBlockSize] = {};
233 Pixel source2_[kMaxBlendingBlockSize * kMaxBlendingBlockSize] = {};
234 dsp::ObmcBlendFunc func_;
235 };
236
237 template <int bitdepth, typename Pixel>
Test(const char * const digest,const bool use_fixed_values,const int value)238 void ObmcBlendTest<bitdepth, Pixel>::Test(const char* const digest,
239 const bool use_fixed_values,
240 const int value) {
241 if (func_ == nullptr) return;
242 if (use_fixed_values) {
243 std::fill(source1_,
244 source1_ + kMaxBlendingBlockSize * kMaxBlendingBlockSize, value);
245 std::fill(source2_,
246 source2_ + kMaxBlendingBlockSize * kMaxBlendingBlockSize, value);
247 } else {
248 libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
249 Pixel* src_1 = source1_;
250 Pixel* src_2 = source2_;
251 const int mask = (1 << bitdepth) - 1;
252 for (int y = 0; y < height_; ++y) {
253 for (int x = 0; x < width_; ++x) {
254 src_1[x] = rnd.Rand16() & mask;
255 src_2[x] = rnd.Rand16() & mask;
256 }
257 src_1 += kMaxBlendingBlockSize;
258 src_2 += width_;
259 }
260 }
261 const ptrdiff_t stride = kMaxBlendingBlockSize * sizeof(Pixel);
262 func_(source1_, stride, width_, height_, source2_,
263 width_ * sizeof(source2_[0]));
264 if (use_fixed_values) {
265 const bool success = test_utils::CompareBlocks(
266 source1_, source2_, width_, height_, kMaxBlendingBlockSize,
267 kMaxBlendingBlockSize, false);
268 EXPECT_TRUE(success);
269 } else {
270 test_utils::CheckMd5Digest(
271 ToString(blending_direction_),
272 absl::StrFormat("%dx%d", width_, height_).c_str(), digest, source1_,
273 sizeof(source1_), absl::Duration());
274 }
275 }
276
277 template <int bitdepth, typename Pixel>
TestSpeed(const char * const digest,const int num_runs)278 void ObmcBlendTest<bitdepth, Pixel>::TestSpeed(const char* const digest,
279 const int num_runs) {
280 if (func_ == nullptr) return;
281 libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
282 Pixel* src_1 = source1_;
283 Pixel* src_2 = source2_;
284 const int mask = (1 << bitdepth) - 1;
285 for (int y = 0; y < height_; ++y) {
286 for (int x = 0; x < width_; ++x) {
287 src_1[x] = rnd.Rand16() & mask;
288 src_2[x] = rnd.Rand16() & mask;
289 }
290 src_1 += kMaxBlendingBlockSize;
291 src_2 += width_;
292 }
293 const ptrdiff_t stride = kMaxBlendingBlockSize * sizeof(Pixel);
294 uint8_t dest[sizeof(Pixel) * kMaxBlendingBlockSize * kMaxBlendingBlockSize];
295 absl::Duration elapsed_time;
296 for (int i = 0; i < num_runs; ++i) {
297 memcpy(dest, source1_,
298 sizeof(Pixel) * kMaxBlendingBlockSize * kMaxBlendingBlockSize);
299 const absl::Time start = absl::Now();
300 func_(dest, stride, width_, height_, source2_,
301 width_ * sizeof(source2_[0]));
302 elapsed_time += absl::Now() - start;
303 }
304 memcpy(source1_, dest,
305 sizeof(Pixel) * kMaxBlendingBlockSize * kMaxBlendingBlockSize);
306 test_utils::CheckMd5Digest(ToString(blending_direction_),
307 absl::StrFormat("%dx%d", width_, height_).c_str(),
308 digest, source1_, sizeof(source1_), elapsed_time);
309 }
310
311 const ObmcTestParam kObmcTestParam[] = {
312 ObmcTestParam(4, 2, kObmcDirectionVertical),
313 ObmcTestParam(4, 4, kObmcDirectionVertical),
314 ObmcTestParam(4, 8, kObmcDirectionVertical),
315 ObmcTestParam(8, 4, kObmcDirectionVertical),
316 ObmcTestParam(8, 8, kObmcDirectionVertical),
317 ObmcTestParam(8, 16, kObmcDirectionVertical),
318 ObmcTestParam(16, 8, kObmcDirectionVertical),
319 ObmcTestParam(16, 16, kObmcDirectionVertical),
320 ObmcTestParam(16, 32, kObmcDirectionVertical),
321 ObmcTestParam(32, 16, kObmcDirectionVertical),
322 ObmcTestParam(32, 32, kObmcDirectionVertical),
323 ObmcTestParam(2, 4, kObmcDirectionHorizontal),
324 ObmcTestParam(4, 4, kObmcDirectionHorizontal),
325 ObmcTestParam(4, 8, kObmcDirectionHorizontal),
326 ObmcTestParam(8, 4, kObmcDirectionHorizontal),
327 ObmcTestParam(8, 8, kObmcDirectionHorizontal),
328 ObmcTestParam(8, 16, kObmcDirectionHorizontal),
329 ObmcTestParam(16, 8, kObmcDirectionHorizontal),
330 ObmcTestParam(16, 16, kObmcDirectionHorizontal),
331 ObmcTestParam(16, 32, kObmcDirectionHorizontal),
332 ObmcTestParam(32, 16, kObmcDirectionHorizontal),
333 ObmcTestParam(32, 32, kObmcDirectionHorizontal),
334 };
335
336 using ObmcBlendTest8bpp = ObmcBlendTest<8, uint8_t>;
337
TEST_P(ObmcBlendTest8bpp,Blending)338 TEST_P(ObmcBlendTest8bpp, Blending) {
339 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 0);
340 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 1);
341 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 128);
342 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 255);
343 Test(GetDigest8bpp(GetDigestId()), /*use_fixed_values=*/false, -1);
344 }
345
TEST_P(ObmcBlendTest8bpp,DISABLED_Speed)346 TEST_P(ObmcBlendTest8bpp, DISABLED_Speed) {
347 TestSpeed(GetDigestSpeed8bpp(GetDigestId()),
348 kNumSpeedTests / (GetParam().height * GetParam().width));
349 }
350
351 INSTANTIATE_TEST_SUITE_P(C, ObmcBlendTest8bpp,
352 testing::ValuesIn(kObmcTestParam));
353
354 #if LIBGAV1_ENABLE_SSE4_1
355 INSTANTIATE_TEST_SUITE_P(SSE41, ObmcBlendTest8bpp,
356 testing::ValuesIn(kObmcTestParam));
357 #endif
358
359 #if LIBGAV1_ENABLE_NEON
360 INSTANTIATE_TEST_SUITE_P(NEON, ObmcBlendTest8bpp,
361 testing::ValuesIn(kObmcTestParam));
362 #endif
363
364 #if LIBGAV1_MAX_BITDEPTH >= 10
365 using ObmcBlendTest10bpp = ObmcBlendTest<10, uint16_t>;
366
TEST_P(ObmcBlendTest10bpp,Blending)367 TEST_P(ObmcBlendTest10bpp, Blending) {
368 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 0);
369 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 1);
370 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 128);
371 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, (1 << 10) - 1);
372 Test(GetDigest10bpp(GetDigestId()), /*use_fixed_values=*/false, -1);
373 }
374
TEST_P(ObmcBlendTest10bpp,DISABLED_Speed)375 TEST_P(ObmcBlendTest10bpp, DISABLED_Speed) {
376 TestSpeed(GetDigestSpeed10bpp(GetDigestId()),
377 kNumSpeedTests / (GetParam().height * GetParam().width));
378 }
379
380 INSTANTIATE_TEST_SUITE_P(C, ObmcBlendTest10bpp,
381 testing::ValuesIn(kObmcTestParam));
382 #if LIBGAV1_ENABLE_SSE4_1
383 INSTANTIATE_TEST_SUITE_P(SSE41, ObmcBlendTest10bpp,
384 testing::ValuesIn(kObmcTestParam));
385 #endif
386 #if LIBGAV1_ENABLE_NEON
387 INSTANTIATE_TEST_SUITE_P(NEON, ObmcBlendTest10bpp,
388 testing::ValuesIn(kObmcTestParam));
389 #endif
390 #endif // LIBGAV1_MAX_BITDEPTH >= 10
391
392 #if LIBGAV1_MAX_BITDEPTH == 12
393 using ObmcBlendTest12bpp = ObmcBlendTest<12, uint16_t>;
394
TEST_P(ObmcBlendTest12bpp,Blending)395 TEST_P(ObmcBlendTest12bpp, Blending) {
396 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 0);
397 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 1);
398 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 128);
399 Test(/*digest=*/nullptr, /*use_fixed_values=*/true, (1 << 12) - 1);
400 Test(GetDigest12bpp(GetDigestId()), /*use_fixed_values=*/false, -1);
401 }
402
TEST_P(ObmcBlendTest12bpp,DISABLED_Speed)403 TEST_P(ObmcBlendTest12bpp, DISABLED_Speed) {
404 TestSpeed(GetDigestSpeed12bpp(GetDigestId()),
405 kNumSpeedTests / (GetParam().height * GetParam().width));
406 }
407
408 INSTANTIATE_TEST_SUITE_P(C, ObmcBlendTest12bpp,
409 testing::ValuesIn(kObmcTestParam));
410 #endif // LIBGAV1_MAX_BITDEPTH == 12
411
412 } // namespace
413 } // namespace dsp
414 } // namespace libgav1
415