1/*
2 *  Copyright 2012 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
13#include "libyuv/cpu_id.h"
14#include "libyuv/rotate.h"
15#include "../unit_test/unit_test.h"
16
17namespace libyuv {
18
19static void I420TestRotate(int src_width, int src_height,
20                           int dst_width, int dst_height,
21                           libyuv::RotationMode mode,
22                           int benchmark_iterations,
23                           int disable_cpu_flags, int benchmark_cpu_info) {
24  if (src_width < 1) {
25    src_width = 1;
26  }
27  if (src_height == 0) {
28    src_height = 1;
29  }
30  if (dst_width < 1) {
31    dst_width = 1;
32  }
33  if (dst_height < 1) {
34    dst_height = 1;
35  }
36  int src_i420_y_size = src_width * Abs(src_height);
37  int src_i420_uv_size = ((src_width + 1) / 2) * ((Abs(src_height) + 1) / 2);
38  int src_i420_size = src_i420_y_size + src_i420_uv_size * 2;
39  align_buffer_page_end(src_i420, src_i420_size);
40  for (int i = 0; i < src_i420_size; ++i) {
41    src_i420[i] = fastrand() & 0xff;
42  }
43
44  int dst_i420_y_size = dst_width * dst_height;
45  int dst_i420_uv_size = ((dst_width + 1) / 2) * ((dst_height + 1) / 2);
46  int dst_i420_size = dst_i420_y_size + dst_i420_uv_size * 2;
47  align_buffer_page_end(dst_i420_c, dst_i420_size);
48  align_buffer_page_end(dst_i420_opt, dst_i420_size);
49  memset(dst_i420_c, 2, dst_i420_size);
50  memset(dst_i420_opt, 3, dst_i420_size);
51
52  MaskCpuFlags(disable_cpu_flags);  // Disable all CPU optimization.
53  I420Rotate(src_i420, src_width,
54             src_i420 + src_i420_y_size, (src_width + 1) / 2,
55             src_i420 + src_i420_y_size + src_i420_uv_size, (src_width + 1) / 2,
56             dst_i420_c, dst_width,
57             dst_i420_c + dst_i420_y_size, (dst_width + 1) / 2,
58             dst_i420_c + dst_i420_y_size + dst_i420_uv_size,
59               (dst_width + 1) / 2,
60             src_width, src_height, mode);
61
62  MaskCpuFlags(benchmark_cpu_info);  // Enable all CPU optimization.
63  for (int i = 0; i < benchmark_iterations; ++i) {
64    I420Rotate(src_i420, src_width,
65               src_i420 + src_i420_y_size, (src_width + 1) / 2,
66               src_i420 + src_i420_y_size + src_i420_uv_size,
67                 (src_width + 1) / 2,
68               dst_i420_opt, dst_width,
69               dst_i420_opt + dst_i420_y_size, (dst_width + 1) / 2,
70               dst_i420_opt + dst_i420_y_size + dst_i420_uv_size,
71                 (dst_width + 1) / 2,
72               src_width, src_height, mode);
73  }
74
75  // Rotation should be exact.
76  for (int i = 0; i < dst_i420_size; ++i) {
77    EXPECT_EQ(dst_i420_c[i], dst_i420_opt[i]);
78  }
79
80  free_aligned_buffer_page_end(dst_i420_c);
81  free_aligned_buffer_page_end(dst_i420_opt);
82  free_aligned_buffer_page_end(src_i420);
83}
84
85TEST_F(LibYUVRotateTest, I420Rotate0_Opt) {
86  I420TestRotate(benchmark_width_, benchmark_height_,
87                 benchmark_width_, benchmark_height_,
88                 kRotate0, benchmark_iterations_,
89                 disable_cpu_flags_, benchmark_cpu_info_);
90}
91
92TEST_F(LibYUVRotateTest, I420Rotate90_Opt) {
93  I420TestRotate(benchmark_width_, benchmark_height_,
94                 benchmark_height_, benchmark_width_,
95                 kRotate90, benchmark_iterations_,
96                 disable_cpu_flags_, benchmark_cpu_info_);
97}
98
99TEST_F(LibYUVRotateTest, I420Rotate180_Opt) {
100  I420TestRotate(benchmark_width_, benchmark_height_,
101                 benchmark_width_, benchmark_height_,
102                 kRotate180, benchmark_iterations_,
103                 disable_cpu_flags_, benchmark_cpu_info_);
104}
105
106TEST_F(LibYUVRotateTest, I420Rotate270_Opt) {
107  I420TestRotate(benchmark_width_, benchmark_height_,
108                 benchmark_height_, benchmark_width_,
109                 kRotate270, benchmark_iterations_,
110                 disable_cpu_flags_, benchmark_cpu_info_);
111}
112
113// TODO(fbarchard): Remove odd width tests.
114// Odd width tests work but disabled because they use C code and can be
115// tested by passing an odd width command line or environment variable.
116TEST_F(LibYUVRotateTest, DISABLED_I420Rotate0_Odd) {
117  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
118                 benchmark_width_ - 3, benchmark_height_ - 1,
119                 kRotate0, benchmark_iterations_,
120                 disable_cpu_flags_, benchmark_cpu_info_);
121}
122
123TEST_F(LibYUVRotateTest, DISABLED_I420Rotate90_Odd) {
124  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
125                 benchmark_height_ - 1, benchmark_width_ - 3,
126                 kRotate90, benchmark_iterations_,
127                 disable_cpu_flags_, benchmark_cpu_info_);
128}
129
130TEST_F(LibYUVRotateTest, DISABLED_I420Rotate180_Odd) {
131  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
132                 benchmark_width_ - 3, benchmark_height_ - 1,
133                 kRotate180, benchmark_iterations_,
134                 disable_cpu_flags_, benchmark_cpu_info_);
135}
136
137TEST_F(LibYUVRotateTest, DISABLED_I420Rotate270_Odd) {
138  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
139                 benchmark_height_ - 1, benchmark_width_ - 3,
140                 kRotate270, benchmark_iterations_,
141                 disable_cpu_flags_, benchmark_cpu_info_);
142}
143
144static void NV12TestRotate(int src_width, int src_height,
145                           int dst_width, int dst_height,
146                           libyuv::RotationMode mode,
147                           int benchmark_iterations,
148                           int disable_cpu_flags, int benchmark_cpu_info) {
149  if (src_width < 1) {
150    src_width = 1;
151  }
152  if (src_height == 0) {  // allow negative for inversion test.
153    src_height = 1;
154  }
155  if (dst_width < 1) {
156    dst_width = 1;
157  }
158  if (dst_height < 1) {
159    dst_height = 1;
160  }
161  int src_nv12_y_size = src_width * Abs(src_height);
162  int src_nv12_uv_size =
163      ((src_width + 1) / 2) * ((Abs(src_height) + 1) / 2) * 2;
164  int src_nv12_size = src_nv12_y_size + src_nv12_uv_size;
165  align_buffer_page_end(src_nv12, src_nv12_size);
166  for (int i = 0; i < src_nv12_size; ++i) {
167    src_nv12[i] = fastrand() & 0xff;
168  }
169
170  int dst_i420_y_size = dst_width * dst_height;
171  int dst_i420_uv_size = ((dst_width + 1) / 2) * ((dst_height + 1) / 2);
172  int dst_i420_size = dst_i420_y_size + dst_i420_uv_size * 2;
173  align_buffer_page_end(dst_i420_c, dst_i420_size);
174  align_buffer_page_end(dst_i420_opt, dst_i420_size);
175  memset(dst_i420_c, 2, dst_i420_size);
176  memset(dst_i420_opt, 3, dst_i420_size);
177
178  MaskCpuFlags(disable_cpu_flags);  // Disable all CPU optimization.
179  NV12ToI420Rotate(src_nv12, src_width,
180                   src_nv12 + src_nv12_y_size, (src_width + 1) & ~1,
181                   dst_i420_c, dst_width,
182                   dst_i420_c + dst_i420_y_size, (dst_width + 1) / 2,
183                   dst_i420_c + dst_i420_y_size + dst_i420_uv_size,
184                     (dst_width + 1) / 2,
185                   src_width, src_height, mode);
186
187  MaskCpuFlags(benchmark_cpu_info);  // Enable all CPU optimization.
188  for (int i = 0; i < benchmark_iterations; ++i) {
189    NV12ToI420Rotate(src_nv12, src_width,
190                     src_nv12 + src_nv12_y_size, (src_width + 1) & ~1,
191                     dst_i420_opt, dst_width,
192                     dst_i420_opt + dst_i420_y_size, (dst_width + 1) / 2,
193                     dst_i420_opt + dst_i420_y_size + dst_i420_uv_size,
194                       (dst_width + 1) / 2,
195                     src_width, src_height, mode);
196  }
197
198  // Rotation should be exact.
199  for (int i = 0; i < dst_i420_size; ++i) {
200    EXPECT_EQ(dst_i420_c[i], dst_i420_opt[i]);
201  }
202
203  free_aligned_buffer_page_end(dst_i420_c);
204  free_aligned_buffer_page_end(dst_i420_opt);
205  free_aligned_buffer_page_end(src_nv12);
206}
207
208TEST_F(LibYUVRotateTest, NV12Rotate0_Opt) {
209  NV12TestRotate(benchmark_width_, benchmark_height_,
210                 benchmark_width_, benchmark_height_,
211                 kRotate0, benchmark_iterations_,
212                 disable_cpu_flags_, benchmark_cpu_info_);
213}
214
215TEST_F(LibYUVRotateTest, NV12Rotate90_Opt) {
216  NV12TestRotate(benchmark_width_, benchmark_height_,
217                 benchmark_height_, benchmark_width_,
218                 kRotate90, benchmark_iterations_,
219                 disable_cpu_flags_, benchmark_cpu_info_);
220}
221
222TEST_F(LibYUVRotateTest, NV12Rotate180_Opt) {
223  NV12TestRotate(benchmark_width_, benchmark_height_,
224                 benchmark_width_, benchmark_height_,
225                 kRotate180, benchmark_iterations_,
226                 disable_cpu_flags_, benchmark_cpu_info_);
227}
228
229TEST_F(LibYUVRotateTest, NV12Rotate270_Opt) {
230  NV12TestRotate(benchmark_width_, benchmark_height_,
231                 benchmark_height_, benchmark_width_,
232                 kRotate270, benchmark_iterations_,
233                 disable_cpu_flags_, benchmark_cpu_info_);
234}
235
236TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate0_Odd) {
237  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
238                 benchmark_width_ - 3, benchmark_height_ - 1,
239                 kRotate0, benchmark_iterations_,
240                 disable_cpu_flags_, benchmark_cpu_info_);
241}
242
243TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate90_Odd) {
244  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
245                 benchmark_height_ - 1, benchmark_width_ - 3,
246                 kRotate90, benchmark_iterations_,
247                 disable_cpu_flags_, benchmark_cpu_info_);
248}
249
250TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate180_Odd) {
251  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
252                 benchmark_width_ - 3, benchmark_height_ - 1,
253                 kRotate180, benchmark_iterations_,
254                 disable_cpu_flags_, benchmark_cpu_info_);
255}
256
257TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate270_Odd) {
258  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
259                 benchmark_height_ - 1, benchmark_width_ - 3,
260                 kRotate270, benchmark_iterations_,
261                 disable_cpu_flags_, benchmark_cpu_info_);
262}
263
264TEST_F(LibYUVRotateTest, NV12Rotate0_Invert) {
265  NV12TestRotate(benchmark_width_, -benchmark_height_,
266                 benchmark_width_, benchmark_height_,
267                 kRotate0, benchmark_iterations_,
268                 disable_cpu_flags_, benchmark_cpu_info_);
269}
270
271TEST_F(LibYUVRotateTest, NV12Rotate90_Invert) {
272  NV12TestRotate(benchmark_width_, -benchmark_height_,
273                 benchmark_height_, benchmark_width_,
274                 kRotate90, benchmark_iterations_,
275                 disable_cpu_flags_, benchmark_cpu_info_);
276}
277
278TEST_F(LibYUVRotateTest, NV12Rotate180_Invert) {
279  NV12TestRotate(benchmark_width_, -benchmark_height_,
280                 benchmark_width_, benchmark_height_,
281                 kRotate180, benchmark_iterations_,
282                 disable_cpu_flags_, benchmark_cpu_info_);
283}
284
285TEST_F(LibYUVRotateTest, NV12Rotate270_Invert) {
286  NV12TestRotate(benchmark_width_, -benchmark_height_,
287                 benchmark_height_, benchmark_width_,
288                 kRotate270, benchmark_iterations_,
289                 disable_cpu_flags_, benchmark_cpu_info_);
290}
291
292
293
294
295
296}  // namespace libyuv
297