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 "../unit_test/unit_test.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/rotate.h"
16
17 namespace libyuv {
18
I420TestRotate(int src_width,int src_height,int dst_width,int dst_height,libyuv::RotationMode mode,int benchmark_iterations,int disable_cpu_flags,int benchmark_cpu_info)19 static void I420TestRotate(int src_width,
20 int src_height,
21 int dst_width,
22 int dst_height,
23 libyuv::RotationMode mode,
24 int benchmark_iterations,
25 int disable_cpu_flags,
26 int benchmark_cpu_info) {
27 if (src_width < 1) {
28 src_width = 1;
29 }
30 if (src_height == 0) {
31 src_height = 1;
32 }
33 if (dst_width < 1) {
34 dst_width = 1;
35 }
36 if (dst_height < 1) {
37 dst_height = 1;
38 }
39 int src_i420_y_size = src_width * Abs(src_height);
40 int src_i420_uv_size = ((src_width + 1) / 2) * ((Abs(src_height) + 1) / 2);
41 int src_i420_size = src_i420_y_size + src_i420_uv_size * 2;
42 align_buffer_page_end(src_i420, src_i420_size);
43 for (int i = 0; i < src_i420_size; ++i) {
44 src_i420[i] = fastrand() & 0xff;
45 }
46
47 int dst_i420_y_size = dst_width * dst_height;
48 int dst_i420_uv_size = ((dst_width + 1) / 2) * ((dst_height + 1) / 2);
49 int dst_i420_size = dst_i420_y_size + dst_i420_uv_size * 2;
50 align_buffer_page_end(dst_i420_c, dst_i420_size);
51 align_buffer_page_end(dst_i420_opt, dst_i420_size);
52 memset(dst_i420_c, 2, dst_i420_size);
53 memset(dst_i420_opt, 3, dst_i420_size);
54
55 MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization.
56 I420Rotate(src_i420, src_width, src_i420 + src_i420_y_size,
57 (src_width + 1) / 2, src_i420 + src_i420_y_size + src_i420_uv_size,
58 (src_width + 1) / 2, dst_i420_c, dst_width,
59 dst_i420_c + dst_i420_y_size, (dst_width + 1) / 2,
60 dst_i420_c + dst_i420_y_size + dst_i420_uv_size,
61 (dst_width + 1) / 2, src_width, src_height, mode);
62
63 MaskCpuFlags(benchmark_cpu_info); // Enable all CPU optimization.
64 for (int i = 0; i < benchmark_iterations; ++i) {
65 I420Rotate(
66 src_i420, src_width, src_i420 + src_i420_y_size, (src_width + 1) / 2,
67 src_i420 + src_i420_y_size + src_i420_uv_size, (src_width + 1) / 2,
68 dst_i420_opt, dst_width, dst_i420_opt + dst_i420_y_size,
69 (dst_width + 1) / 2, dst_i420_opt + dst_i420_y_size + dst_i420_uv_size,
70 (dst_width + 1) / 2, src_width, src_height, mode);
71 }
72
73 // Rotation should be exact.
74 for (int i = 0; i < dst_i420_size; ++i) {
75 EXPECT_EQ(dst_i420_c[i], dst_i420_opt[i]);
76 }
77
78 free_aligned_buffer_page_end(dst_i420_c);
79 free_aligned_buffer_page_end(dst_i420_opt);
80 free_aligned_buffer_page_end(src_i420);
81 }
82
TEST_F(LibYUVRotateTest,I420Rotate0_Opt)83 TEST_F(LibYUVRotateTest, I420Rotate0_Opt) {
84 I420TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
85 benchmark_height_, kRotate0, benchmark_iterations_,
86 disable_cpu_flags_, benchmark_cpu_info_);
87 }
88
TEST_F(LibYUVRotateTest,I420Rotate90_Opt)89 TEST_F(LibYUVRotateTest, I420Rotate90_Opt) {
90 I420TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
91 benchmark_width_, kRotate90, benchmark_iterations_,
92 disable_cpu_flags_, benchmark_cpu_info_);
93 }
94
TEST_F(LibYUVRotateTest,I420Rotate180_Opt)95 TEST_F(LibYUVRotateTest, I420Rotate180_Opt) {
96 I420TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
97 benchmark_height_, kRotate180, benchmark_iterations_,
98 disable_cpu_flags_, benchmark_cpu_info_);
99 }
100
TEST_F(LibYUVRotateTest,I420Rotate270_Opt)101 TEST_F(LibYUVRotateTest, I420Rotate270_Opt) {
102 I420TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
103 benchmark_width_, kRotate270, benchmark_iterations_,
104 disable_cpu_flags_, benchmark_cpu_info_);
105 }
106
107 // TODO(fbarchard): Remove odd width tests.
108 // Odd width tests work but disabled because they use C code and can be
109 // tested by passing an odd width command line or environment variable.
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate0_Odd)110 TEST_F(LibYUVRotateTest, DISABLED_I420Rotate0_Odd) {
111 I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
112 benchmark_width_ - 3, benchmark_height_ - 1, kRotate0,
113 benchmark_iterations_, disable_cpu_flags_,
114 benchmark_cpu_info_);
115 }
116
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate90_Odd)117 TEST_F(LibYUVRotateTest, DISABLED_I420Rotate90_Odd) {
118 I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
119 benchmark_height_ - 1, benchmark_width_ - 3, kRotate90,
120 benchmark_iterations_, disable_cpu_flags_,
121 benchmark_cpu_info_);
122 }
123
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate180_Odd)124 TEST_F(LibYUVRotateTest, DISABLED_I420Rotate180_Odd) {
125 I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
126 benchmark_width_ - 3, benchmark_height_ - 1, kRotate180,
127 benchmark_iterations_, disable_cpu_flags_,
128 benchmark_cpu_info_);
129 }
130
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate270_Odd)131 TEST_F(LibYUVRotateTest, DISABLED_I420Rotate270_Odd) {
132 I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
133 benchmark_height_ - 1, benchmark_width_ - 3, kRotate270,
134 benchmark_iterations_, disable_cpu_flags_,
135 benchmark_cpu_info_);
136 }
137
I444TestRotate(int src_width,int src_height,int dst_width,int dst_height,libyuv::RotationMode mode,int benchmark_iterations,int disable_cpu_flags,int benchmark_cpu_info)138 static void I444TestRotate(int src_width,
139 int src_height,
140 int dst_width,
141 int dst_height,
142 libyuv::RotationMode mode,
143 int benchmark_iterations,
144 int disable_cpu_flags,
145 int benchmark_cpu_info) {
146 if (src_width < 1) {
147 src_width = 1;
148 }
149 if (src_height == 0) {
150 src_height = 1;
151 }
152 if (dst_width < 1) {
153 dst_width = 1;
154 }
155 if (dst_height < 1) {
156 dst_height = 1;
157 }
158 int src_i444_y_size = src_width * Abs(src_height);
159 int src_i444_uv_size = src_width * Abs(src_height);
160 int src_i444_size = src_i444_y_size + src_i444_uv_size * 2;
161 align_buffer_page_end(src_i444, src_i444_size);
162 for (int i = 0; i < src_i444_size; ++i) {
163 src_i444[i] = fastrand() & 0xff;
164 }
165
166 int dst_i444_y_size = dst_width * dst_height;
167 int dst_i444_uv_size = dst_width * dst_height;
168 int dst_i444_size = dst_i444_y_size + dst_i444_uv_size * 2;
169 align_buffer_page_end(dst_i444_c, dst_i444_size);
170 align_buffer_page_end(dst_i444_opt, dst_i444_size);
171 memset(dst_i444_c, 2, dst_i444_size);
172 memset(dst_i444_opt, 3, dst_i444_size);
173
174 MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization.
175 I444Rotate(src_i444, src_width, src_i444 + src_i444_y_size, src_width,
176 src_i444 + src_i444_y_size + src_i444_uv_size, src_width,
177 dst_i444_c, dst_width, dst_i444_c + dst_i444_y_size, dst_width,
178 dst_i444_c + dst_i444_y_size + dst_i444_uv_size, dst_width,
179 src_width, src_height, mode);
180
181 MaskCpuFlags(benchmark_cpu_info); // Enable all CPU optimization.
182 for (int i = 0; i < benchmark_iterations; ++i) {
183 I444Rotate(src_i444, src_width, src_i444 + src_i444_y_size, src_width,
184 src_i444 + src_i444_y_size + src_i444_uv_size, src_width,
185 dst_i444_opt, dst_width, dst_i444_opt + dst_i444_y_size,
186 dst_width, dst_i444_opt + dst_i444_y_size + dst_i444_uv_size,
187 dst_width, src_width, src_height, mode);
188 }
189
190 // Rotation should be exact.
191 for (int i = 0; i < dst_i444_size; ++i) {
192 EXPECT_EQ(dst_i444_c[i], dst_i444_opt[i]);
193 }
194
195 free_aligned_buffer_page_end(dst_i444_c);
196 free_aligned_buffer_page_end(dst_i444_opt);
197 free_aligned_buffer_page_end(src_i444);
198 }
199
TEST_F(LibYUVRotateTest,I444Rotate0_Opt)200 TEST_F(LibYUVRotateTest, I444Rotate0_Opt) {
201 I444TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
202 benchmark_height_, kRotate0, benchmark_iterations_,
203 disable_cpu_flags_, benchmark_cpu_info_);
204 }
205
TEST_F(LibYUVRotateTest,I444Rotate90_Opt)206 TEST_F(LibYUVRotateTest, I444Rotate90_Opt) {
207 I444TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
208 benchmark_width_, kRotate90, benchmark_iterations_,
209 disable_cpu_flags_, benchmark_cpu_info_);
210 }
211
TEST_F(LibYUVRotateTest,I444Rotate180_Opt)212 TEST_F(LibYUVRotateTest, I444Rotate180_Opt) {
213 I444TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
214 benchmark_height_, kRotate180, benchmark_iterations_,
215 disable_cpu_flags_, benchmark_cpu_info_);
216 }
217
TEST_F(LibYUVRotateTest,I444Rotate270_Opt)218 TEST_F(LibYUVRotateTest, I444Rotate270_Opt) {
219 I444TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
220 benchmark_width_, kRotate270, benchmark_iterations_,
221 disable_cpu_flags_, benchmark_cpu_info_);
222 }
223
224 // TODO(fbarchard): Remove odd width tests.
225 // Odd width tests work but disabled because they use C code and can be
226 // tested by passing an odd width command line or environment variable.
TEST_F(LibYUVRotateTest,DISABLED_I444Rotate0_Odd)227 TEST_F(LibYUVRotateTest, DISABLED_I444Rotate0_Odd) {
228 I444TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
229 benchmark_width_ - 3, benchmark_height_ - 1, kRotate0,
230 benchmark_iterations_, disable_cpu_flags_,
231 benchmark_cpu_info_);
232 }
233
TEST_F(LibYUVRotateTest,DISABLED_I444Rotate90_Odd)234 TEST_F(LibYUVRotateTest, DISABLED_I444Rotate90_Odd) {
235 I444TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
236 benchmark_height_ - 1, benchmark_width_ - 3, kRotate90,
237 benchmark_iterations_, disable_cpu_flags_,
238 benchmark_cpu_info_);
239 }
240
TEST_F(LibYUVRotateTest,DISABLED_I444Rotate180_Odd)241 TEST_F(LibYUVRotateTest, DISABLED_I444Rotate180_Odd) {
242 I444TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
243 benchmark_width_ - 3, benchmark_height_ - 1, kRotate180,
244 benchmark_iterations_, disable_cpu_flags_,
245 benchmark_cpu_info_);
246 }
247
TEST_F(LibYUVRotateTest,DISABLED_I444Rotate270_Odd)248 TEST_F(LibYUVRotateTest, DISABLED_I444Rotate270_Odd) {
249 I444TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
250 benchmark_height_ - 1, benchmark_width_ - 3, kRotate270,
251 benchmark_iterations_, disable_cpu_flags_,
252 benchmark_cpu_info_);
253 }
254
NV12TestRotate(int src_width,int src_height,int dst_width,int dst_height,libyuv::RotationMode mode,int benchmark_iterations,int disable_cpu_flags,int benchmark_cpu_info)255 static void NV12TestRotate(int src_width,
256 int src_height,
257 int dst_width,
258 int dst_height,
259 libyuv::RotationMode mode,
260 int benchmark_iterations,
261 int disable_cpu_flags,
262 int benchmark_cpu_info) {
263 if (src_width < 1) {
264 src_width = 1;
265 }
266 if (src_height == 0) { // allow negative for inversion test.
267 src_height = 1;
268 }
269 if (dst_width < 1) {
270 dst_width = 1;
271 }
272 if (dst_height < 1) {
273 dst_height = 1;
274 }
275 int src_nv12_y_size = src_width * Abs(src_height);
276 int src_nv12_uv_size =
277 ((src_width + 1) / 2) * ((Abs(src_height) + 1) / 2) * 2;
278 int src_nv12_size = src_nv12_y_size + src_nv12_uv_size;
279 align_buffer_page_end(src_nv12, src_nv12_size);
280 for (int i = 0; i < src_nv12_size; ++i) {
281 src_nv12[i] = fastrand() & 0xff;
282 }
283
284 int dst_i420_y_size = dst_width * dst_height;
285 int dst_i420_uv_size = ((dst_width + 1) / 2) * ((dst_height + 1) / 2);
286 int dst_i420_size = dst_i420_y_size + dst_i420_uv_size * 2;
287 align_buffer_page_end(dst_i420_c, dst_i420_size);
288 align_buffer_page_end(dst_i420_opt, dst_i420_size);
289 memset(dst_i420_c, 2, dst_i420_size);
290 memset(dst_i420_opt, 3, dst_i420_size);
291
292 MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization.
293 NV12ToI420Rotate(src_nv12, src_width, src_nv12 + src_nv12_y_size,
294 (src_width + 1) & ~1, dst_i420_c, dst_width,
295 dst_i420_c + dst_i420_y_size, (dst_width + 1) / 2,
296 dst_i420_c + dst_i420_y_size + dst_i420_uv_size,
297 (dst_width + 1) / 2, src_width, src_height, mode);
298
299 MaskCpuFlags(benchmark_cpu_info); // Enable all CPU optimization.
300 for (int i = 0; i < benchmark_iterations; ++i) {
301 NV12ToI420Rotate(src_nv12, src_width, src_nv12 + src_nv12_y_size,
302 (src_width + 1) & ~1, dst_i420_opt, dst_width,
303 dst_i420_opt + dst_i420_y_size, (dst_width + 1) / 2,
304 dst_i420_opt + dst_i420_y_size + dst_i420_uv_size,
305 (dst_width + 1) / 2, src_width, src_height, mode);
306 }
307
308 // Rotation should be exact.
309 for (int i = 0; i < dst_i420_size; ++i) {
310 EXPECT_EQ(dst_i420_c[i], dst_i420_opt[i]);
311 }
312
313 free_aligned_buffer_page_end(dst_i420_c);
314 free_aligned_buffer_page_end(dst_i420_opt);
315 free_aligned_buffer_page_end(src_nv12);
316 }
317
TEST_F(LibYUVRotateTest,NV12Rotate0_Opt)318 TEST_F(LibYUVRotateTest, NV12Rotate0_Opt) {
319 NV12TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
320 benchmark_height_, kRotate0, benchmark_iterations_,
321 disable_cpu_flags_, benchmark_cpu_info_);
322 }
323
TEST_F(LibYUVRotateTest,NV12Rotate90_Opt)324 TEST_F(LibYUVRotateTest, NV12Rotate90_Opt) {
325 NV12TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
326 benchmark_width_, kRotate90, benchmark_iterations_,
327 disable_cpu_flags_, benchmark_cpu_info_);
328 }
329
TEST_F(LibYUVRotateTest,NV12Rotate180_Opt)330 TEST_F(LibYUVRotateTest, NV12Rotate180_Opt) {
331 NV12TestRotate(benchmark_width_, benchmark_height_, benchmark_width_,
332 benchmark_height_, kRotate180, benchmark_iterations_,
333 disable_cpu_flags_, benchmark_cpu_info_);
334 }
335
TEST_F(LibYUVRotateTest,NV12Rotate270_Opt)336 TEST_F(LibYUVRotateTest, NV12Rotate270_Opt) {
337 NV12TestRotate(benchmark_width_, benchmark_height_, benchmark_height_,
338 benchmark_width_, kRotate270, benchmark_iterations_,
339 disable_cpu_flags_, benchmark_cpu_info_);
340 }
341
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate0_Odd)342 TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate0_Odd) {
343 NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
344 benchmark_width_ - 3, benchmark_height_ - 1, kRotate0,
345 benchmark_iterations_, disable_cpu_flags_,
346 benchmark_cpu_info_);
347 }
348
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate90_Odd)349 TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate90_Odd) {
350 NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
351 benchmark_height_ - 1, benchmark_width_ - 3, kRotate90,
352 benchmark_iterations_, disable_cpu_flags_,
353 benchmark_cpu_info_);
354 }
355
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate180_Odd)356 TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate180_Odd) {
357 NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
358 benchmark_width_ - 3, benchmark_height_ - 1, kRotate180,
359 benchmark_iterations_, disable_cpu_flags_,
360 benchmark_cpu_info_);
361 }
362
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate270_Odd)363 TEST_F(LibYUVRotateTest, DISABLED_NV12Rotate270_Odd) {
364 NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
365 benchmark_height_ - 1, benchmark_width_ - 3, kRotate270,
366 benchmark_iterations_, disable_cpu_flags_,
367 benchmark_cpu_info_);
368 }
369
TEST_F(LibYUVRotateTest,NV12Rotate0_Invert)370 TEST_F(LibYUVRotateTest, NV12Rotate0_Invert) {
371 NV12TestRotate(benchmark_width_, -benchmark_height_, benchmark_width_,
372 benchmark_height_, kRotate0, benchmark_iterations_,
373 disable_cpu_flags_, benchmark_cpu_info_);
374 }
375
TEST_F(LibYUVRotateTest,NV12Rotate90_Invert)376 TEST_F(LibYUVRotateTest, NV12Rotate90_Invert) {
377 NV12TestRotate(benchmark_width_, -benchmark_height_, benchmark_height_,
378 benchmark_width_, kRotate90, benchmark_iterations_,
379 disable_cpu_flags_, benchmark_cpu_info_);
380 }
381
TEST_F(LibYUVRotateTest,NV12Rotate180_Invert)382 TEST_F(LibYUVRotateTest, NV12Rotate180_Invert) {
383 NV12TestRotate(benchmark_width_, -benchmark_height_, benchmark_width_,
384 benchmark_height_, kRotate180, benchmark_iterations_,
385 disable_cpu_flags_, benchmark_cpu_info_);
386 }
387
TEST_F(LibYUVRotateTest,NV12Rotate270_Invert)388 TEST_F(LibYUVRotateTest, NV12Rotate270_Invert) {
389 NV12TestRotate(benchmark_width_, -benchmark_height_, benchmark_height_,
390 benchmark_width_, kRotate270, benchmark_iterations_,
391 disable_cpu_flags_, benchmark_cpu_info_);
392 }
393
394 } // namespace libyuv
395