1 /*
2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14
15 #include "../unit_test/unit_test.h"
16 #include "libyuv/basic_types.h"
17 #include "libyuv/compare.h"
18 #include "libyuv/compare_row.h" /* For HammingDistance_C */
19 #include "libyuv/cpu_id.h"
20 #include "libyuv/video_common.h"
21
22 namespace libyuv {
23
24 // hash seed of 5381 recommended.
ReferenceHashDjb2(const uint8_t * src,uint64_t count,uint32_t seed)25 static uint32_t ReferenceHashDjb2(const uint8_t* src,
26 uint64_t count,
27 uint32_t seed) {
28 uint32_t hash = seed;
29 if (count > 0) {
30 do {
31 hash = hash * 33 + *src++;
32 } while (--count);
33 }
34 return hash;
35 }
36
TEST_F(LibYUVCompareTest,Djb2_Test)37 TEST_F(LibYUVCompareTest, Djb2_Test) {
38 const int kMaxTest = benchmark_width_ * benchmark_height_;
39 align_buffer_page_end(src_a, kMaxTest);
40 align_buffer_page_end(src_b, kMaxTest);
41
42 const char* fox =
43 "The quick brown fox jumps over the lazy dog"
44 " and feels as if he were in the seventh heaven of typography"
45 " together with Hermann Zapf";
46 uint32_t foxhash = HashDjb2(reinterpret_cast<const uint8_t*>(fox), 131, 5381);
47 const uint32_t kExpectedFoxHash = 2611006483u;
48 EXPECT_EQ(kExpectedFoxHash, foxhash);
49
50 for (int i = 0; i < kMaxTest; ++i) {
51 src_a[i] = (fastrand() & 0xff);
52 src_b[i] = (fastrand() & 0xff);
53 }
54 // Compare different buffers. Expect hash is different.
55 uint32_t h1 = HashDjb2(src_a, kMaxTest, 5381);
56 uint32_t h2 = HashDjb2(src_b, kMaxTest, 5381);
57 EXPECT_NE(h1, h2);
58
59 // Make last half same. Expect hash is different.
60 memcpy(src_a + kMaxTest / 2, src_b + kMaxTest / 2, kMaxTest / 2);
61 h1 = HashDjb2(src_a, kMaxTest, 5381);
62 h2 = HashDjb2(src_b, kMaxTest, 5381);
63 EXPECT_NE(h1, h2);
64
65 // Make first half same. Expect hash is different.
66 memcpy(src_a + kMaxTest / 2, src_a, kMaxTest / 2);
67 memcpy(src_b + kMaxTest / 2, src_b, kMaxTest / 2);
68 memcpy(src_a, src_b, kMaxTest / 2);
69 h1 = HashDjb2(src_a, kMaxTest, 5381);
70 h2 = HashDjb2(src_b, kMaxTest, 5381);
71 EXPECT_NE(h1, h2);
72
73 // Make same. Expect hash is same.
74 memcpy(src_a, src_b, kMaxTest);
75 h1 = HashDjb2(src_a, kMaxTest, 5381);
76 h2 = HashDjb2(src_b, kMaxTest, 5381);
77 EXPECT_EQ(h1, h2);
78
79 // Mask seed different. Expect hash is different.
80 memcpy(src_a, src_b, kMaxTest);
81 h1 = HashDjb2(src_a, kMaxTest, 5381);
82 h2 = HashDjb2(src_b, kMaxTest, 1234);
83 EXPECT_NE(h1, h2);
84
85 // Make one byte different in middle. Expect hash is different.
86 memcpy(src_a, src_b, kMaxTest);
87 ++src_b[kMaxTest / 2];
88 h1 = HashDjb2(src_a, kMaxTest, 5381);
89 h2 = HashDjb2(src_b, kMaxTest, 5381);
90 EXPECT_NE(h1, h2);
91
92 // Make first byte different. Expect hash is different.
93 memcpy(src_a, src_b, kMaxTest);
94 ++src_b[0];
95 h1 = HashDjb2(src_a, kMaxTest, 5381);
96 h2 = HashDjb2(src_b, kMaxTest, 5381);
97 EXPECT_NE(h1, h2);
98
99 // Make last byte different. Expect hash is different.
100 memcpy(src_a, src_b, kMaxTest);
101 ++src_b[kMaxTest - 1];
102 h1 = HashDjb2(src_a, kMaxTest, 5381);
103 h2 = HashDjb2(src_b, kMaxTest, 5381);
104 EXPECT_NE(h1, h2);
105
106 // Make a zeros. Test different lengths. Expect hash is different.
107 memset(src_a, 0, kMaxTest);
108 h1 = HashDjb2(src_a, kMaxTest, 5381);
109 h2 = HashDjb2(src_a, kMaxTest / 2, 5381);
110 EXPECT_NE(h1, h2);
111
112 // Make a zeros and seed of zero. Test different lengths. Expect hash is same.
113 memset(src_a, 0, kMaxTest);
114 h1 = HashDjb2(src_a, kMaxTest, 0);
115 h2 = HashDjb2(src_a, kMaxTest / 2, 0);
116 EXPECT_EQ(h1, h2);
117
118 free_aligned_buffer_page_end(src_a);
119 free_aligned_buffer_page_end(src_b);
120 }
121
TEST_F(LibYUVCompareTest,BenchmarkDjb2_Opt)122 TEST_F(LibYUVCompareTest, BenchmarkDjb2_Opt) {
123 const int kMaxTest = benchmark_width_ * benchmark_height_;
124 align_buffer_page_end(src_a, kMaxTest);
125
126 for (int i = 0; i < kMaxTest; ++i) {
127 src_a[i] = i;
128 }
129 uint32_t h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381);
130 uint32_t h1;
131 for (int i = 0; i < benchmark_iterations_; ++i) {
132 h1 = HashDjb2(src_a, kMaxTest, 5381);
133 }
134 EXPECT_EQ(h1, h2);
135 free_aligned_buffer_page_end(src_a);
136 }
137
TEST_F(LibYUVCompareTest,BenchmarkDjb2_Unaligned)138 TEST_F(LibYUVCompareTest, BenchmarkDjb2_Unaligned) {
139 const int kMaxTest = benchmark_width_ * benchmark_height_;
140 align_buffer_page_end(src_a, kMaxTest + 1);
141 for (int i = 0; i < kMaxTest; ++i) {
142 src_a[i + 1] = i;
143 }
144 uint32_t h2 = ReferenceHashDjb2(src_a + 1, kMaxTest, 5381);
145 uint32_t h1;
146 for (int i = 0; i < benchmark_iterations_; ++i) {
147 h1 = HashDjb2(src_a + 1, kMaxTest, 5381);
148 }
149 EXPECT_EQ(h1, h2);
150 free_aligned_buffer_page_end(src_a);
151 }
152
TEST_F(LibYUVCompareTest,BenchmarkARGBDetect_Opt)153 TEST_F(LibYUVCompareTest, BenchmarkARGBDetect_Opt) {
154 uint32_t fourcc;
155 const int kMaxTest = benchmark_width_ * benchmark_height_ * 4;
156 align_buffer_page_end(src_a, kMaxTest);
157 for (int i = 0; i < kMaxTest; ++i) {
158 src_a[i] = 255;
159 }
160
161 src_a[0] = 0;
162 fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_,
163 benchmark_height_);
164 EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_BGRA), fourcc);
165 src_a[0] = 255;
166 src_a[3] = 0;
167 fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_,
168 benchmark_height_);
169 EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_ARGB), fourcc);
170 src_a[3] = 255;
171
172 for (int i = 0; i < benchmark_iterations_; ++i) {
173 fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_,
174 benchmark_height_);
175 }
176 EXPECT_EQ(0u, fourcc);
177
178 free_aligned_buffer_page_end(src_a);
179 }
180
TEST_F(LibYUVCompareTest,BenchmarkARGBDetect_Unaligned)181 TEST_F(LibYUVCompareTest, BenchmarkARGBDetect_Unaligned) {
182 uint32_t fourcc;
183 const int kMaxTest = benchmark_width_ * benchmark_height_ * 4 + 1;
184 align_buffer_page_end(src_a, kMaxTest);
185 for (int i = 1; i < kMaxTest; ++i) {
186 src_a[i] = 255;
187 }
188
189 src_a[0 + 1] = 0;
190 fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_,
191 benchmark_height_);
192 EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_BGRA), fourcc);
193 src_a[0 + 1] = 255;
194 src_a[3 + 1] = 0;
195 fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_,
196 benchmark_height_);
197 EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_ARGB), fourcc);
198 src_a[3 + 1] = 255;
199
200 for (int i = 0; i < benchmark_iterations_; ++i) {
201 fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_,
202 benchmark_height_);
203 }
204 EXPECT_EQ(0u, fourcc);
205
206 free_aligned_buffer_page_end(src_a);
207 }
208
TEST_F(LibYUVCompareTest,BenchmarkHammingDistance_Opt)209 TEST_F(LibYUVCompareTest, BenchmarkHammingDistance_Opt) {
210 const int kMaxWidth = 4096 * 3;
211 align_buffer_page_end(src_a, kMaxWidth);
212 align_buffer_page_end(src_b, kMaxWidth);
213 memset(src_a, 0, kMaxWidth);
214 memset(src_b, 0, kMaxWidth);
215
216 // Test known value
217 memcpy(src_a, "test0123test4567", 16);
218 memcpy(src_b, "tick0123tock4567", 16);
219 uint32_t h1 = HammingDistance_C(src_a, src_b, 16);
220 EXPECT_EQ(16u, h1);
221
222 // Test C vs OPT on random buffer
223 MemRandomize(src_a, kMaxWidth);
224 MemRandomize(src_b, kMaxWidth);
225
226 uint32_t h0 = HammingDistance_C(src_a, src_b, kMaxWidth);
227
228 int count =
229 benchmark_iterations_ *
230 ((benchmark_width_ * benchmark_height_ + kMaxWidth - 1) / kMaxWidth);
231 for (int i = 0; i < count; ++i) {
232 #if defined(HAS_HAMMINGDISTANCE_NEON)
233 h1 = HammingDistance_NEON(src_a, src_b, kMaxWidth);
234 #elif defined(HAS_HAMMINGDISTANCE_AVX2)
235 int has_avx2 = TestCpuFlag(kCpuHasAVX2);
236 if (has_avx2) {
237 h1 = HammingDistance_AVX2(src_a, src_b, kMaxWidth);
238 } else {
239 int has_sse42 = TestCpuFlag(kCpuHasSSE42);
240 if (has_sse42) {
241 h1 = HammingDistance_SSE42(src_a, src_b, kMaxWidth);
242 } else {
243 int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
244 if (has_ssse3) {
245 h1 = HammingDistance_SSSE3(src_a, src_b, kMaxWidth);
246 } else {
247 h1 = HammingDistance_C(src_a, src_b, kMaxWidth);
248 }
249 }
250 }
251 #elif defined(HAS_HAMMINGDISTANCE_SSE42)
252 int has_sse42 = TestCpuFlag(kCpuHasSSE42);
253 if (has_sse42) {
254 h1 = HammingDistance_SSE42(src_a, src_b, kMaxWidth);
255 } else {
256 h1 = HammingDistance_C(src_a, src_b, kMaxWidth);
257 }
258 #else
259 h1 = HammingDistance_C(src_a, src_b, kMaxWidth);
260 #endif
261 }
262 EXPECT_EQ(h0, h1);
263
264 free_aligned_buffer_page_end(src_a);
265 free_aligned_buffer_page_end(src_b);
266 }
267
TEST_F(LibYUVCompareTest,BenchmarkHammingDistance_C)268 TEST_F(LibYUVCompareTest, BenchmarkHammingDistance_C) {
269 const int kMaxWidth = 4096 * 3;
270 align_buffer_page_end(src_a, kMaxWidth);
271 align_buffer_page_end(src_b, kMaxWidth);
272 memset(src_a, 0, kMaxWidth);
273 memset(src_b, 0, kMaxWidth);
274
275 // Test known value
276 memcpy(src_a, "test0123test4567", 16);
277 memcpy(src_b, "tick0123tock4567", 16);
278 uint32_t h1 = HammingDistance_C(src_a, src_b, 16);
279 EXPECT_EQ(16u, h1);
280
281 // Test C vs OPT on random buffer
282 MemRandomize(src_a, kMaxWidth);
283 MemRandomize(src_b, kMaxWidth);
284
285 uint32_t h0 = HammingDistance_C(src_a, src_b, kMaxWidth);
286
287 int count =
288 benchmark_iterations_ *
289 ((benchmark_width_ * benchmark_height_ + kMaxWidth - 1) / kMaxWidth);
290 for (int i = 0; i < count; ++i) {
291 h1 = HammingDistance_C(src_a, src_b, kMaxWidth);
292 }
293
294 EXPECT_EQ(h0, h1);
295
296 free_aligned_buffer_page_end(src_a);
297 free_aligned_buffer_page_end(src_b);
298 }
299
TEST_F(LibYUVCompareTest,BenchmarkHammingDistance)300 TEST_F(LibYUVCompareTest, BenchmarkHammingDistance) {
301 const int kMaxWidth = 4096 * 3;
302 align_buffer_page_end(src_a, kMaxWidth);
303 align_buffer_page_end(src_b, kMaxWidth);
304 memset(src_a, 0, kMaxWidth);
305 memset(src_b, 0, kMaxWidth);
306
307 memcpy(src_a, "test0123test4567", 16);
308 memcpy(src_b, "tick0123tock4567", 16);
309 uint64_t h1 = ComputeHammingDistance(src_a, src_b, 16);
310 EXPECT_EQ(16u, h1);
311
312 // Test C vs OPT on random buffer
313 MemRandomize(src_a, kMaxWidth);
314 MemRandomize(src_b, kMaxWidth);
315
316 uint32_t h0 = HammingDistance_C(src_a, src_b, kMaxWidth);
317
318 int count =
319 benchmark_iterations_ *
320 ((benchmark_width_ * benchmark_height_ + kMaxWidth - 1) / kMaxWidth);
321 for (int i = 0; i < count; ++i) {
322 h1 = ComputeHammingDistance(src_a, src_b, kMaxWidth);
323 }
324
325 EXPECT_EQ(h0, h1);
326
327 free_aligned_buffer_page_end(src_a);
328 free_aligned_buffer_page_end(src_b);
329 }
330
331 // Tests low levels match reference C for specified size.
332 // The opt implementations have size limitations
333 // For NEON the counters are 16 bit so the shorts overflow after 65536 bytes.
334 // So doing one less iteration of the loop is the maximum.
335 #if defined(HAS_HAMMINGDISTANCE_NEON)
336 static const int kMaxOptCount = 65536 - 32; // 65504
337 #else
338 static const int kMaxOptCount = (1 << (32 - 3)) - 64; // 536870848
339 #endif
340
TEST_F(LibYUVCompareTest,TestHammingDistance_Opt)341 TEST_F(LibYUVCompareTest, TestHammingDistance_Opt) {
342 uint32_t h1 = 0;
343 const int kMaxWidth = (benchmark_width_ * benchmark_height_ + 31) & ~31;
344 align_buffer_page_end(src_a, kMaxWidth);
345 align_buffer_page_end(src_b, kMaxWidth);
346 memset(src_a, 255u, kMaxWidth);
347 memset(src_b, 0u, kMaxWidth);
348
349 uint64_t h0 = ComputeHammingDistance(src_a, src_b, kMaxWidth);
350 EXPECT_EQ(kMaxWidth * 8ULL, h0);
351
352 for (int i = 0; i < benchmark_iterations_; ++i) {
353 #if defined(HAS_HAMMINGDISTANCE_NEON)
354 h1 = HammingDistance_NEON(src_a, src_b, kMaxWidth);
355 #elif defined(HAS_HAMMINGDISTANCE_AVX2)
356 int has_avx2 = TestCpuFlag(kCpuHasAVX2);
357 if (has_avx2) {
358 h1 = HammingDistance_AVX2(src_a, src_b, kMaxWidth);
359 } else {
360 int has_sse42 = TestCpuFlag(kCpuHasSSE42);
361 if (has_sse42) {
362 h1 = HammingDistance_SSE42(src_a, src_b, kMaxWidth);
363 } else {
364 int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
365 if (has_ssse3) {
366 h1 = HammingDistance_SSSE3(src_a, src_b, kMaxWidth);
367 } else {
368 h1 = HammingDistance_C(src_a, src_b, kMaxWidth);
369 }
370 }
371 }
372 #elif defined(HAS_HAMMINGDISTANCE_SSE42)
373 int has_sse42 = TestCpuFlag(kCpuHasSSE42);
374 if (has_sse42) {
375 h1 = HammingDistance_SSE42(src_a, src_b, kMaxWidth);
376 } else {
377 h1 = HammingDistance_C(src_a, src_b, kMaxWidth);
378 }
379 #else
380 h1 = HammingDistance_C(src_a, src_b, kMaxWidth);
381 #endif
382 }
383
384 // A large count will cause the low level to potentially overflow so the
385 // result can not be expected to be correct.
386 // TODO(fbarchard): Consider expecting the low 16 bits to match.
387 if (kMaxWidth <= kMaxOptCount) {
388 EXPECT_EQ(kMaxWidth * 8U, h1);
389 } else {
390 if (kMaxWidth * 8ULL != static_cast<uint64_t>(h1)) {
391 printf(
392 "warning - HammingDistance_Opt %u does not match %llu "
393 "but length of %u is longer than guaranteed.\n",
394 h1, kMaxWidth * 8ULL, kMaxWidth);
395 } else {
396 printf(
397 "warning - HammingDistance_Opt %u matches but length of %u "
398 "is longer than guaranteed.\n",
399 h1, kMaxWidth);
400 }
401 }
402
403 free_aligned_buffer_page_end(src_a);
404 free_aligned_buffer_page_end(src_b);
405 }
406
TEST_F(LibYUVCompareTest,TestHammingDistance)407 TEST_F(LibYUVCompareTest, TestHammingDistance) {
408 align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_);
409 align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
410 memset(src_a, 255u, benchmark_width_ * benchmark_height_);
411 memset(src_b, 0, benchmark_width_ * benchmark_height_);
412
413 uint64_t h1 = 0;
414 for (int i = 0; i < benchmark_iterations_; ++i) {
415 h1 = ComputeHammingDistance(src_a, src_b,
416 benchmark_width_ * benchmark_height_);
417 }
418 EXPECT_EQ(benchmark_width_ * benchmark_height_ * 8ULL, h1);
419
420 free_aligned_buffer_page_end(src_a);
421 free_aligned_buffer_page_end(src_b);
422 }
423
TEST_F(LibYUVCompareTest,BenchmarkSumSquareError_Opt)424 TEST_F(LibYUVCompareTest, BenchmarkSumSquareError_Opt) {
425 const int kMaxWidth = 4096 * 3;
426 align_buffer_page_end(src_a, kMaxWidth);
427 align_buffer_page_end(src_b, kMaxWidth);
428 memset(src_a, 0, kMaxWidth);
429 memset(src_b, 0, kMaxWidth);
430
431 memcpy(src_a, "test0123test4567", 16);
432 memcpy(src_b, "tick0123tock4567", 16);
433 uint64_t h1 = ComputeSumSquareError(src_a, src_b, 16);
434 EXPECT_EQ(790u, h1);
435
436 for (int i = 0; i < kMaxWidth; ++i) {
437 src_a[i] = i;
438 src_b[i] = i;
439 }
440 memset(src_a, 0, kMaxWidth);
441 memset(src_b, 0, kMaxWidth);
442
443 int count =
444 benchmark_iterations_ *
445 ((benchmark_width_ * benchmark_height_ + kMaxWidth - 1) / kMaxWidth);
446 for (int i = 0; i < count; ++i) {
447 h1 = ComputeSumSquareError(src_a, src_b, kMaxWidth);
448 }
449
450 EXPECT_EQ(0u, h1);
451
452 free_aligned_buffer_page_end(src_a);
453 free_aligned_buffer_page_end(src_b);
454 }
455
TEST_F(LibYUVCompareTest,SumSquareError)456 TEST_F(LibYUVCompareTest, SumSquareError) {
457 const int kMaxWidth = 4096 * 3;
458 align_buffer_page_end(src_a, kMaxWidth);
459 align_buffer_page_end(src_b, kMaxWidth);
460 memset(src_a, 0, kMaxWidth);
461 memset(src_b, 0, kMaxWidth);
462
463 uint64_t err;
464 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
465
466 EXPECT_EQ(0u, err);
467
468 memset(src_a, 1, kMaxWidth);
469 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
470
471 EXPECT_EQ(static_cast<int>(err), kMaxWidth);
472
473 memset(src_a, 190, kMaxWidth);
474 memset(src_b, 193, kMaxWidth);
475 err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
476
477 EXPECT_EQ(static_cast<int>(err), kMaxWidth * 3 * 3);
478
479 for (int i = 0; i < kMaxWidth; ++i) {
480 src_a[i] = (fastrand() & 0xff);
481 src_b[i] = (fastrand() & 0xff);
482 }
483
484 MaskCpuFlags(disable_cpu_flags_);
485 uint64_t c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
486
487 MaskCpuFlags(benchmark_cpu_info_);
488 uint64_t opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth);
489
490 EXPECT_EQ(c_err, opt_err);
491
492 free_aligned_buffer_page_end(src_a);
493 free_aligned_buffer_page_end(src_b);
494 }
495
TEST_F(LibYUVCompareTest,BenchmarkPsnr_Opt)496 TEST_F(LibYUVCompareTest, BenchmarkPsnr_Opt) {
497 align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_);
498 align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
499 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
500 src_a[i] = i;
501 src_b[i] = i;
502 }
503
504 MaskCpuFlags(benchmark_cpu_info_);
505
506 double opt_time = get_time();
507 for (int i = 0; i < benchmark_iterations_; ++i) {
508 CalcFramePsnr(src_a, benchmark_width_, src_b, benchmark_width_,
509 benchmark_width_, benchmark_height_);
510 }
511
512 opt_time = (get_time() - opt_time) / benchmark_iterations_;
513 printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6);
514
515 EXPECT_EQ(0, 0);
516
517 free_aligned_buffer_page_end(src_a);
518 free_aligned_buffer_page_end(src_b);
519 }
520
TEST_F(LibYUVCompareTest,BenchmarkPsnr_Unaligned)521 TEST_F(LibYUVCompareTest, BenchmarkPsnr_Unaligned) {
522 align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_ + 1);
523 align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
524 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
525 src_a[i + 1] = i;
526 src_b[i] = i;
527 }
528
529 MaskCpuFlags(benchmark_cpu_info_);
530
531 double opt_time = get_time();
532 for (int i = 0; i < benchmark_iterations_; ++i) {
533 CalcFramePsnr(src_a + 1, benchmark_width_, src_b, benchmark_width_,
534 benchmark_width_, benchmark_height_);
535 }
536
537 opt_time = (get_time() - opt_time) / benchmark_iterations_;
538 printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6);
539
540 EXPECT_EQ(0, 0);
541
542 free_aligned_buffer_page_end(src_a);
543 free_aligned_buffer_page_end(src_b);
544 }
545
TEST_F(LibYUVCompareTest,Psnr)546 TEST_F(LibYUVCompareTest, Psnr) {
547 const int kSrcWidth = benchmark_width_;
548 const int kSrcHeight = benchmark_height_;
549 const int b = 128;
550 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
551 const int kSrcStride = 2 * b + kSrcWidth;
552 align_buffer_page_end(src_a, kSrcPlaneSize);
553 align_buffer_page_end(src_b, kSrcPlaneSize);
554 memset(src_a, 0, kSrcPlaneSize);
555 memset(src_b, 0, kSrcPlaneSize);
556
557 double err;
558 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
559 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
560 kSrcHeight);
561
562 EXPECT_EQ(err, kMaxPsnr);
563
564 memset(src_a, 255, kSrcPlaneSize);
565
566 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
567 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
568 kSrcHeight);
569
570 EXPECT_EQ(err, 0.0);
571
572 memset(src_a, 1, kSrcPlaneSize);
573
574 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
575 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
576 kSrcHeight);
577
578 EXPECT_GT(err, 48.0);
579 EXPECT_LT(err, 49.0);
580
581 for (int i = 0; i < kSrcPlaneSize; ++i) {
582 src_a[i] = i;
583 }
584
585 err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
586 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
587 kSrcHeight);
588
589 EXPECT_GT(err, 2.0);
590 if (kSrcWidth * kSrcHeight >= 256) {
591 EXPECT_LT(err, 6.0);
592 }
593
594 memset(src_a, 0, kSrcPlaneSize);
595 memset(src_b, 0, kSrcPlaneSize);
596
597 for (int i = b; i < (kSrcHeight + b); ++i) {
598 for (int j = b; j < (kSrcWidth + b); ++j) {
599 src_a[(i * kSrcStride) + j] = (fastrand() & 0xff);
600 src_b[(i * kSrcStride) + j] = (fastrand() & 0xff);
601 }
602 }
603
604 MaskCpuFlags(disable_cpu_flags_);
605 double c_err, opt_err;
606
607 c_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
608 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
609 kSrcHeight);
610
611 MaskCpuFlags(benchmark_cpu_info_);
612
613 opt_err = CalcFramePsnr(src_a + kSrcStride * b + b, kSrcStride,
614 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
615 kSrcHeight);
616
617 EXPECT_EQ(opt_err, c_err);
618
619 free_aligned_buffer_page_end(src_a);
620 free_aligned_buffer_page_end(src_b);
621 }
622
TEST_F(LibYUVCompareTest,DISABLED_BenchmarkSsim_Opt)623 TEST_F(LibYUVCompareTest, DISABLED_BenchmarkSsim_Opt) {
624 align_buffer_page_end(src_a, benchmark_width_ * benchmark_height_);
625 align_buffer_page_end(src_b, benchmark_width_ * benchmark_height_);
626 for (int i = 0; i < benchmark_width_ * benchmark_height_; ++i) {
627 src_a[i] = i;
628 src_b[i] = i;
629 }
630
631 MaskCpuFlags(benchmark_cpu_info_);
632
633 double opt_time = get_time();
634 for (int i = 0; i < benchmark_iterations_; ++i) {
635 CalcFrameSsim(src_a, benchmark_width_, src_b, benchmark_width_,
636 benchmark_width_, benchmark_height_);
637 }
638
639 opt_time = (get_time() - opt_time) / benchmark_iterations_;
640 printf("BenchmarkSsim_Opt - %8.2f us opt\n", opt_time * 1e6);
641
642 EXPECT_EQ(0, 0); // Pass if we get this far.
643
644 free_aligned_buffer_page_end(src_a);
645 free_aligned_buffer_page_end(src_b);
646 }
647
TEST_F(LibYUVCompareTest,Ssim)648 TEST_F(LibYUVCompareTest, Ssim) {
649 const int kSrcWidth = benchmark_width_;
650 const int kSrcHeight = benchmark_height_;
651 const int b = 128;
652 const int kSrcPlaneSize = (kSrcWidth + b * 2) * (kSrcHeight + b * 2);
653 const int kSrcStride = 2 * b + kSrcWidth;
654 align_buffer_page_end(src_a, kSrcPlaneSize);
655 align_buffer_page_end(src_b, kSrcPlaneSize);
656 memset(src_a, 0, kSrcPlaneSize);
657 memset(src_b, 0, kSrcPlaneSize);
658
659 if (kSrcWidth <= 8 || kSrcHeight <= 8) {
660 printf("warning - Ssim size too small. Testing function executes.\n");
661 }
662
663 double err;
664 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
665 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
666 kSrcHeight);
667
668 if (kSrcWidth > 8 && kSrcHeight > 8) {
669 EXPECT_EQ(err, 1.0);
670 }
671
672 memset(src_a, 255, kSrcPlaneSize);
673
674 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
675 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
676 kSrcHeight);
677
678 if (kSrcWidth > 8 && kSrcHeight > 8) {
679 EXPECT_LT(err, 0.0001);
680 }
681
682 memset(src_a, 1, kSrcPlaneSize);
683
684 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
685 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
686 kSrcHeight);
687
688 if (kSrcWidth > 8 && kSrcHeight > 8) {
689 EXPECT_GT(err, 0.0001);
690 EXPECT_LT(err, 0.9);
691 }
692
693 for (int i = 0; i < kSrcPlaneSize; ++i) {
694 src_a[i] = i;
695 }
696
697 err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
698 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
699 kSrcHeight);
700
701 if (kSrcWidth > 8 && kSrcHeight > 8) {
702 EXPECT_GT(err, 0.0);
703 EXPECT_LT(err, 0.01);
704 }
705
706 for (int i = b; i < (kSrcHeight + b); ++i) {
707 for (int j = b; j < (kSrcWidth + b); ++j) {
708 src_a[(i * kSrcStride) + j] = (fastrand() & 0xff);
709 src_b[(i * kSrcStride) + j] = (fastrand() & 0xff);
710 }
711 }
712
713 MaskCpuFlags(disable_cpu_flags_);
714 double c_err, opt_err;
715
716 c_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
717 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
718 kSrcHeight);
719
720 MaskCpuFlags(benchmark_cpu_info_);
721
722 opt_err = CalcFrameSsim(src_a + kSrcStride * b + b, kSrcStride,
723 src_b + kSrcStride * b + b, kSrcStride, kSrcWidth,
724 kSrcHeight);
725
726 if (kSrcWidth > 8 && kSrcHeight > 8) {
727 EXPECT_EQ(opt_err, c_err);
728 }
729
730 free_aligned_buffer_page_end(src_a);
731 free_aligned_buffer_page_end(src_b);
732 }
733
734 } // namespace libyuv
735