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