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#include <time.h>
13
14#include "libyuv/cpu_id.h"
15#include "libyuv/rotate.h"
16#include "libyuv/row.h"
17#include "../unit_test/unit_test.h"
18
19namespace libyuv {
20
21static void I420TestRotate(int src_width, int src_height,
22                           int dst_width, int dst_height,
23                           libyuv::RotationMode mode,
24                           int benchmark_iterations) {
25  if (src_width < 1) {
26    src_width = 1;
27  }
28  if (src_height < 1) {
29    src_height = 1;
30  }
31  if (dst_width < 1) {
32    dst_width = 1;
33  }
34  if (dst_height < 1) {
35    dst_height = 1;
36  }
37  int src_i420_y_size = src_width * src_height;
38  int src_i420_uv_size = ((src_width + 1) / 2) * ((src_height + 1) / 2);
39  int src_i420_size = src_i420_y_size + src_i420_uv_size * 2;
40  align_buffer_64(src_i420, src_i420_size);
41  for (int i = 0; i < src_i420_size; ++i) {
42    src_i420[i] = random() & 0xff;
43  }
44
45  int dst_i420_y_size = dst_width * dst_height;
46  int dst_i420_uv_size = ((dst_width + 1) / 2) * ((dst_height + 1) / 2);
47  int dst_i420_size = dst_i420_y_size + dst_i420_uv_size * 2;
48  align_buffer_64(dst_i420_c, dst_i420_size);
49  align_buffer_64(dst_i420_opt, dst_i420_size);
50  memset(dst_i420_c, 2, dst_i420_size);
51  memset(dst_i420_opt, 3, dst_i420_size);
52
53  MaskCpuFlags(0);  // Disable all CPU optimization.
54  I420Rotate(src_i420, src_width,
55             src_i420 + src_i420_y_size, (src_width + 1) / 2,
56             src_i420 + src_i420_y_size + src_i420_uv_size, (src_width + 1) / 2,
57             dst_i420_c, dst_width,
58             dst_i420_c + dst_i420_y_size, (dst_width + 1) / 2,
59             dst_i420_c + dst_i420_y_size + dst_i420_uv_size,
60               (dst_width + 1) / 2,
61             src_width, src_height, mode);
62
63  MaskCpuFlags(-1);  // Enable all CPU optimization.
64  for (int i = 0; i < benchmark_iterations; ++i) {
65    I420Rotate(src_i420, src_width,
66               src_i420 + src_i420_y_size, (src_width + 1) / 2,
67               src_i420 + src_i420_y_size + src_i420_uv_size,
68                 (src_width + 1) / 2,
69               dst_i420_opt, dst_width,
70               dst_i420_opt + dst_i420_y_size, (dst_width + 1) / 2,
71               dst_i420_opt + dst_i420_y_size + dst_i420_uv_size,
72                 (dst_width + 1) / 2,
73               src_width, src_height, mode);
74  }
75
76  // Rotation should be exact.
77  for (int i = 0; i < dst_i420_size; ++i) {
78    EXPECT_EQ(dst_i420_c[i], dst_i420_opt[i]);
79  }
80
81  free_aligned_buffer_64(dst_i420_c);
82  free_aligned_buffer_64(dst_i420_opt);
83  free_aligned_buffer_64(src_i420);
84}
85
86TEST_F(libyuvTest, I420Rotate0) {
87  I420TestRotate(benchmark_width_, benchmark_height_,
88                 benchmark_width_, benchmark_height_,
89                 kRotate0, benchmark_iterations_);
90}
91
92TEST_F(libyuvTest, I420Rotate90) {
93  I420TestRotate(benchmark_width_, benchmark_height_,
94                 benchmark_height_, benchmark_width_,
95                 kRotate90, benchmark_iterations_);
96}
97
98TEST_F(libyuvTest, I420Rotate180) {
99  I420TestRotate(benchmark_width_, benchmark_height_,
100                 benchmark_width_, benchmark_height_,
101                 kRotate180, benchmark_iterations_);
102}
103
104TEST_F(libyuvTest, I420Rotate270) {
105  I420TestRotate(benchmark_width_, benchmark_height_,
106                 benchmark_height_, benchmark_width_,
107                 kRotate270, benchmark_iterations_);
108}
109
110TEST_F(libyuvTest, I420Rotate0_Odd) {
111  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
112                 benchmark_width_ - 3, benchmark_height_ - 1,
113                 kRotate0, benchmark_iterations_);
114}
115
116TEST_F(libyuvTest, I420Rotate90_Odd) {
117  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
118                 benchmark_height_ - 1, benchmark_width_ - 3,
119                 kRotate90, benchmark_iterations_);
120}
121
122TEST_F(libyuvTest, I420Rotate180_Odd) {
123  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
124                 benchmark_width_ - 3, benchmark_height_ - 1,
125                 kRotate180, benchmark_iterations_);
126}
127
128TEST_F(libyuvTest, I420Rotate270_Odd) {
129  I420TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
130                 benchmark_height_ - 1, benchmark_width_ - 3,
131                 kRotate270, benchmark_iterations_);
132}
133
134static void NV12TestRotate(int src_width, int src_height,
135                           int dst_width, int dst_height,
136                           libyuv::RotationMode mode,
137                           int benchmark_iterations) {
138  if (src_width < 1) {
139    src_width = 1;
140  }
141  if (src_height < 1) {
142    src_height = 1;
143  }
144  if (dst_width < 1) {
145    dst_width = 1;
146  }
147  if (dst_height < 1) {
148    dst_height = 1;
149  }
150  int src_nv12_y_size = src_width * src_height;
151  int src_nv12_uv_size = ((src_width + 1) / 2) * ((src_height + 1) / 2) * 2;
152  int src_nv12_size = src_nv12_y_size + src_nv12_uv_size;
153  align_buffer_64(src_nv12, src_nv12_size);
154  for (int i = 0; i < src_nv12_size; ++i) {
155    src_nv12[i] = random() & 0xff;
156  }
157
158  int dst_i420_y_size = dst_width * dst_height;
159  int dst_i420_uv_size = ((dst_width + 1) / 2) * ((dst_height + 1) / 2);
160  int dst_i420_size = dst_i420_y_size + dst_i420_uv_size * 2;
161  align_buffer_64(dst_i420_c, dst_i420_size);
162  align_buffer_64(dst_i420_opt, dst_i420_size);
163  memset(dst_i420_c, 2, dst_i420_size);
164  memset(dst_i420_opt, 3, dst_i420_size);
165
166  MaskCpuFlags(0);  // Disable all CPU optimization.
167  NV12ToI420Rotate(src_nv12, src_width,
168                   src_nv12 + src_nv12_y_size, (src_width + 1) & ~1,
169                   dst_i420_c, dst_width,
170                   dst_i420_c + dst_i420_y_size, (dst_width + 1) / 2,
171                   dst_i420_c + dst_i420_y_size + dst_i420_uv_size,
172                     (dst_width + 1) / 2,
173                   src_width, src_height, mode);
174
175  MaskCpuFlags(-1);  // Enable all CPU optimization.
176  for (int i = 0; i < benchmark_iterations; ++i) {
177    NV12ToI420Rotate(src_nv12, src_width,
178                     src_nv12 + src_nv12_y_size, (src_width + 1) & ~1,
179                     dst_i420_opt, dst_width,
180                     dst_i420_opt + dst_i420_y_size, (dst_width + 1) / 2,
181                     dst_i420_opt + dst_i420_y_size + dst_i420_uv_size,
182                       (dst_width + 1) / 2,
183                     src_width, src_height, mode);
184  }
185
186  // Rotation should be exact.
187  for (int i = 0; i < dst_i420_size; ++i) {
188    EXPECT_EQ(dst_i420_c[i], dst_i420_opt[i]);
189  }
190
191  free_aligned_buffer_64(dst_i420_c);
192  free_aligned_buffer_64(dst_i420_opt);
193  free_aligned_buffer_64(src_nv12);
194}
195
196TEST_F(libyuvTest, NV12Rotate0) {
197  NV12TestRotate(benchmark_width_, benchmark_height_,
198                 benchmark_width_, benchmark_height_,
199                 kRotate0, benchmark_iterations_);
200}
201
202TEST_F(libyuvTest, NV12Rotate90) {
203  NV12TestRotate(benchmark_width_, benchmark_height_,
204                 benchmark_height_, benchmark_width_,
205                 kRotate90, benchmark_iterations_);
206}
207
208TEST_F(libyuvTest, NV12Rotate180) {
209  NV12TestRotate(benchmark_width_, benchmark_height_,
210                 benchmark_width_, benchmark_height_,
211                 kRotate180, benchmark_iterations_);
212}
213
214TEST_F(libyuvTest, NV12Rotate270) {
215  NV12TestRotate(benchmark_width_, benchmark_height_,
216                 benchmark_height_, benchmark_width_,
217                 kRotate270, benchmark_iterations_);
218}
219
220TEST_F(libyuvTest, NV12Rotate0_Odd) {
221  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
222                 benchmark_width_ - 3, benchmark_height_ - 1,
223                 kRotate0, benchmark_iterations_);
224}
225
226TEST_F(libyuvTest, NV12Rotate90_Odd) {
227  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
228                 benchmark_height_ - 1, benchmark_width_ - 3,
229                 kRotate90, benchmark_iterations_);
230}
231
232TEST_F(libyuvTest, NV12Rotate180_Odd) {
233  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
234                 benchmark_width_ - 3, benchmark_height_ - 1,
235                 kRotate180, benchmark_iterations_);
236}
237
238TEST_F(libyuvTest, NV12Rotate270_Odd) {
239  NV12TestRotate(benchmark_width_ - 3, benchmark_height_ - 1,
240                 benchmark_height_ - 1, benchmark_width_ - 3,
241                 kRotate270, benchmark_iterations_);
242}
243
244}  // namespace libyuv
245