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
18namespace libyuv {
19
20static 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
104TEST_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
119TEST_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
134TEST_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
149TEST_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
164TEST_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
179TEST_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
194TEST_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
209TEST_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
224TEST_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
240TEST_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