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 <time.h>
13 
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/scale_argb.h"
16 #include "../unit_test/unit_test.h"
17 
18 namespace libyuv {
19 
ARGBTestFilter(int src_width,int src_height,int dst_width,int dst_height,FilterMode f,int benchmark_iterations)20 static int ARGBTestFilter(int src_width, int src_height,
21                           int dst_width, int dst_height,
22                           FilterMode f, int benchmark_iterations) {
23   const int b = 128;
24   int src_argb_plane_size = (src_width + b * 2) * (src_height + b * 2) * 4;
25   int src_stride_argb = (b * 2 + src_width) * 4;
26 
27   align_buffer_16(src_argb, src_argb_plane_size)
28   memset(src_argb, 1, src_argb_plane_size);
29 
30   int dst_argb_plane_size = (dst_width + b * 2) * (dst_height + b * 2) * 4;
31   int dst_stride_argb = (b * 2 + dst_width) * 4;
32 
33   srandom(time(NULL));
34 
35   int i, j;
36   for (i = b; i < (src_height + b); ++i) {
37     for (j = b; j < (src_width + b) * 4; ++j) {
38       src_argb[(i * src_stride_argb) + j] = (random() & 0xff);
39     }
40   }
41 
42   align_buffer_16(dst_argb_c, dst_argb_plane_size)
43   align_buffer_16(dst_argb_opt, dst_argb_plane_size)
44   memset(dst_argb_c, 2, dst_argb_plane_size);
45   memset(dst_argb_opt, 3, dst_argb_plane_size);
46 
47   // Warm up both versions for consistent benchmarks.
48   MaskCpuFlags(0);  // Disable all CPU optimization.
49   ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
50             src_width, src_height,
51             dst_argb_c + (dst_stride_argb * b) + b * 4, dst_stride_argb,
52             dst_width, dst_height, f);
53   MaskCpuFlags(-1);  // Enable all CPU optimization.
54   ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
55             src_width, src_height,
56             dst_argb_opt + (dst_stride_argb * b) + b * 4, dst_stride_argb,
57             dst_width, dst_height, f);
58 
59   MaskCpuFlags(0);  // Disable all CPU optimization.
60   double c_time = get_time();
61   for (i = 0; i < benchmark_iterations; ++i) {
62     ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
63               src_width, src_height,
64               dst_argb_c + (dst_stride_argb * b) + b * 4, dst_stride_argb,
65               dst_width, dst_height, f);
66   }
67   c_time = (get_time() - c_time) / benchmark_iterations;
68 
69   MaskCpuFlags(-1);  // Enable all CPU optimization.
70   double opt_time = get_time();
71   for (i = 0; i < benchmark_iterations; ++i) {
72     ARGBScale(src_argb + (src_stride_argb * b) + b * 4, src_stride_argb,
73               src_width, src_height,
74               dst_argb_opt + (dst_stride_argb * b) + b * 4, dst_stride_argb,
75               dst_width, dst_height, f);
76   }
77   opt_time = (get_time() - opt_time) / benchmark_iterations;
78 
79   // Report performance of C vs OPT
80   printf("filter %d - %8d us C - %8d us OPT\n",
81          f, static_cast<int>(c_time*1e6), static_cast<int>(opt_time*1e6));
82 
83   // C version may be a little off from the optimized. Order of
84   //  operations may introduce rounding somewhere. So do a difference
85   //  of the buffers and look to see that the max difference isn't
86   //  over 2.
87   int max_diff = 0;
88   for (i = b; i < (dst_height + b); ++i) {
89     for (j = b * 4; j < (dst_width + b) * 4; ++j) {
90       int abs_diff = abs(dst_argb_c[(i * dst_stride_argb) + j] -
91                          dst_argb_opt[(i * dst_stride_argb) + j]);
92       if (abs_diff > max_diff) {
93         max_diff = abs_diff;
94       }
95     }
96   }
97 
98   free_aligned_buffer_16(dst_argb_c)
99   free_aligned_buffer_16(dst_argb_opt)
100   free_aligned_buffer_16(src_argb)
101   return max_diff;
102 }
103 
TEST_F(libyuvTest,ARGBScaleDownBy2)104 TEST_F(libyuvTest, ARGBScaleDownBy2) {
105   const int src_width = 1280;
106   const int src_height = 720;
107   const int dst_width = src_width / 2;
108   const int dst_height = src_height / 2;
109 
110   for (int f = 0; f < 2; ++f) {
111     int max_diff = ARGBTestFilter(src_width, src_height,
112                                   dst_width, dst_height,
113                                   static_cast<FilterMode>(f),
114                                   benchmark_iterations_);
115     EXPECT_LE(max_diff, 1);
116   }
117 }
118 
TEST_F(libyuvTest,ARGBScaleDownBy4)119 TEST_F(libyuvTest, ARGBScaleDownBy4) {
120   const int src_width = 1280;
121   const int src_height = 720;
122   const int dst_width = src_width / 4;
123   const int dst_height = src_height / 4;
124 
125   for (int f = 0; f < 2; ++f) {
126     int max_diff = ARGBTestFilter(src_width, src_height,
127                                   dst_width, dst_height,
128                                   static_cast<FilterMode>(f),
129                                   benchmark_iterations_);
130     EXPECT_LE(max_diff, 1);
131   }
132 }
133 
TEST_F(libyuvTest,ARGBScaleDownBy5)134 TEST_F(libyuvTest, ARGBScaleDownBy5) {
135   const int src_width = 1280;
136   const int src_height = 720;
137   const int dst_width = src_width / 5;
138   const int dst_height = src_height / 5;
139 
140   for (int f = 0; f < 2; ++f) {
141     int max_diff = ARGBTestFilter(src_width, src_height,
142                                   dst_width, dst_height,
143                                   static_cast<FilterMode>(f),
144                                   benchmark_iterations_);
145     EXPECT_LE(max_diff, 1);
146   }
147 }
148 
TEST_F(libyuvTest,ARGBScaleDownBy8)149 TEST_F(libyuvTest, ARGBScaleDownBy8) {
150   const int src_width = 1280;
151   const int src_height = 720;
152   const int dst_width = src_width / 8;
153   const int dst_height = src_height / 8;
154 
155   for (int f = 0; f < 2; ++f) {
156     int max_diff = ARGBTestFilter(src_width, src_height,
157                                   dst_width, dst_height,
158                                   static_cast<FilterMode>(f),
159                                   benchmark_iterations_);
160     EXPECT_LE(max_diff, 1);
161   }
162 }
163 
TEST_F(libyuvTest,ARGBScaleDownBy16)164 TEST_F(libyuvTest, ARGBScaleDownBy16) {
165   const int src_width = 1280;
166   const int src_height = 720;
167   const int dst_width = src_width / 16;
168   const int dst_height = src_height / 16;
169 
170   for (int f = 0; f < 2; ++f) {
171     int max_diff = ARGBTestFilter(src_width, src_height,
172                                   dst_width, dst_height,
173                                   static_cast<FilterMode>(f),
174                                   benchmark_iterations_);
175     EXPECT_LE(max_diff, 1);
176   }
177 }
178 
TEST_F(libyuvTest,ARGBScaleDownBy34)179 TEST_F(libyuvTest, ARGBScaleDownBy34) {
180   const int src_width = 1280;
181   const int src_height = 720;
182   const int dst_width = src_width * 3 / 4;
183   const int dst_height = src_height * 3 / 4;
184 
185   for (int f = 0; f < 2; ++f) {
186     int max_diff = ARGBTestFilter(src_width, src_height,
187                                   dst_width, dst_height,
188                                   static_cast<FilterMode>(f),
189                                   benchmark_iterations_);
190     EXPECT_LE(max_diff, 1);
191   }
192 }
193 
TEST_F(libyuvTest,ARGBScaleDownBy38)194 TEST_F(libyuvTest, ARGBScaleDownBy38) {
195   int src_width = 1280;
196   int src_height = 720;
197   int dst_width = src_width * 3 / 8;
198   int dst_height = src_height * 3 / 8;
199 
200   for (int f = 0; f < 2; ++f) {
201     int max_diff = ARGBTestFilter(src_width, src_height,
202                                   dst_width, dst_height,
203                                   static_cast<FilterMode>(f),
204                                   benchmark_iterations_);
205     EXPECT_LE(max_diff, 1);
206   }
207 }
208 
TEST_F(libyuvTest,ARGBScaleTo1366)209 TEST_F(libyuvTest, ARGBScaleTo1366) {
210   int src_width = 1280;
211   int src_height = 720;
212   int dst_width = 1366;
213   int dst_height = 768;
214 
215   for (int f = 0; f < 2; ++f) {
216     int max_diff = ARGBTestFilter(src_width, src_height,
217                                   dst_width, dst_height,
218                                   static_cast<FilterMode>(f),
219                                   benchmark_iterations_);
220     EXPECT_LE(max_diff, 1);
221   }
222 }
223 
TEST_F(libyuvTest,ARGBScaleTo4074)224 TEST_F(libyuvTest, ARGBScaleTo4074) {
225   int src_width = 2880 * 2;
226   int src_height = 1800;
227   int dst_width = 4074;
228   int dst_height = 1272;
229 
230   for (int f = 0; f < 2; ++f) {
231     int max_diff = ARGBTestFilter(src_width, src_height,
232                                   dst_width, dst_height,
233                                   static_cast<FilterMode>(f),
234                                   benchmark_iterations_);
235     EXPECT_LE(max_diff, 1);
236   }
237 }
238 
239 
TEST_F(libyuvTest,ARGBScaleTo853)240 TEST_F(libyuvTest, ARGBScaleTo853) {
241   int src_width = 1280;
242   int src_height = 720;
243   int dst_width = 853;
244   int dst_height = 480;
245 
246   for (int f = 0; f < 2; ++f) {
247     int max_diff = ARGBTestFilter(src_width, src_height,
248                                   dst_width, dst_height,
249                                   static_cast<FilterMode>(f),
250                                   benchmark_iterations_);
251     EXPECT_LE(max_diff, 1);
252   }
253 }
254 
255 }  // namespace libyuv
256