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
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, 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
TEST_F(LibYUVRotateTest,I420Rotate0_Opt)85 TEST_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
TEST_F(LibYUVRotateTest,I420Rotate90_Opt)92 TEST_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
TEST_F(LibYUVRotateTest,I420Rotate180_Opt)99 TEST_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
TEST_F(LibYUVRotateTest,I420Rotate270_Opt)106 TEST_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.
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate0_Odd)116 TEST_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
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate90_Odd)123 TEST_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
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate180_Odd)130 TEST_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
TEST_F(LibYUVRotateTest,DISABLED_I420Rotate270_Odd)137 TEST_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
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)144 static 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
TEST_F(LibYUVRotateTest,NV12Rotate0_Opt)208 TEST_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
TEST_F(LibYUVRotateTest,NV12Rotate90_Opt)215 TEST_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
TEST_F(LibYUVRotateTest,NV12Rotate180_Opt)222 TEST_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
TEST_F(LibYUVRotateTest,NV12Rotate270_Opt)229 TEST_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
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate0_Odd)236 TEST_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
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate90_Odd)243 TEST_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
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate180_Odd)250 TEST_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
TEST_F(LibYUVRotateTest,DISABLED_NV12Rotate270_Odd)257 TEST_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
TEST_F(LibYUVRotateTest,NV12Rotate0_Invert)264 TEST_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
TEST_F(LibYUVRotateTest,NV12Rotate90_Invert)271 TEST_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
TEST_F(LibYUVRotateTest,NV12Rotate180_Invert)278 TEST_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
TEST_F(LibYUVRotateTest,NV12Rotate270_Invert)285 TEST_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