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