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 <assert.h>
12 #include <stdlib.h>
13 #include <time.h>
14
15 #include "libyuv/row.h" /* For ARGBToAR30Row_AVX2 */
16
17 #include "libyuv/basic_types.h"
18 #include "libyuv/compare.h"
19 #include "libyuv/convert.h"
20 #include "libyuv/convert_argb.h"
21 #include "libyuv/convert_from.h"
22 #include "libyuv/convert_from_argb.h"
23 #include "libyuv/cpu_id.h"
24 #ifdef HAVE_JPEG
25 #include "libyuv/mjpeg_decoder.h"
26 #endif
27 #include "../unit_test/unit_test.h"
28 #include "libyuv/planar_functions.h"
29 #include "libyuv/rotate.h"
30 #include "libyuv/video_common.h"
31
32 #if defined(__arm__) || defined(__aarch64__)
33 // arm version subsamples by summing 4 pixels then multiplying by matrix with
34 // 4x smaller coefficients which are rounded to nearest integer.
35 #define ARM_YUV_ERROR 4
36 #else
37 #define ARM_YUV_ERROR 0
38 #endif
39
40 namespace libyuv {
41
42 // Alias to copy pixels as is
43 #define AR30ToAR30 ARGBCopy
44 #define ABGRToABGR ARGBCopy
45
46 #define SUBSAMPLE(v, a) ((((v) + (a)-1)) / (a))
47
48 // Planar test
49
50 #define TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, \
51 SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC, \
52 DST_SUBSAMP_X, DST_SUBSAMP_Y, W1280, N, NEG, OFF) \
53 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) { \
54 static_assert(SRC_BPC == 1 || SRC_BPC == 2, "SRC BPC unsupported"); \
55 static_assert(DST_BPC == 1 || DST_BPC == 2, "DST BPC unsupported"); \
56 static_assert(SRC_SUBSAMP_X == 1 || SRC_SUBSAMP_X == 2, \
57 "DST SRC_SUBSAMP_X unsupported"); \
58 static_assert(SRC_SUBSAMP_Y == 1 || SRC_SUBSAMP_Y == 2, \
59 "DST SRC_SUBSAMP_Y unsupported"); \
60 static_assert(DST_SUBSAMP_X == 1 || DST_SUBSAMP_X == 2, \
61 "DST DST_SUBSAMP_X unsupported"); \
62 static_assert(DST_SUBSAMP_Y == 1 || DST_SUBSAMP_Y == 2, \
63 "DST DST_SUBSAMP_Y unsupported"); \
64 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
65 const int kHeight = benchmark_height_; \
66 const int kSrcHalfWidth = SUBSAMPLE(kWidth, SRC_SUBSAMP_X); \
67 const int kSrcHalfHeight = SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); \
68 const int kDstHalfWidth = SUBSAMPLE(kWidth, DST_SUBSAMP_X); \
69 const int kDstHalfHeight = SUBSAMPLE(kHeight, DST_SUBSAMP_Y); \
70 align_buffer_page_end(src_y, kWidth* kHeight* SRC_BPC + OFF); \
71 align_buffer_page_end(src_u, \
72 kSrcHalfWidth* kSrcHalfHeight* SRC_BPC + OFF); \
73 align_buffer_page_end(src_v, \
74 kSrcHalfWidth* kSrcHalfHeight* SRC_BPC + OFF); \
75 align_buffer_page_end(dst_y_c, kWidth* kHeight* DST_BPC); \
76 align_buffer_page_end(dst_u_c, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
77 align_buffer_page_end(dst_v_c, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
78 align_buffer_page_end(dst_y_opt, kWidth* kHeight* DST_BPC); \
79 align_buffer_page_end(dst_u_opt, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
80 align_buffer_page_end(dst_v_opt, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
81 MemRandomize(src_y + OFF, kWidth * kHeight * SRC_BPC); \
82 MemRandomize(src_u + OFF, kSrcHalfWidth * kSrcHalfHeight * SRC_BPC); \
83 MemRandomize(src_v + OFF, kSrcHalfWidth * kSrcHalfHeight * SRC_BPC); \
84 memset(dst_y_c, 1, kWidth* kHeight* DST_BPC); \
85 memset(dst_u_c, 2, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
86 memset(dst_v_c, 3, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
87 memset(dst_y_opt, 101, kWidth* kHeight* DST_BPC); \
88 memset(dst_u_opt, 102, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
89 memset(dst_v_opt, 103, kDstHalfWidth* kDstHalfHeight* DST_BPC); \
90 MaskCpuFlags(disable_cpu_flags_); \
91 SRC_FMT_PLANAR##To##FMT_PLANAR( \
92 reinterpret_cast<SRC_T*>(src_y + OFF), kWidth, \
93 reinterpret_cast<SRC_T*>(src_u + OFF), kSrcHalfWidth, \
94 reinterpret_cast<SRC_T*>(src_v + OFF), kSrcHalfWidth, \
95 reinterpret_cast<DST_T*>(dst_y_c), kWidth, \
96 reinterpret_cast<DST_T*>(dst_u_c), kDstHalfWidth, \
97 reinterpret_cast<DST_T*>(dst_v_c), kDstHalfWidth, kWidth, \
98 NEG kHeight); \
99 MaskCpuFlags(benchmark_cpu_info_); \
100 for (int i = 0; i < benchmark_iterations_; ++i) { \
101 SRC_FMT_PLANAR##To##FMT_PLANAR( \
102 reinterpret_cast<SRC_T*>(src_y + OFF), kWidth, \
103 reinterpret_cast<SRC_T*>(src_u + OFF), kSrcHalfWidth, \
104 reinterpret_cast<SRC_T*>(src_v + OFF), kSrcHalfWidth, \
105 reinterpret_cast<DST_T*>(dst_y_opt), kWidth, \
106 reinterpret_cast<DST_T*>(dst_u_opt), kDstHalfWidth, \
107 reinterpret_cast<DST_T*>(dst_v_opt), kDstHalfWidth, kWidth, \
108 NEG kHeight); \
109 } \
110 for (int i = 0; i < kHeight * kWidth * DST_BPC; ++i) { \
111 EXPECT_EQ(dst_y_c[i], dst_y_opt[i]); \
112 } \
113 for (int i = 0; i < kDstHalfWidth * kDstHalfHeight * DST_BPC; ++i) { \
114 EXPECT_EQ(dst_u_c[i], dst_u_opt[i]); \
115 EXPECT_EQ(dst_v_c[i], dst_v_opt[i]); \
116 } \
117 free_aligned_buffer_page_end(dst_y_c); \
118 free_aligned_buffer_page_end(dst_u_c); \
119 free_aligned_buffer_page_end(dst_v_c); \
120 free_aligned_buffer_page_end(dst_y_opt); \
121 free_aligned_buffer_page_end(dst_u_opt); \
122 free_aligned_buffer_page_end(dst_v_opt); \
123 free_aligned_buffer_page_end(src_y); \
124 free_aligned_buffer_page_end(src_u); \
125 free_aligned_buffer_page_end(src_v); \
126 }
127
128 #define TESTPLANARTOP(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, \
129 SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC, \
130 DST_SUBSAMP_X, DST_SUBSAMP_Y) \
131 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
132 FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \
133 benchmark_width_ - 4, _Any, +, 0) \
134 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
135 FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \
136 benchmark_width_, _Unaligned, +, 1) \
137 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
138 FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \
139 benchmark_width_, _Invert, -, 0) \
140 TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
141 FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \
142 benchmark_width_, _Opt, +, 0)
143
144 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I420, uint8_t, 1, 2, 2)
145 TESTPLANARTOP(I422, uint8_t, 1, 2, 1, I420, uint8_t, 1, 2, 2)
146 TESTPLANARTOP(I444, uint8_t, 1, 1, 1, I420, uint8_t, 1, 2, 2)
147 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I422, uint8_t, 1, 2, 1)
148 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I444, uint8_t, 1, 1, 1)
149 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I420Mirror, uint8_t, 1, 2, 2)
150 TESTPLANARTOP(I422, uint8_t, 1, 2, 1, I422, uint8_t, 1, 2, 1)
151 TESTPLANARTOP(I444, uint8_t, 1, 1, 1, I444, uint8_t, 1, 1, 1)
152 TESTPLANARTOP(I010, uint16_t, 2, 2, 2, I010, uint16_t, 2, 2, 2)
153 TESTPLANARTOP(I010, uint16_t, 2, 2, 2, I420, uint8_t, 1, 2, 2)
154 TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I010, uint16_t, 2, 2, 2)
155 TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H010, uint16_t, 2, 2, 2)
156 TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H420, uint8_t, 1, 2, 2)
157 TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2)
158
159 // Test Android 420 to I420
160 #define TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, \
161 SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
162 W1280, N, NEG, OFF, PN, OFF_U, OFF_V) \
163 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##_##PN##N) { \
164 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
165 const int kHeight = benchmark_height_; \
166 const int kSizeUV = \
167 SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); \
168 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
169 align_buffer_page_end(src_uv, \
170 kSizeUV*((PIXEL_STRIDE == 3) ? 3 : 2) + OFF); \
171 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
172 align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
173 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
174 align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
175 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
176 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
177 align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
178 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
179 align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
180 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
181 uint8_t* src_u = src_uv + OFF_U; \
182 uint8_t* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUV : OFF_V); \
183 int src_stride_uv = SUBSAMPLE(kWidth, SUBSAMP_X) * PIXEL_STRIDE; \
184 for (int i = 0; i < kHeight; ++i) \
185 for (int j = 0; j < kWidth; ++j) \
186 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
187 for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \
188 for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \
189 src_u[(i * src_stride_uv) + j * PIXEL_STRIDE + OFF] = \
190 (fastrand() & 0xff); \
191 src_v[(i * src_stride_uv) + j * PIXEL_STRIDE + OFF] = \
192 (fastrand() & 0xff); \
193 } \
194 } \
195 memset(dst_y_c, 1, kWidth* kHeight); \
196 memset(dst_u_c, 2, \
197 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
198 memset(dst_v_c, 3, \
199 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
200 memset(dst_y_opt, 101, kWidth* kHeight); \
201 memset(dst_u_opt, 102, \
202 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
203 memset(dst_v_opt, 103, \
204 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
205 MaskCpuFlags(disable_cpu_flags_); \
206 SRC_FMT_PLANAR##To##FMT_PLANAR( \
207 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
208 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE, dst_y_c, \
209 kWidth, dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c, \
210 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
211 MaskCpuFlags(benchmark_cpu_info_); \
212 for (int i = 0; i < benchmark_iterations_; ++i) { \
213 SRC_FMT_PLANAR##To##FMT_PLANAR( \
214 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
215 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), PIXEL_STRIDE, \
216 dst_y_opt, kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), \
217 dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
218 } \
219 int max_diff = 0; \
220 for (int i = 0; i < kHeight; ++i) { \
221 for (int j = 0; j < kWidth; ++j) { \
222 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
223 static_cast<int>(dst_y_opt[i * kWidth + j])); \
224 if (abs_diff > max_diff) { \
225 max_diff = abs_diff; \
226 } \
227 } \
228 } \
229 EXPECT_EQ(0, max_diff); \
230 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
231 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
232 int abs_diff = abs( \
233 static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
234 static_cast<int>( \
235 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
236 if (abs_diff > max_diff) { \
237 max_diff = abs_diff; \
238 } \
239 } \
240 } \
241 EXPECT_LE(max_diff, 3); \
242 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
243 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
244 int abs_diff = abs( \
245 static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
246 static_cast<int>( \
247 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
248 if (abs_diff > max_diff) { \
249 max_diff = abs_diff; \
250 } \
251 } \
252 } \
253 EXPECT_LE(max_diff, 3); \
254 free_aligned_buffer_page_end(dst_y_c); \
255 free_aligned_buffer_page_end(dst_u_c); \
256 free_aligned_buffer_page_end(dst_v_c); \
257 free_aligned_buffer_page_end(dst_y_opt); \
258 free_aligned_buffer_page_end(dst_u_opt); \
259 free_aligned_buffer_page_end(dst_v_opt); \
260 free_aligned_buffer_page_end(src_y); \
261 free_aligned_buffer_page_end(src_uv); \
262 }
263
264 #define TESTAPLANARTOP(SRC_FMT_PLANAR, PN, PIXEL_STRIDE, OFF_U, OFF_V, \
265 SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, SUBSAMP_X, \
266 SUBSAMP_Y) \
267 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
268 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, \
269 _Any, +, 0, PN, OFF_U, OFF_V) \
270 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
271 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, \
272 _Unaligned, +, 1, PN, OFF_U, OFF_V) \
273 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
274 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, \
275 -, 0, PN, OFF_U, OFF_V) \
276 TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
277 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, \
278 0, PN, OFF_U, OFF_V)
279
280 TESTAPLANARTOP(Android420, I420, 1, 0, 0, 2, 2, I420, 2, 2)
281 TESTAPLANARTOP(Android420, NV12, 2, 0, 1, 2, 2, I420, 2, 2)
282 TESTAPLANARTOP(Android420, NV21, 2, 1, 0, 2, 2, I420, 2, 2)
283
284 #define TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
285 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \
286 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) { \
287 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
288 const int kHeight = benchmark_height_; \
289 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
290 align_buffer_page_end(src_u, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
291 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
292 OFF); \
293 align_buffer_page_end(src_v, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
294 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
295 OFF); \
296 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
297 align_buffer_page_end(dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X) * \
298 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
299 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
300 align_buffer_page_end(dst_uv_opt, SUBSAMPLE(kWidth * 2, SUBSAMP_X) * \
301 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
302 for (int i = 0; i < kHeight; ++i) \
303 for (int j = 0; j < kWidth; ++j) \
304 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
305 for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \
306 for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \
307 src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
308 (fastrand() & 0xff); \
309 src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
310 (fastrand() & 0xff); \
311 } \
312 } \
313 memset(dst_y_c, 1, kWidth* kHeight); \
314 memset(dst_uv_c, 2, \
315 SUBSAMPLE(kWidth * 2, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
316 memset(dst_y_opt, 101, kWidth* kHeight); \
317 memset(dst_uv_opt, 102, \
318 SUBSAMPLE(kWidth * 2, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
319 MaskCpuFlags(disable_cpu_flags_); \
320 SRC_FMT_PLANAR##To##FMT_PLANAR( \
321 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
322 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_c, kWidth, \
323 dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X), kWidth, NEG kHeight); \
324 MaskCpuFlags(benchmark_cpu_info_); \
325 for (int i = 0; i < benchmark_iterations_; ++i) { \
326 SRC_FMT_PLANAR##To##FMT_PLANAR( \
327 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \
328 src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_opt, kWidth, \
329 dst_uv_opt, SUBSAMPLE(kWidth * 2, SUBSAMP_X), kWidth, NEG kHeight); \
330 } \
331 int max_diff = 0; \
332 for (int i = 0; i < kHeight; ++i) { \
333 for (int j = 0; j < kWidth; ++j) { \
334 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
335 static_cast<int>(dst_y_opt[i * kWidth + j])); \
336 if (abs_diff > max_diff) { \
337 max_diff = abs_diff; \
338 } \
339 } \
340 } \
341 EXPECT_LE(max_diff, 1); \
342 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
343 for (int j = 0; j < SUBSAMPLE(kWidth * 2, SUBSAMP_X); ++j) { \
344 int abs_diff = \
345 abs(static_cast<int>( \
346 dst_uv_c[i * SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j]) - \
347 static_cast<int>( \
348 dst_uv_opt[i * SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j])); \
349 if (abs_diff > max_diff) { \
350 max_diff = abs_diff; \
351 } \
352 } \
353 } \
354 EXPECT_LE(max_diff, 1); \
355 free_aligned_buffer_page_end(dst_y_c); \
356 free_aligned_buffer_page_end(dst_uv_c); \
357 free_aligned_buffer_page_end(dst_y_opt); \
358 free_aligned_buffer_page_end(dst_uv_opt); \
359 free_aligned_buffer_page_end(src_y); \
360 free_aligned_buffer_page_end(src_u); \
361 free_aligned_buffer_page_end(src_v); \
362 }
363
364 #define TESTPLANARTOBP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
365 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
366 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
367 SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0) \
368 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
369 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1) \
370 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
371 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0) \
372 TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
373 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0)
374
375 TESTPLANARTOBP(I420, 2, 2, NV12, 2, 2)
376 TESTPLANARTOBP(I420, 2, 2, NV21, 2, 2)
377
378 #define TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
379 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF, \
380 DOY) \
381 TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) { \
382 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
383 const int kHeight = benchmark_height_; \
384 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
385 align_buffer_page_end(src_uv, 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \
386 SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \
387 OFF); \
388 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
389 align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
390 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
391 align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \
392 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
393 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
394 align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
395 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
396 align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \
397 SUBSAMPLE(kHeight, SUBSAMP_Y)); \
398 for (int i = 0; i < kHeight; ++i) \
399 for (int j = 0; j < kWidth; ++j) \
400 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
401 for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \
402 for (int j = 0; j < 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \
403 src_uv[(i * 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \
404 (fastrand() & 0xff); \
405 } \
406 } \
407 memset(dst_y_c, 1, kWidth* kHeight); \
408 memset(dst_u_c, 2, \
409 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
410 memset(dst_v_c, 3, \
411 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
412 memset(dst_y_opt, 101, kWidth* kHeight); \
413 memset(dst_u_opt, 102, \
414 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
415 memset(dst_v_opt, 103, \
416 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
417 MaskCpuFlags(disable_cpu_flags_); \
418 SRC_FMT_PLANAR##To##FMT_PLANAR( \
419 src_y + OFF, kWidth, src_uv + OFF, \
420 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_c : NULL, kWidth, \
421 dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c, \
422 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
423 MaskCpuFlags(benchmark_cpu_info_); \
424 for (int i = 0; i < benchmark_iterations_; ++i) { \
425 SRC_FMT_PLANAR##To##FMT_PLANAR( \
426 src_y + OFF, kWidth, src_uv + OFF, \
427 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X), DOY ? dst_y_opt : NULL, \
428 kWidth, dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_opt, \
429 SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \
430 } \
431 int max_diff = 0; \
432 if (DOY) { \
433 for (int i = 0; i < kHeight; ++i) { \
434 for (int j = 0; j < kWidth; ++j) { \
435 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
436 static_cast<int>(dst_y_opt[i * kWidth + j])); \
437 if (abs_diff > max_diff) { \
438 max_diff = abs_diff; \
439 } \
440 } \
441 } \
442 EXPECT_LE(max_diff, 1); \
443 } \
444 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
445 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
446 int abs_diff = abs( \
447 static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
448 static_cast<int>( \
449 dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
450 if (abs_diff > max_diff) { \
451 max_diff = abs_diff; \
452 } \
453 } \
454 } \
455 EXPECT_LE(max_diff, 1); \
456 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
457 for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \
458 int abs_diff = abs( \
459 static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \
460 static_cast<int>( \
461 dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \
462 if (abs_diff > max_diff) { \
463 max_diff = abs_diff; \
464 } \
465 } \
466 } \
467 EXPECT_LE(max_diff, 1); \
468 free_aligned_buffer_page_end(dst_y_c); \
469 free_aligned_buffer_page_end(dst_u_c); \
470 free_aligned_buffer_page_end(dst_v_c); \
471 free_aligned_buffer_page_end(dst_y_opt); \
472 free_aligned_buffer_page_end(dst_u_opt); \
473 free_aligned_buffer_page_end(dst_v_opt); \
474 free_aligned_buffer_page_end(src_y); \
475 free_aligned_buffer_page_end(src_uv); \
476 }
477
478 #define TESTBIPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \
479 FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
480 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
481 SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0, 1) \
482 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
483 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1, \
484 1) \
485 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
486 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0, 1) \
487 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
488 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0, 1) \
489 TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \
490 SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _NullY, +, 0, 0)
491
492 TESTBIPLANARTOP(NV12, 2, 2, I420, 2, 2)
493 TESTBIPLANARTOP(NV21, 2, 2, I420, 2, 2)
494
495 #define ALIGNINT(V, ALIGN) (((V) + (ALIGN)-1) / (ALIGN) * (ALIGN))
496
497 #define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
498 YALIGN, W1280, N, NEG, OFF) \
499 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \
500 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
501 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
502 const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \
503 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
504 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
505 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
506 align_buffer_page_end(src_u, kSizeUV + OFF); \
507 align_buffer_page_end(src_v, kSizeUV + OFF); \
508 align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \
509 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \
510 for (int i = 0; i < kWidth * kHeight; ++i) { \
511 src_y[i + OFF] = (fastrand() & 0xff); \
512 } \
513 for (int i = 0; i < kSizeUV; ++i) { \
514 src_u[i + OFF] = (fastrand() & 0xff); \
515 src_v[i + OFF] = (fastrand() & 0xff); \
516 } \
517 memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \
518 memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \
519 MaskCpuFlags(disable_cpu_flags_); \
520 double time0 = get_time(); \
521 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
522 src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideB, \
523 kWidth, NEG kHeight); \
524 double time1 = get_time(); \
525 MaskCpuFlags(benchmark_cpu_info_); \
526 for (int i = 0; i < benchmark_iterations_; ++i) { \
527 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
528 src_v + OFF, kStrideUV, dst_argb_opt + OFF, \
529 kStrideB, kWidth, NEG kHeight); \
530 } \
531 double time2 = get_time(); \
532 printf(" %8d us C - %8d us OPT\n", \
533 static_cast<int>((time1 - time0) * 1e6), \
534 static_cast<int>((time2 - time1) * 1e6 / benchmark_iterations_)); \
535 for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) { \
536 EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_opt[i + OFF]); \
537 } \
538 free_aligned_buffer_page_end(src_y); \
539 free_aligned_buffer_page_end(src_u); \
540 free_aligned_buffer_page_end(src_v); \
541 free_aligned_buffer_page_end(dst_argb_c); \
542 free_aligned_buffer_page_end(dst_argb_opt); \
543 }
544
545 #define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
546 YALIGN) \
547 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
548 YALIGN, benchmark_width_ - 4, _Any, +, 0) \
549 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
550 YALIGN, benchmark_width_, _Unaligned, +, 1) \
551 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
552 YALIGN, benchmark_width_, _Invert, -, 0) \
553 TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
554 YALIGN, benchmark_width_, _Opt, +, 0)
555
556 TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1)
557 TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1)
558 TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1)
559 TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1)
560 TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1)
561 TESTPLANARTOB(I420, 2, 2, BGRA, 4, 4, 1)
562 TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1)
563 TESTPLANARTOB(I420, 2, 2, RGBA, 4, 4, 1)
564 TESTPLANARTOB(I420, 2, 2, RAW, 3, 3, 1)
565 TESTPLANARTOB(I420, 2, 2, RGB24, 3, 3, 1)
566 TESTPLANARTOB(H420, 2, 2, RAW, 3, 3, 1)
567 TESTPLANARTOB(H420, 2, 2, RGB24, 3, 3, 1)
568 TESTPLANARTOB(I420, 2, 2, RGB565, 2, 2, 1)
569 TESTPLANARTOB(I420, 2, 2, ARGB1555, 2, 2, 1)
570 TESTPLANARTOB(I420, 2, 2, ARGB4444, 2, 2, 1)
571 TESTPLANARTOB(I422, 2, 1, ARGB, 4, 4, 1)
572 TESTPLANARTOB(I422, 2, 1, RGB565, 2, 2, 1)
573 TESTPLANARTOB(J422, 2, 1, ARGB, 4, 4, 1)
574 TESTPLANARTOB(J422, 2, 1, ABGR, 4, 4, 1)
575 TESTPLANARTOB(H422, 2, 1, ARGB, 4, 4, 1)
576 TESTPLANARTOB(H422, 2, 1, ABGR, 4, 4, 1)
577 TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1)
578 TESTPLANARTOB(I422, 2, 1, ABGR, 4, 4, 1)
579 TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1)
580 TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1)
581 TESTPLANARTOB(J444, 1, 1, ARGB, 4, 4, 1)
582 TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1)
583 TESTPLANARTOB(I420, 2, 2, YUY2, 2, 4, 1)
584 TESTPLANARTOB(I420, 2, 2, UYVY, 2, 4, 1)
585 TESTPLANARTOB(I422, 2, 1, YUY2, 2, 4, 1)
586 TESTPLANARTOB(I422, 2, 1, UYVY, 2, 4, 1)
587 TESTPLANARTOB(I420, 2, 2, I400, 1, 1, 1)
588 TESTPLANARTOB(J420, 2, 2, J400, 1, 1, 1)
589 TESTPLANARTOB(I420, 2, 2, AR30, 4, 4, 1)
590 TESTPLANARTOB(H420, 2, 2, AR30, 4, 4, 1)
591
592 #define TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
593 YALIGN, W1280, DIFF, N, NEG, OFF, ATTEN) \
594 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \
595 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
596 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
597 const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \
598 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
599 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
600 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
601 align_buffer_page_end(src_u, kSizeUV + OFF); \
602 align_buffer_page_end(src_v, kSizeUV + OFF); \
603 align_buffer_page_end(src_a, kWidth* kHeight + OFF); \
604 align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \
605 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \
606 for (int i = 0; i < kWidth * kHeight; ++i) { \
607 src_y[i + OFF] = (fastrand() & 0xff); \
608 src_a[i + OFF] = (fastrand() & 0xff); \
609 } \
610 for (int i = 0; i < kSizeUV; ++i) { \
611 src_u[i + OFF] = (fastrand() & 0xff); \
612 src_v[i + OFF] = (fastrand() & 0xff); \
613 } \
614 memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \
615 memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \
616 MaskCpuFlags(disable_cpu_flags_); \
617 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
618 src_v + OFF, kStrideUV, src_a + OFF, kWidth, \
619 dst_argb_c + OFF, kStrideB, kWidth, NEG kHeight, \
620 ATTEN); \
621 MaskCpuFlags(benchmark_cpu_info_); \
622 for (int i = 0; i < benchmark_iterations_; ++i) { \
623 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
624 src_v + OFF, kStrideUV, src_a + OFF, kWidth, \
625 dst_argb_opt + OFF, kStrideB, kWidth, NEG kHeight, \
626 ATTEN); \
627 } \
628 int max_diff = 0; \
629 for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) { \
630 int abs_diff = abs(static_cast<int>(dst_argb_c[i + OFF]) - \
631 static_cast<int>(dst_argb_opt[i + OFF])); \
632 if (abs_diff > max_diff) { \
633 max_diff = abs_diff; \
634 } \
635 } \
636 EXPECT_LE(max_diff, DIFF); \
637 free_aligned_buffer_page_end(src_y); \
638 free_aligned_buffer_page_end(src_u); \
639 free_aligned_buffer_page_end(src_v); \
640 free_aligned_buffer_page_end(src_a); \
641 free_aligned_buffer_page_end(dst_argb_c); \
642 free_aligned_buffer_page_end(dst_argb_opt); \
643 }
644
645 #define TESTQPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
646 YALIGN, DIFF) \
647 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
648 YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0) \
649 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
650 YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 0) \
651 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
652 YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0) \
653 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
654 YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0) \
655 TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
656 YALIGN, benchmark_width_, DIFF, _Premult, +, 0, 1)
657
658 TESTQPLANARTOB(I420Alpha, 2, 2, ARGB, 4, 4, 1, 2)
659 TESTQPLANARTOB(I420Alpha, 2, 2, ABGR, 4, 4, 1, 2)
660
661 #define TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
662 W1280, DIFF, N, NEG, OFF) \
663 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \
664 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
665 const int kHeight = benchmark_height_; \
666 const int kStrideB = kWidth * BPP_B; \
667 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
668 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
669 align_buffer_page_end(src_uv, \
670 kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y) * 2 + OFF); \
671 align_buffer_page_end(dst_argb_c, kStrideB* kHeight); \
672 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight); \
673 for (int i = 0; i < kHeight; ++i) \
674 for (int j = 0; j < kWidth; ++j) \
675 src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \
676 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
677 for (int j = 0; j < kStrideUV * 2; ++j) { \
678 src_uv[i * kStrideUV * 2 + j + OFF] = (fastrand() & 0xff); \
679 } \
680 } \
681 memset(dst_argb_c, 1, kStrideB* kHeight); \
682 memset(dst_argb_opt, 101, kStrideB* kHeight); \
683 MaskCpuFlags(disable_cpu_flags_); \
684 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2, \
685 dst_argb_c, kWidth * BPP_B, kWidth, NEG kHeight); \
686 MaskCpuFlags(benchmark_cpu_info_); \
687 for (int i = 0; i < benchmark_iterations_; ++i) { \
688 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_uv + OFF, kStrideUV * 2, \
689 dst_argb_opt, kWidth * BPP_B, kWidth, \
690 NEG kHeight); \
691 } \
692 /* Convert to ARGB so 565 is expanded to bytes that can be compared. */ \
693 align_buffer_page_end(dst_argb32_c, kWidth * 4 * kHeight); \
694 align_buffer_page_end(dst_argb32_opt, kWidth * 4 * kHeight); \
695 memset(dst_argb32_c, 2, kWidth * 4 * kHeight); \
696 memset(dst_argb32_opt, 102, kWidth * 4 * kHeight); \
697 FMT_B##ToARGB(dst_argb_c, kStrideB, dst_argb32_c, kWidth * 4, kWidth, \
698 kHeight); \
699 FMT_B##ToARGB(dst_argb_opt, kStrideB, dst_argb32_opt, kWidth * 4, kWidth, \
700 kHeight); \
701 int max_diff = 0; \
702 for (int i = 0; i < kHeight; ++i) { \
703 for (int j = 0; j < kWidth * 4; ++j) { \
704 int abs_diff = \
705 abs(static_cast<int>(dst_argb32_c[i * kWidth * 4 + j]) - \
706 static_cast<int>(dst_argb32_opt[i * kWidth * 4 + j])); \
707 if (abs_diff > max_diff) { \
708 max_diff = abs_diff; \
709 } \
710 } \
711 } \
712 EXPECT_LE(max_diff, DIFF); \
713 free_aligned_buffer_page_end(src_y); \
714 free_aligned_buffer_page_end(src_uv); \
715 free_aligned_buffer_page_end(dst_argb_c); \
716 free_aligned_buffer_page_end(dst_argb_opt); \
717 free_aligned_buffer_page_end(dst_argb32_c); \
718 free_aligned_buffer_page_end(dst_argb32_opt); \
719 }
720
721 #define TESTBIPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, DIFF) \
722 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
723 benchmark_width_ - 4, DIFF, _Any, +, 0) \
724 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
725 benchmark_width_, DIFF, _Unaligned, +, 1) \
726 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
727 benchmark_width_, DIFF, _Invert, -, 0) \
728 TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
729 benchmark_width_, DIFF, _Opt, +, 0)
730
731 TESTBIPLANARTOB(NV12, 2, 2, ARGB, 4, 2)
732 TESTBIPLANARTOB(NV21, 2, 2, ARGB, 4, 2)
733 TESTBIPLANARTOB(NV12, 2, 2, ABGR, 4, 2)
734 TESTBIPLANARTOB(NV21, 2, 2, ABGR, 4, 2)
735 TESTBIPLANARTOB(NV12, 2, 2, RGB24, 3, 2)
736 TESTBIPLANARTOB(NV21, 2, 2, RGB24, 3, 2)
737 TESTBIPLANARTOB(NV12, 2, 2, RGB565, 2, 9)
738
739 #ifdef DO_THREE_PLANES
740 // Do 3 allocations for yuv. conventional but slower.
741 #define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
742 W1280, DIFF, N, NEG, OFF) \
743 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) { \
744 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
745 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
746 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
747 const int kStride = (kStrideUV * SUBSAMP_X * 8 * BPP_A + 7) / 8; \
748 align_buffer_page_end(src_argb, kStride* kHeight + OFF); \
749 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
750 align_buffer_page_end(dst_u_c, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
751 align_buffer_page_end(dst_v_c, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
752 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
753 align_buffer_page_end(dst_u_opt, \
754 kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
755 align_buffer_page_end(dst_v_opt, \
756 kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
757 memset(dst_y_c, 1, kWidth* kHeight); \
758 memset(dst_u_c, 2, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
759 memset(dst_v_c, 3, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
760 memset(dst_y_opt, 101, kWidth* kHeight); \
761 memset(dst_u_opt, 102, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
762 memset(dst_v_opt, 103, kStrideUV* SUBSAMPLE(kHeight, SUBSAMP_Y)); \
763 for (int i = 0; i < kHeight; ++i) \
764 for (int j = 0; j < kStride; ++j) \
765 src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff); \
766 MaskCpuFlags(disable_cpu_flags_); \
767 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_u_c, \
768 kStrideUV, dst_v_c, kStrideUV, kWidth, NEG kHeight); \
769 MaskCpuFlags(benchmark_cpu_info_); \
770 for (int i = 0; i < benchmark_iterations_; ++i) { \
771 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth, \
772 dst_u_opt, kStrideUV, dst_v_opt, kStrideUV, \
773 kWidth, NEG kHeight); \
774 } \
775 for (int i = 0; i < kHeight; ++i) { \
776 for (int j = 0; j < kWidth; ++j) { \
777 EXPECT_NEAR(static_cast<int>(dst_y_c[i * kWidth + j]), \
778 static_cast<int>(dst_y_opt[i * kWidth + j]), DIFF); \
779 } \
780 } \
781 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
782 for (int j = 0; j < kStrideUV; ++j) { \
783 EXPECT_NEAR(static_cast<int>(dst_u_c[i * kStrideUV + j]), \
784 static_cast<int>(dst_u_opt[i * kStrideUV + j]), DIFF); \
785 } \
786 } \
787 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
788 for (int j = 0; j < kStrideUV; ++j) { \
789 EXPECT_NEAR(static_cast<int>(dst_v_c[i * kStrideUV + j]), \
790 static_cast<int>(dst_v_opt[i * kStrideUV + j]), DIFF); \
791 } \
792 } \
793 free_aligned_buffer_page_end(dst_y_c); \
794 free_aligned_buffer_page_end(dst_u_c); \
795 free_aligned_buffer_page_end(dst_v_c); \
796 free_aligned_buffer_page_end(dst_y_opt); \
797 free_aligned_buffer_page_end(dst_u_opt); \
798 free_aligned_buffer_page_end(dst_v_opt); \
799 free_aligned_buffer_page_end(src_argb); \
800 }
801 #else
802 #define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
803 W1280, DIFF, N, NEG, OFF) \
804 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) { \
805 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
806 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
807 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
808 const int kStride = (kStrideUV * SUBSAMP_X * 8 * BPP_A + 7) / 8; \
809 align_buffer_page_end(src_argb, kStride* kHeight + OFF); \
810 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
811 align_buffer_page_end(dst_uv_c, \
812 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
813 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
814 align_buffer_page_end(dst_uv_opt, \
815 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
816 memset(dst_y_c, 1, kWidth* kHeight); \
817 memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
818 memset(dst_y_opt, 101, kWidth* kHeight); \
819 memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
820 for (int i = 0; i < kHeight; ++i) \
821 for (int j = 0; j < kStride; ++j) \
822 src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff); \
823 MaskCpuFlags(disable_cpu_flags_); \
824 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_uv_c, \
825 kStrideUV * 2, dst_uv_c + kStrideUV, kStrideUV * 2, \
826 kWidth, NEG kHeight); \
827 MaskCpuFlags(benchmark_cpu_info_); \
828 for (int i = 0; i < benchmark_iterations_; ++i) { \
829 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth, \
830 dst_uv_opt, kStrideUV * 2, dst_uv_opt + kStrideUV, \
831 kStrideUV * 2, kWidth, NEG kHeight); \
832 } \
833 for (int i = 0; i < kHeight; ++i) { \
834 for (int j = 0; j < kWidth; ++j) { \
835 EXPECT_NEAR(static_cast<int>(dst_y_c[i * kWidth + j]), \
836 static_cast<int>(dst_y_opt[i * kWidth + j]), DIFF); \
837 } \
838 } \
839 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y) * 2; ++i) { \
840 for (int j = 0; j < kStrideUV; ++j) { \
841 EXPECT_NEAR(static_cast<int>(dst_uv_c[i * kStrideUV + j]), \
842 static_cast<int>(dst_uv_opt[i * kStrideUV + j]), DIFF); \
843 } \
844 } \
845 free_aligned_buffer_page_end(dst_y_c); \
846 free_aligned_buffer_page_end(dst_uv_c); \
847 free_aligned_buffer_page_end(dst_y_opt); \
848 free_aligned_buffer_page_end(dst_uv_opt); \
849 free_aligned_buffer_page_end(src_argb); \
850 }
851 #endif
852
853 #define TESTATOPLANAR(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
854 DIFF) \
855 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
856 benchmark_width_ - 4, DIFF, _Any, +, 0) \
857 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
858 benchmark_width_, DIFF, _Unaligned, +, 1) \
859 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
860 benchmark_width_, DIFF, _Invert, -, 0) \
861 TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
862 benchmark_width_, DIFF, _Opt, +, 0)
863
864 TESTATOPLANAR(ARGB, 4, 1, I420, 2, 2, 4)
865 TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, ARM_YUV_ERROR)
866 TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, ARM_YUV_ERROR)
867 TESTATOPLANAR(BGRA, 4, 1, I420, 2, 2, 4)
868 TESTATOPLANAR(ABGR, 4, 1, I420, 2, 2, 4)
869 TESTATOPLANAR(RGBA, 4, 1, I420, 2, 2, 4)
870 TESTATOPLANAR(RAW, 3, 1, I420, 2, 2, 4)
871 TESTATOPLANAR(RGB24, 3, 1, I420, 2, 2, 4)
872 TESTATOPLANAR(RGB565, 2, 1, I420, 2, 2, 5)
873 // TODO(fbarchard): Make 1555 neon work same as C code, reduce to diff 9.
874 TESTATOPLANAR(ARGB1555, 2, 1, I420, 2, 2, 15)
875 TESTATOPLANAR(ARGB4444, 2, 1, I420, 2, 2, 17)
876 TESTATOPLANAR(ARGB, 4, 1, I422, 2, 1, 2)
877 TESTATOPLANAR(ARGB, 4, 1, I444, 1, 1, 2)
878 TESTATOPLANAR(YUY2, 2, 1, I420, 2, 2, 2)
879 TESTATOPLANAR(UYVY, 2, 1, I420, 2, 2, 2)
880 TESTATOPLANAR(YUY2, 2, 1, I422, 2, 1, 2)
881 TESTATOPLANAR(UYVY, 2, 1, I422, 2, 1, 2)
882 TESTATOPLANAR(I400, 1, 1, I420, 2, 2, 2)
883 TESTATOPLANAR(J400, 1, 1, J420, 2, 2, 2)
884
885 #define TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, \
886 SUBSAMP_Y, W1280, N, NEG, OFF) \
887 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) { \
888 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
889 const int kHeight = benchmark_height_; \
890 const int kStride = SUBSAMPLE(kWidth, SUB_A) * BPP_A; \
891 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
892 align_buffer_page_end(src_argb, kStride* kHeight + OFF); \
893 align_buffer_page_end(dst_y_c, kWidth* kHeight); \
894 align_buffer_page_end(dst_uv_c, \
895 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
896 align_buffer_page_end(dst_y_opt, kWidth* kHeight); \
897 align_buffer_page_end(dst_uv_opt, \
898 kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
899 for (int i = 0; i < kHeight; ++i) \
900 for (int j = 0; j < kStride; ++j) \
901 src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff); \
902 memset(dst_y_c, 1, kWidth* kHeight); \
903 memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
904 memset(dst_y_opt, 101, kWidth* kHeight); \
905 memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y)); \
906 MaskCpuFlags(disable_cpu_flags_); \
907 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_c, kWidth, dst_uv_c, \
908 kStrideUV * 2, kWidth, NEG kHeight); \
909 MaskCpuFlags(benchmark_cpu_info_); \
910 for (int i = 0; i < benchmark_iterations_; ++i) { \
911 FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride, dst_y_opt, kWidth, \
912 dst_uv_opt, kStrideUV * 2, kWidth, NEG kHeight); \
913 } \
914 int max_diff = 0; \
915 for (int i = 0; i < kHeight; ++i) { \
916 for (int j = 0; j < kWidth; ++j) { \
917 int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \
918 static_cast<int>(dst_y_opt[i * kWidth + j])); \
919 if (abs_diff > max_diff) { \
920 max_diff = abs_diff; \
921 } \
922 } \
923 } \
924 EXPECT_LE(max_diff, 4); \
925 for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \
926 for (int j = 0; j < kStrideUV * 2; ++j) { \
927 int abs_diff = \
928 abs(static_cast<int>(dst_uv_c[i * kStrideUV * 2 + j]) - \
929 static_cast<int>(dst_uv_opt[i * kStrideUV * 2 + j])); \
930 if (abs_diff > max_diff) { \
931 max_diff = abs_diff; \
932 } \
933 } \
934 } \
935 EXPECT_LE(max_diff, 4); \
936 free_aligned_buffer_page_end(dst_y_c); \
937 free_aligned_buffer_page_end(dst_uv_c); \
938 free_aligned_buffer_page_end(dst_y_opt); \
939 free_aligned_buffer_page_end(dst_uv_opt); \
940 free_aligned_buffer_page_end(src_argb); \
941 }
942
943 #define TESTATOBIPLANAR(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
944 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
945 benchmark_width_ - 4, _Any, +, 0) \
946 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
947 benchmark_width_, _Unaligned, +, 1) \
948 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
949 benchmark_width_, _Invert, -, 0) \
950 TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
951 benchmark_width_, _Opt, +, 0)
952
953 TESTATOBIPLANAR(ARGB, 1, 4, NV12, 2, 2)
954 TESTATOBIPLANAR(ARGB, 1, 4, NV21, 2, 2)
955 TESTATOBIPLANAR(YUY2, 2, 4, NV12, 2, 2)
956 TESTATOBIPLANAR(UYVY, 2, 4, NV12, 2, 2)
957
958 #define TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
959 HEIGHT_B, W1280, DIFF, N, NEG, OFF) \
960 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##N) { \
961 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
962 const int kHeight = benchmark_height_; \
963 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
964 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
965 const int kStrideA = \
966 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
967 const int kStrideB = \
968 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
969 align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF); \
970 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
971 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
972 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
973 src_argb[i + OFF] = (fastrand() & 0xff); \
974 } \
975 memset(dst_argb_c, 1, kStrideB* kHeightB); \
976 memset(dst_argb_opt, 101, kStrideB* kHeightB); \
977 MaskCpuFlags(disable_cpu_flags_); \
978 FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, kWidth, \
979 NEG kHeight); \
980 MaskCpuFlags(benchmark_cpu_info_); \
981 for (int i = 0; i < benchmark_iterations_; ++i) { \
982 FMT_A##To##FMT_B(src_argb + OFF, kStrideA, dst_argb_opt, kStrideB, \
983 kWidth, NEG kHeight); \
984 } \
985 int max_diff = 0; \
986 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
987 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
988 static_cast<int>(dst_argb_opt[i])); \
989 if (abs_diff > max_diff) { \
990 max_diff = abs_diff; \
991 } \
992 } \
993 EXPECT_LE(max_diff, DIFF); \
994 free_aligned_buffer_page_end(src_argb); \
995 free_aligned_buffer_page_end(dst_argb_c); \
996 free_aligned_buffer_page_end(dst_argb_opt); \
997 }
998
999 #define TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, \
1000 STRIDE_B, HEIGHT_B, DIFF) \
1001 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_Random) { \
1002 for (int times = 0; times < benchmark_iterations_; ++times) { \
1003 const int kWidth = (fastrand() & 63) + 1; \
1004 const int kHeight = (fastrand() & 31) + 1; \
1005 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1006 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1007 const int kStrideA = \
1008 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1009 const int kStrideB = \
1010 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
1011 align_buffer_page_end(src_argb, kStrideA* kHeightA); \
1012 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
1013 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
1014 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1015 src_argb[i] = (fastrand() & 0xff); \
1016 } \
1017 memset(dst_argb_c, 123, kStrideB* kHeightB); \
1018 memset(dst_argb_opt, 123, kStrideB* kHeightB); \
1019 MaskCpuFlags(disable_cpu_flags_); \
1020 FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_c, kStrideB, kWidth, \
1021 kHeight); \
1022 MaskCpuFlags(benchmark_cpu_info_); \
1023 FMT_A##To##FMT_B(src_argb, kStrideA, dst_argb_opt, kStrideB, kWidth, \
1024 kHeight); \
1025 int max_diff = 0; \
1026 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
1027 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
1028 static_cast<int>(dst_argb_opt[i])); \
1029 if (abs_diff > max_diff) { \
1030 max_diff = abs_diff; \
1031 } \
1032 } \
1033 EXPECT_LE(max_diff, DIFF); \
1034 free_aligned_buffer_page_end(src_argb); \
1035 free_aligned_buffer_page_end(dst_argb_c); \
1036 free_aligned_buffer_page_end(dst_argb_opt); \
1037 } \
1038 }
1039
1040 #define TESTATOB(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1041 HEIGHT_B, DIFF) \
1042 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1043 HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0) \
1044 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1045 HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1) \
1046 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1047 HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0) \
1048 TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1049 HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0) \
1050 TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1051 HEIGHT_B, DIFF)
1052
1053 TESTATOB(ARGB, 4, 4, 1, ARGB, 4, 4, 1, 0)
1054 TESTATOB(ARGB, 4, 4, 1, BGRA, 4, 4, 1, 0)
1055 TESTATOB(ARGB, 4, 4, 1, ABGR, 4, 4, 1, 0)
1056 TESTATOB(ARGB, 4, 4, 1, RGBA, 4, 4, 1, 0)
1057 TESTATOB(ARGB, 4, 4, 1, RAW, 3, 3, 1, 0)
1058 TESTATOB(ARGB, 4, 4, 1, RGB24, 3, 3, 1, 0)
1059 TESTATOB(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1060 TESTATOB(ARGB, 4, 4, 1, ARGB1555, 2, 2, 1, 0)
1061 TESTATOB(ARGB, 4, 4, 1, ARGB4444, 2, 2, 1, 0)
1062 TESTATOB(ABGR, 4, 4, 1, AR30, 4, 4, 1, 0)
1063 TESTATOB(ARGB, 4, 4, 1, AR30, 4, 4, 1, 0)
1064 TESTATOB(ARGB, 4, 4, 1, YUY2, 2, 4, 1, 4)
1065 TESTATOB(ARGB, 4, 4, 1, UYVY, 2, 4, 1, 4)
1066 TESTATOB(ARGB, 4, 4, 1, I400, 1, 1, 1, 2)
1067 TESTATOB(ARGB, 4, 4, 1, J400, 1, 1, 1, 2)
1068 TESTATOB(BGRA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1069 TESTATOB(ABGR, 4, 4, 1, ARGB, 4, 4, 1, 0)
1070 TESTATOB(RGBA, 4, 4, 1, ARGB, 4, 4, 1, 0)
1071 TESTATOB(AR30, 4, 4, 1, AR30, 4, 4, 1, 0)
1072 TESTATOB(RAW, 3, 3, 1, ARGB, 4, 4, 1, 0)
1073 TESTATOB(RAW, 3, 3, 1, RGB24, 3, 3, 1, 0)
1074 TESTATOB(RGB24, 3, 3, 1, ARGB, 4, 4, 1, 0)
1075 TESTATOB(RGB565, 2, 2, 1, ARGB, 4, 4, 1, 0)
1076 TESTATOB(ARGB1555, 2, 2, 1, ARGB, 4, 4, 1, 0)
1077 TESTATOB(ARGB4444, 2, 2, 1, ARGB, 4, 4, 1, 0)
1078 TESTATOB(AR30, 4, 4, 1, ARGB, 4, 4, 1, 0)
1079 TESTATOB(AR30, 4, 4, 1, ABGR, 4, 4, 1, 0)
1080 TESTATOB(AB30, 4, 4, 1, ARGB, 4, 4, 1, 0)
1081 TESTATOB(AB30, 4, 4, 1, ABGR, 4, 4, 1, 0)
1082 TESTATOB(AR30, 4, 4, 1, AB30, 4, 4, 1, 0)
1083 TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR)
1084 TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR)
1085 TESTATOB(YUY2, 2, 4, 1, Y, 1, 1, 1, 0)
1086 TESTATOB(I400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1087 TESTATOB(J400, 1, 1, 1, ARGB, 4, 4, 1, 0)
1088 TESTATOB(I400, 1, 1, 1, I400, 1, 1, 1, 0)
1089 TESTATOB(J400, 1, 1, 1, J400, 1, 1, 1, 0)
1090 TESTATOB(I400, 1, 1, 1, I400Mirror, 1, 1, 1, 0)
1091 TESTATOB(ARGB, 4, 4, 1, ARGBMirror, 4, 4, 1, 0)
1092
1093 #define TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1094 HEIGHT_B, W1280, DIFF, N, NEG, OFF) \
1095 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither##N) { \
1096 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1097 const int kHeight = benchmark_height_; \
1098 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1099 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1100 const int kStrideA = \
1101 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1102 const int kStrideB = \
1103 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
1104 align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF); \
1105 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
1106 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
1107 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1108 src_argb[i + OFF] = (fastrand() & 0xff); \
1109 } \
1110 memset(dst_argb_c, 1, kStrideB* kHeightB); \
1111 memset(dst_argb_opt, 101, kStrideB* kHeightB); \
1112 MaskCpuFlags(disable_cpu_flags_); \
1113 FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_c, kStrideB, \
1114 NULL, kWidth, NEG kHeight); \
1115 MaskCpuFlags(benchmark_cpu_info_); \
1116 for (int i = 0; i < benchmark_iterations_; ++i) { \
1117 FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA, dst_argb_opt, \
1118 kStrideB, NULL, kWidth, NEG kHeight); \
1119 } \
1120 int max_diff = 0; \
1121 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
1122 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
1123 static_cast<int>(dst_argb_opt[i])); \
1124 if (abs_diff > max_diff) { \
1125 max_diff = abs_diff; \
1126 } \
1127 } \
1128 EXPECT_LE(max_diff, DIFF); \
1129 free_aligned_buffer_page_end(src_argb); \
1130 free_aligned_buffer_page_end(dst_argb_c); \
1131 free_aligned_buffer_page_end(dst_argb_opt); \
1132 }
1133
1134 #define TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, \
1135 STRIDE_B, HEIGHT_B, DIFF) \
1136 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither_Random) { \
1137 for (int times = 0; times < benchmark_iterations_; ++times) { \
1138 const int kWidth = (fastrand() & 63) + 1; \
1139 const int kHeight = (fastrand() & 31) + 1; \
1140 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1141 const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B; \
1142 const int kStrideA = \
1143 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1144 const int kStrideB = \
1145 (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B; \
1146 align_buffer_page_end(src_argb, kStrideA* kHeightA); \
1147 align_buffer_page_end(dst_argb_c, kStrideB* kHeightB); \
1148 align_buffer_page_end(dst_argb_opt, kStrideB* kHeightB); \
1149 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1150 src_argb[i] = (fastrand() & 0xff); \
1151 } \
1152 memset(dst_argb_c, 123, kStrideB* kHeightB); \
1153 memset(dst_argb_opt, 123, kStrideB* kHeightB); \
1154 MaskCpuFlags(disable_cpu_flags_); \
1155 FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_c, kStrideB, NULL, \
1156 kWidth, kHeight); \
1157 MaskCpuFlags(benchmark_cpu_info_); \
1158 FMT_A##To##FMT_B##Dither(src_argb, kStrideA, dst_argb_opt, kStrideB, \
1159 NULL, kWidth, kHeight); \
1160 int max_diff = 0; \
1161 for (int i = 0; i < kStrideB * kHeightB; ++i) { \
1162 int abs_diff = abs(static_cast<int>(dst_argb_c[i]) - \
1163 static_cast<int>(dst_argb_opt[i])); \
1164 if (abs_diff > max_diff) { \
1165 max_diff = abs_diff; \
1166 } \
1167 } \
1168 EXPECT_LE(max_diff, DIFF); \
1169 free_aligned_buffer_page_end(src_argb); \
1170 free_aligned_buffer_page_end(dst_argb_c); \
1171 free_aligned_buffer_page_end(dst_argb_opt); \
1172 } \
1173 }
1174
1175 #define TESTATOBD(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1176 HEIGHT_B, DIFF) \
1177 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1178 HEIGHT_B, benchmark_width_ - 4, DIFF, _Any, +, 0) \
1179 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1180 HEIGHT_B, benchmark_width_, DIFF, _Unaligned, +, 1) \
1181 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1182 HEIGHT_B, benchmark_width_, DIFF, _Invert, -, 0) \
1183 TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1184 HEIGHT_B, benchmark_width_, DIFF, _Opt, +, 0) \
1185 TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, FMT_B, BPP_B, STRIDE_B, \
1186 HEIGHT_B, DIFF)
1187
1188 TESTATOBD(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1189
1190 #define TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, W1280, N, NEG, OFF) \
1191 TEST_F(LibYUVConvertTest, FMT_ATOB##_Symetric##N) { \
1192 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1193 const int kHeight = benchmark_height_; \
1194 const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A; \
1195 const int kStrideA = \
1196 (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A; \
1197 align_buffer_page_end(src_argb, kStrideA* kHeightA + OFF); \
1198 align_buffer_page_end(dst_argb_c, kStrideA* kHeightA); \
1199 align_buffer_page_end(dst_argb_opt, kStrideA* kHeightA); \
1200 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1201 src_argb[i + OFF] = (fastrand() & 0xff); \
1202 } \
1203 memset(dst_argb_c, 1, kStrideA* kHeightA); \
1204 memset(dst_argb_opt, 101, kStrideA* kHeightA); \
1205 MaskCpuFlags(disable_cpu_flags_); \
1206 FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_c, kStrideA, kWidth, \
1207 NEG kHeight); \
1208 MaskCpuFlags(benchmark_cpu_info_); \
1209 for (int i = 0; i < benchmark_iterations_; ++i) { \
1210 FMT_ATOB(src_argb + OFF, kStrideA, dst_argb_opt, kStrideA, kWidth, \
1211 NEG kHeight); \
1212 } \
1213 MaskCpuFlags(disable_cpu_flags_); \
1214 FMT_ATOB(dst_argb_c, kStrideA, dst_argb_c, kStrideA, kWidth, NEG kHeight); \
1215 MaskCpuFlags(benchmark_cpu_info_); \
1216 FMT_ATOB(dst_argb_opt, kStrideA, dst_argb_opt, kStrideA, kWidth, \
1217 NEG kHeight); \
1218 for (int i = 0; i < kStrideA * kHeightA; ++i) { \
1219 EXPECT_EQ(src_argb[i + OFF], dst_argb_opt[i]); \
1220 EXPECT_EQ(dst_argb_c[i], dst_argb_opt[i]); \
1221 } \
1222 free_aligned_buffer_page_end(src_argb); \
1223 free_aligned_buffer_page_end(dst_argb_c); \
1224 free_aligned_buffer_page_end(dst_argb_opt); \
1225 }
1226
1227 #define TESTSYM(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A) \
1228 TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_ - 4, _Any, +, \
1229 0) \
1230 TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Unaligned, \
1231 +, 1) \
1232 TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A, benchmark_width_, _Opt, +, 0)
1233
1234 TESTSYM(ARGBToARGB, 4, 4, 1)
1235 TESTSYM(ARGBToBGRA, 4, 4, 1)
1236 TESTSYM(ARGBToABGR, 4, 4, 1)
1237 TESTSYM(BGRAToARGB, 4, 4, 1)
1238 TESTSYM(ABGRToARGB, 4, 4, 1)
1239
TEST_F(LibYUVConvertTest,Test565)1240 TEST_F(LibYUVConvertTest, Test565) {
1241 SIMD_ALIGNED(uint8_t orig_pixels[256][4]);
1242 SIMD_ALIGNED(uint8_t pixels565[256][2]);
1243
1244 for (int i = 0; i < 256; ++i) {
1245 for (int j = 0; j < 4; ++j) {
1246 orig_pixels[i][j] = i;
1247 }
1248 }
1249 ARGBToRGB565(&orig_pixels[0][0], 0, &pixels565[0][0], 0, 256, 1);
1250 uint32_t checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381);
1251 EXPECT_EQ(610919429u, checksum);
1252 }
1253
1254 #ifdef HAVE_JPEG
TEST_F(LibYUVConvertTest,ValidateJpeg)1255 TEST_F(LibYUVConvertTest, ValidateJpeg) {
1256 const int kOff = 10;
1257 const int kMinJpeg = 64;
1258 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1259 ? benchmark_width_ * benchmark_height_
1260 : kMinJpeg;
1261 const int kSize = kImageSize + kOff;
1262 align_buffer_page_end(orig_pixels, kSize);
1263
1264 // No SOI or EOI. Expect fail.
1265 memset(orig_pixels, 0, kSize);
1266 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1267
1268 // Test special value that matches marker start.
1269 memset(orig_pixels, 0xff, kSize);
1270 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1271
1272 // EOI, SOI. Expect pass.
1273 orig_pixels[0] = 0xff;
1274 orig_pixels[1] = 0xd8; // SOI.
1275 orig_pixels[kSize - kOff + 0] = 0xff;
1276 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1277 for (int times = 0; times < benchmark_iterations_; ++times) {
1278 EXPECT_TRUE(ValidateJpeg(orig_pixels, kSize));
1279 }
1280 free_aligned_buffer_page_end(orig_pixels);
1281 }
1282
TEST_F(LibYUVConvertTest,ValidateJpegLarge)1283 TEST_F(LibYUVConvertTest, ValidateJpegLarge) {
1284 const int kOff = 10;
1285 const int kMinJpeg = 64;
1286 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1287 ? benchmark_width_ * benchmark_height_
1288 : kMinJpeg;
1289 const int kSize = kImageSize + kOff;
1290 const int kMultiple = 10;
1291 const int kBufSize = kImageSize * kMultiple + kOff;
1292 align_buffer_page_end(orig_pixels, kBufSize);
1293
1294 // No SOI or EOI. Expect fail.
1295 memset(orig_pixels, 0, kBufSize);
1296 EXPECT_FALSE(ValidateJpeg(orig_pixels, kBufSize));
1297
1298 // EOI, SOI. Expect pass.
1299 orig_pixels[0] = 0xff;
1300 orig_pixels[1] = 0xd8; // SOI.
1301 orig_pixels[kSize - kOff + 0] = 0xff;
1302 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1303 for (int times = 0; times < benchmark_iterations_; ++times) {
1304 EXPECT_TRUE(ValidateJpeg(orig_pixels, kBufSize));
1305 }
1306 free_aligned_buffer_page_end(orig_pixels);
1307 }
1308
TEST_F(LibYUVConvertTest,InvalidateJpeg)1309 TEST_F(LibYUVConvertTest, InvalidateJpeg) {
1310 const int kOff = 10;
1311 const int kMinJpeg = 64;
1312 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1313 ? benchmark_width_ * benchmark_height_
1314 : kMinJpeg;
1315 const int kSize = kImageSize + kOff;
1316 align_buffer_page_end(orig_pixels, kSize);
1317
1318 // NULL pointer. Expect fail.
1319 EXPECT_FALSE(ValidateJpeg(NULL, kSize));
1320
1321 // Negative size. Expect fail.
1322 EXPECT_FALSE(ValidateJpeg(orig_pixels, -1));
1323
1324 // Too large size. Expect fail.
1325 EXPECT_FALSE(ValidateJpeg(orig_pixels, 0xfb000000ull));
1326
1327 // No SOI or EOI. Expect fail.
1328 memset(orig_pixels, 0, kSize);
1329 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1330
1331 // SOI but no EOI. Expect fail.
1332 orig_pixels[0] = 0xff;
1333 orig_pixels[1] = 0xd8; // SOI.
1334 for (int times = 0; times < benchmark_iterations_; ++times) {
1335 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1336 }
1337
1338 // EOI but no SOI. Expect fail.
1339 orig_pixels[0] = 0;
1340 orig_pixels[1] = 0;
1341 orig_pixels[kSize - kOff + 0] = 0xff;
1342 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1343 EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1344
1345 free_aligned_buffer_page_end(orig_pixels);
1346 }
1347
TEST_F(LibYUVConvertTest,FuzzJpeg)1348 TEST_F(LibYUVConvertTest, FuzzJpeg) {
1349 // SOI but no EOI. Expect fail.
1350 for (int times = 0; times < benchmark_iterations_; ++times) {
1351 const int kSize = fastrand() % 5000 + 2;
1352 align_buffer_page_end(orig_pixels, kSize);
1353 MemRandomize(orig_pixels, kSize);
1354
1355 // Add SOI so frame will be scanned.
1356 orig_pixels[0] = 0xff;
1357 orig_pixels[1] = 0xd8; // SOI.
1358 orig_pixels[kSize - 1] = 0xff;
1359 ValidateJpeg(orig_pixels, kSize); // Failure normally expected.
1360 free_aligned_buffer_page_end(orig_pixels);
1361 }
1362 }
1363
TEST_F(LibYUVConvertTest,MJPGToI420)1364 TEST_F(LibYUVConvertTest, MJPGToI420) {
1365 const int kOff = 10;
1366 const int kMinJpeg = 64;
1367 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1368 ? benchmark_width_ * benchmark_height_
1369 : kMinJpeg;
1370 const int kSize = kImageSize + kOff;
1371 align_buffer_page_end(orig_pixels, kSize);
1372 align_buffer_page_end(dst_y_opt, benchmark_width_ * benchmark_height_);
1373 align_buffer_page_end(dst_u_opt, SUBSAMPLE(benchmark_width_, 2) *
1374 SUBSAMPLE(benchmark_height_, 2));
1375 align_buffer_page_end(dst_v_opt, SUBSAMPLE(benchmark_width_, 2) *
1376 SUBSAMPLE(benchmark_height_, 2));
1377
1378 // EOI, SOI to make MJPG appear valid.
1379 memset(orig_pixels, 0, kSize);
1380 orig_pixels[0] = 0xff;
1381 orig_pixels[1] = 0xd8; // SOI.
1382 orig_pixels[kSize - kOff + 0] = 0xff;
1383 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1384
1385 for (int times = 0; times < benchmark_iterations_; ++times) {
1386 int ret =
1387 MJPGToI420(orig_pixels, kSize, dst_y_opt, benchmark_width_, dst_u_opt,
1388 SUBSAMPLE(benchmark_width_, 2), dst_v_opt,
1389 SUBSAMPLE(benchmark_width_, 2), benchmark_width_,
1390 benchmark_height_, benchmark_width_, benchmark_height_);
1391 // Expect failure because image is not really valid.
1392 EXPECT_EQ(1, ret);
1393 }
1394
1395 free_aligned_buffer_page_end(dst_y_opt);
1396 free_aligned_buffer_page_end(dst_u_opt);
1397 free_aligned_buffer_page_end(dst_v_opt);
1398 free_aligned_buffer_page_end(orig_pixels);
1399 }
1400
TEST_F(LibYUVConvertTest,MJPGToARGB)1401 TEST_F(LibYUVConvertTest, MJPGToARGB) {
1402 const int kOff = 10;
1403 const int kMinJpeg = 64;
1404 const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
1405 ? benchmark_width_ * benchmark_height_
1406 : kMinJpeg;
1407 const int kSize = kImageSize + kOff;
1408 align_buffer_page_end(orig_pixels, kSize);
1409 align_buffer_page_end(dst_argb_opt, benchmark_width_ * benchmark_height_ * 4);
1410
1411 // EOI, SOI to make MJPG appear valid.
1412 memset(orig_pixels, 0, kSize);
1413 orig_pixels[0] = 0xff;
1414 orig_pixels[1] = 0xd8; // SOI.
1415 orig_pixels[kSize - kOff + 0] = 0xff;
1416 orig_pixels[kSize - kOff + 1] = 0xd9; // EOI.
1417
1418 for (int times = 0; times < benchmark_iterations_; ++times) {
1419 int ret = MJPGToARGB(orig_pixels, kSize, dst_argb_opt, benchmark_width_ * 4,
1420 benchmark_width_, benchmark_height_, benchmark_width_,
1421 benchmark_height_);
1422 // Expect failure because image is not really valid.
1423 EXPECT_EQ(1, ret);
1424 }
1425
1426 free_aligned_buffer_page_end(dst_argb_opt);
1427 free_aligned_buffer_page_end(orig_pixels);
1428 }
1429
1430 #endif // HAVE_JPEG
1431
TEST_F(LibYUVConvertTest,NV12Crop)1432 TEST_F(LibYUVConvertTest, NV12Crop) {
1433 const int SUBSAMP_X = 2;
1434 const int SUBSAMP_Y = 2;
1435 const int kWidth = benchmark_width_;
1436 const int kHeight = benchmark_height_;
1437 const int crop_y =
1438 ((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1;
1439 const int kDestWidth = benchmark_width_;
1440 const int kDestHeight = benchmark_height_ - crop_y * 2;
1441 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);
1442 const int sample_size =
1443 kWidth * kHeight + kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2;
1444 align_buffer_page_end(src_y, sample_size);
1445 uint8_t* src_uv = src_y + kWidth * kHeight;
1446
1447 align_buffer_page_end(dst_y, kDestWidth * kDestHeight);
1448 align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1449 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1450 align_buffer_page_end(dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1451 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1452
1453 align_buffer_page_end(dst_y_2, kDestWidth * kDestHeight);
1454 align_buffer_page_end(dst_u_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1455 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1456 align_buffer_page_end(dst_v_2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1457 SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1458
1459 for (int i = 0; i < kHeight * kWidth; ++i) {
1460 src_y[i] = (fastrand() & 0xff);
1461 }
1462 for (int i = 0; i < (SUBSAMPLE(kHeight, SUBSAMP_Y) * kStrideUV) * 2; ++i) {
1463 src_uv[i] = (fastrand() & 0xff);
1464 }
1465 memset(dst_y, 1, kDestWidth * kDestHeight);
1466 memset(dst_u, 2,
1467 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1468 memset(dst_v, 3,
1469 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1470 memset(dst_y_2, 1, kDestWidth * kDestHeight);
1471 memset(dst_u_2, 2,
1472 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1473 memset(dst_v_2, 3,
1474 SUBSAMPLE(kDestWidth, SUBSAMP_X) * SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1475
1476 ConvertToI420(src_y, sample_size, dst_y_2, kDestWidth, dst_u_2,
1477 SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v_2,
1478 SUBSAMPLE(kDestWidth, SUBSAMP_X), 0, crop_y, kWidth, kHeight,
1479 kDestWidth, kDestHeight, libyuv::kRotate0, libyuv::FOURCC_NV12);
1480
1481 NV12ToI420(src_y + crop_y * kWidth, kWidth,
1482 src_uv + (crop_y / 2) * kStrideUV * 2, kStrideUV * 2, dst_y,
1483 kDestWidth, dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X), dst_v,
1484 SUBSAMPLE(kDestWidth, SUBSAMP_X), kDestWidth, kDestHeight);
1485
1486 for (int i = 0; i < kDestHeight; ++i) {
1487 for (int j = 0; j < kDestWidth; ++j) {
1488 EXPECT_EQ(dst_y[i * kWidth + j], dst_y_2[i * kWidth + j]);
1489 }
1490 }
1491 for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1492 for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1493 EXPECT_EQ(dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1494 dst_u_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1495 }
1496 }
1497 for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1498 for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1499 EXPECT_EQ(dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1500 dst_v_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1501 }
1502 }
1503 free_aligned_buffer_page_end(dst_y);
1504 free_aligned_buffer_page_end(dst_u);
1505 free_aligned_buffer_page_end(dst_v);
1506 free_aligned_buffer_page_end(dst_y_2);
1507 free_aligned_buffer_page_end(dst_u_2);
1508 free_aligned_buffer_page_end(dst_v_2);
1509 free_aligned_buffer_page_end(src_y);
1510 }
1511
TEST_F(LibYUVConvertTest,TestYToARGB)1512 TEST_F(LibYUVConvertTest, TestYToARGB) {
1513 uint8_t y[32];
1514 uint8_t expectedg[32];
1515 for (int i = 0; i < 32; ++i) {
1516 y[i] = i * 5 + 17;
1517 expectedg[i] = static_cast<int>((y[i] - 16) * 1.164f + 0.5f);
1518 }
1519 uint8_t argb[32 * 4];
1520 YToARGB(y, 0, argb, 0, 32, 1);
1521
1522 for (int i = 0; i < 32; ++i) {
1523 printf("%2d %d: %d <-> %d,%d,%d,%d\n", i, y[i], expectedg[i],
1524 argb[i * 4 + 0], argb[i * 4 + 1], argb[i * 4 + 2], argb[i * 4 + 3]);
1525 }
1526 for (int i = 0; i < 32; ++i) {
1527 EXPECT_EQ(expectedg[i], argb[i * 4 + 0]);
1528 }
1529 }
1530
1531 static const uint8_t kNoDither4x4[16] = {
1532 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1533 };
1534
TEST_F(LibYUVConvertTest,TestNoDither)1535 TEST_F(LibYUVConvertTest, TestNoDither) {
1536 align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1537 align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1538 align_buffer_page_end(dst_rgb565dither,
1539 benchmark_width_ * benchmark_height_ * 2);
1540 MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1541 MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1542 MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1543 ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
1544 benchmark_width_, benchmark_height_);
1545 ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
1546 benchmark_width_ * 2, kNoDither4x4, benchmark_width_,
1547 benchmark_height_);
1548 for (int i = 0; i < benchmark_width_ * benchmark_height_ * 2; ++i) {
1549 EXPECT_EQ(dst_rgb565[i], dst_rgb565dither[i]);
1550 }
1551
1552 free_aligned_buffer_page_end(src_argb);
1553 free_aligned_buffer_page_end(dst_rgb565);
1554 free_aligned_buffer_page_end(dst_rgb565dither);
1555 }
1556
1557 // Ordered 4x4 dither for 888 to 565. Values from 0 to 7.
1558 static const uint8_t kDither565_4x4[16] = {
1559 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1560 };
1561
TEST_F(LibYUVConvertTest,TestDither)1562 TEST_F(LibYUVConvertTest, TestDither) {
1563 align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1564 align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1565 align_buffer_page_end(dst_rgb565dither,
1566 benchmark_width_ * benchmark_height_ * 2);
1567 align_buffer_page_end(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1568 align_buffer_page_end(dst_argbdither,
1569 benchmark_width_ * benchmark_height_ * 4);
1570 MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1571 MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1572 MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1573 MemRandomize(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1574 MemRandomize(dst_argbdither, benchmark_width_ * benchmark_height_ * 4);
1575 ARGBToRGB565(src_argb, benchmark_width_ * 4, dst_rgb565, benchmark_width_ * 2,
1576 benchmark_width_, benchmark_height_);
1577 ARGBToRGB565Dither(src_argb, benchmark_width_ * 4, dst_rgb565dither,
1578 benchmark_width_ * 2, kDither565_4x4, benchmark_width_,
1579 benchmark_height_);
1580 RGB565ToARGB(dst_rgb565, benchmark_width_ * 2, dst_argb, benchmark_width_ * 4,
1581 benchmark_width_, benchmark_height_);
1582 RGB565ToARGB(dst_rgb565dither, benchmark_width_ * 2, dst_argbdither,
1583 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
1584
1585 for (int i = 0; i < benchmark_width_ * benchmark_height_ * 4; ++i) {
1586 EXPECT_NEAR(dst_argb[i], dst_argbdither[i], 9);
1587 }
1588 free_aligned_buffer_page_end(src_argb);
1589 free_aligned_buffer_page_end(dst_rgb565);
1590 free_aligned_buffer_page_end(dst_rgb565dither);
1591 free_aligned_buffer_page_end(dst_argb);
1592 free_aligned_buffer_page_end(dst_argbdither);
1593 }
1594
1595 #define TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1596 YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C) \
1597 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##Dither##N) { \
1598 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1599 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
1600 const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \
1601 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
1602 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
1603 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
1604 align_buffer_page_end(src_u, kSizeUV + OFF); \
1605 align_buffer_page_end(src_v, kSizeUV + OFF); \
1606 align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \
1607 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \
1608 for (int i = 0; i < kWidth * kHeight; ++i) { \
1609 src_y[i + OFF] = (fastrand() & 0xff); \
1610 } \
1611 for (int i = 0; i < kSizeUV; ++i) { \
1612 src_u[i + OFF] = (fastrand() & 0xff); \
1613 src_v[i + OFF] = (fastrand() & 0xff); \
1614 } \
1615 memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \
1616 memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \
1617 MaskCpuFlags(disable_cpu_flags_); \
1618 FMT_PLANAR##To##FMT_B##Dither(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
1619 src_v + OFF, kStrideUV, dst_argb_c + OFF, \
1620 kStrideB, NULL, kWidth, NEG kHeight); \
1621 MaskCpuFlags(benchmark_cpu_info_); \
1622 for (int i = 0; i < benchmark_iterations_; ++i) { \
1623 FMT_PLANAR##To##FMT_B##Dither( \
1624 src_y + OFF, kWidth, src_u + OFF, kStrideUV, src_v + OFF, kStrideUV, \
1625 dst_argb_opt + OFF, kStrideB, NULL, kWidth, NEG kHeight); \
1626 } \
1627 int max_diff = 0; \
1628 /* Convert to ARGB so 565 is expanded to bytes that can be compared. */ \
1629 align_buffer_page_end(dst_argb32_c, kWidth* BPP_C* kHeight); \
1630 align_buffer_page_end(dst_argb32_opt, kWidth* BPP_C* kHeight); \
1631 memset(dst_argb32_c, 2, kWidth* BPP_C* kHeight); \
1632 memset(dst_argb32_opt, 102, kWidth* BPP_C* kHeight); \
1633 FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB, dst_argb32_c, kWidth * BPP_C, \
1634 kWidth, kHeight); \
1635 FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB, dst_argb32_opt, \
1636 kWidth * BPP_C, kWidth, kHeight); \
1637 for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) { \
1638 int abs_diff = abs(static_cast<int>(dst_argb32_c[i]) - \
1639 static_cast<int>(dst_argb32_opt[i])); \
1640 if (abs_diff > max_diff) { \
1641 max_diff = abs_diff; \
1642 } \
1643 } \
1644 EXPECT_LE(max_diff, DIFF); \
1645 free_aligned_buffer_page_end(src_y); \
1646 free_aligned_buffer_page_end(src_u); \
1647 free_aligned_buffer_page_end(src_v); \
1648 free_aligned_buffer_page_end(dst_argb_c); \
1649 free_aligned_buffer_page_end(dst_argb_opt); \
1650 free_aligned_buffer_page_end(dst_argb32_c); \
1651 free_aligned_buffer_page_end(dst_argb32_opt); \
1652 }
1653
1654 #define TESTPLANARTOBD(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1655 YALIGN, DIFF, FMT_C, BPP_C) \
1656 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1657 YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C, \
1658 BPP_C) \
1659 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1660 YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C, \
1661 BPP_C) \
1662 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1663 YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C) \
1664 TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1665 YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C)
1666
1667 TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4)
1668
1669 #define TESTPTOB(NAME, UYVYTOI420, UYVYTONV12) \
1670 TEST_F(LibYUVConvertTest, NAME) { \
1671 const int kWidth = benchmark_width_; \
1672 const int kHeight = benchmark_height_; \
1673 \
1674 align_buffer_page_end(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight); \
1675 align_buffer_page_end(orig_y, kWidth* kHeight); \
1676 align_buffer_page_end(orig_u, \
1677 SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1678 align_buffer_page_end(orig_v, \
1679 SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1680 \
1681 align_buffer_page_end(dst_y_orig, kWidth* kHeight); \
1682 align_buffer_page_end(dst_uv_orig, \
1683 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1684 \
1685 align_buffer_page_end(dst_y, kWidth* kHeight); \
1686 align_buffer_page_end(dst_uv, \
1687 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2)); \
1688 \
1689 MemRandomize(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight); \
1690 \
1691 /* Convert UYVY to NV12 in 2 steps for reference */ \
1692 libyuv::UYVYTOI420(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), orig_y, kWidth, \
1693 orig_u, SUBSAMPLE(kWidth, 2), orig_v, \
1694 SUBSAMPLE(kWidth, 2), kWidth, kHeight); \
1695 libyuv::I420ToNV12(orig_y, kWidth, orig_u, SUBSAMPLE(kWidth, 2), orig_v, \
1696 SUBSAMPLE(kWidth, 2), dst_y_orig, kWidth, dst_uv_orig, \
1697 2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight); \
1698 \
1699 /* Convert to NV12 */ \
1700 for (int i = 0; i < benchmark_iterations_; ++i) { \
1701 libyuv::UYVYTONV12(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2), dst_y, kWidth, \
1702 dst_uv, 2 * SUBSAMPLE(kWidth, 2), kWidth, kHeight); \
1703 } \
1704 \
1705 for (int i = 0; i < kWidth * kHeight; ++i) { \
1706 EXPECT_EQ(orig_y[i], dst_y[i]); \
1707 } \
1708 for (int i = 0; i < kWidth * kHeight; ++i) { \
1709 EXPECT_EQ(dst_y_orig[i], dst_y[i]); \
1710 } \
1711 for (int i = 0; i < 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2); \
1712 ++i) { \
1713 EXPECT_EQ(dst_uv_orig[i], dst_uv[i]); \
1714 } \
1715 \
1716 free_aligned_buffer_page_end(orig_uyvy); \
1717 free_aligned_buffer_page_end(orig_y); \
1718 free_aligned_buffer_page_end(orig_u); \
1719 free_aligned_buffer_page_end(orig_v); \
1720 free_aligned_buffer_page_end(dst_y_orig); \
1721 free_aligned_buffer_page_end(dst_uv_orig); \
1722 free_aligned_buffer_page_end(dst_y); \
1723 free_aligned_buffer_page_end(dst_uv); \
1724 }
1725
TESTPTOB(TestYUY2ToNV12,YUY2ToI420,YUY2ToNV12)1726 TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12)
1727 TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12)
1728
1729 // Transitive tests. A to B to C is same as A to C.
1730
1731 #define TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1732 W1280, N, NEG, OFF, FMT_C, BPP_C) \
1733 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) { \
1734 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1735 const int kHeight = benchmark_height_; \
1736 const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B; \
1737 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
1738 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
1739 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
1740 align_buffer_page_end(src_u, kSizeUV + OFF); \
1741 align_buffer_page_end(src_v, kSizeUV + OFF); \
1742 align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF); \
1743 for (int i = 0; i < kWidth * kHeight; ++i) { \
1744 src_y[i + OFF] = (fastrand() & 0xff); \
1745 } \
1746 for (int i = 0; i < kSizeUV; ++i) { \
1747 src_u[i + OFF] = (fastrand() & 0xff); \
1748 src_v[i + OFF] = (fastrand() & 0xff); \
1749 } \
1750 memset(dst_argb_b + OFF, 1, kStrideB * kHeight); \
1751 for (int i = 0; i < benchmark_iterations_; ++i) { \
1752 FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
1753 src_v + OFF, kStrideUV, dst_argb_b + OFF, \
1754 kStrideB, kWidth, NEG kHeight); \
1755 } \
1756 /* Convert to a 3rd format in 1 step and 2 steps and compare */ \
1757 const int kStrideC = kWidth * BPP_C; \
1758 align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF); \
1759 align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF); \
1760 memset(dst_argb_c + OFF, 2, kStrideC * kHeight); \
1761 memset(dst_argb_bc + OFF, 3, kStrideC * kHeight); \
1762 FMT_PLANAR##To##FMT_C(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \
1763 src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideC, \
1764 kWidth, NEG kHeight); \
1765 /* Convert B to C */ \
1766 FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \
1767 kWidth, kHeight); \
1768 for (int i = 0; i < kStrideC * kHeight; ++i) { \
1769 EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]); \
1770 } \
1771 free_aligned_buffer_page_end(src_y); \
1772 free_aligned_buffer_page_end(src_u); \
1773 free_aligned_buffer_page_end(src_v); \
1774 free_aligned_buffer_page_end(dst_argb_b); \
1775 free_aligned_buffer_page_end(dst_argb_c); \
1776 free_aligned_buffer_page_end(dst_argb_bc); \
1777 }
1778
1779 #define TESTPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1780 FMT_C, BPP_C) \
1781 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1782 benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C) \
1783 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1784 benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C) \
1785 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1786 benchmark_width_, _Invert, -, 0, FMT_C, BPP_C) \
1787 TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1788 benchmark_width_, _Opt, +, 0, FMT_C, BPP_C)
1789
1790 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ABGR, 4)
1791 TESTPLANARTOE(J420, 2, 2, ARGB, 1, 4, ARGB, 4)
1792 TESTPLANARTOE(J420, 2, 2, ABGR, 1, 4, ARGB, 4)
1793 TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, ARGB, 4)
1794 TESTPLANARTOE(H420, 2, 2, ABGR, 1, 4, ARGB, 4)
1795 TESTPLANARTOE(I420, 2, 2, BGRA, 1, 4, ARGB, 4)
1796 TESTPLANARTOE(I420, 2, 2, ABGR, 1, 4, ARGB, 4)
1797 TESTPLANARTOE(I420, 2, 2, RGBA, 1, 4, ARGB, 4)
1798 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, ARGB, 4)
1799 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, RGB24, 3)
1800 TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, RAW, 3)
1801 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RAW, 3)
1802 TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, ARGB, 4)
1803 TESTPLANARTOE(H420, 2, 2, RGB24, 1, 3, ARGB, 4)
1804 TESTPLANARTOE(H420, 2, 2, RAW, 1, 3, RGB24, 3)
1805 TESTPLANARTOE(H420, 2, 2, RGB24, 1, 3, RAW, 3)
1806 TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, RAW, 3)
1807 TESTPLANARTOE(H420, 2, 2, RAW, 1, 3, ARGB, 4)
1808 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RGB565, 2)
1809 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB1555, 2)
1810 TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB4444, 2)
1811 TESTPLANARTOE(I422, 2, 1, ARGB, 1, 4, RGB565, 2)
1812 TESTPLANARTOE(J422, 2, 1, ARGB, 1, 4, ARGB, 4)
1813 TESTPLANARTOE(J422, 2, 1, ABGR, 1, 4, ARGB, 4)
1814 TESTPLANARTOE(H422, 2, 1, ARGB, 1, 4, ARGB, 4)
1815 TESTPLANARTOE(H422, 2, 1, ABGR, 1, 4, ARGB, 4)
1816 TESTPLANARTOE(I422, 2, 1, BGRA, 1, 4, ARGB, 4)
1817 TESTPLANARTOE(I422, 2, 1, ABGR, 1, 4, ARGB, 4)
1818 TESTPLANARTOE(I422, 2, 1, RGBA, 1, 4, ARGB, 4)
1819 TESTPLANARTOE(I444, 1, 1, ARGB, 1, 4, ARGB, 4)
1820 TESTPLANARTOE(J444, 1, 1, ARGB, 1, 4, ARGB, 4)
1821 TESTPLANARTOE(I444, 1, 1, ABGR, 1, 4, ARGB, 4)
1822 TESTPLANARTOE(I420, 2, 2, YUY2, 2, 4, ARGB, 4)
1823 TESTPLANARTOE(I420, 2, 2, UYVY, 2, 4, ARGB, 4)
1824 TESTPLANARTOE(I422, 2, 1, YUY2, 2, 4, ARGB, 4)
1825 TESTPLANARTOE(I422, 2, 1, UYVY, 2, 4, ARGB, 4)
1826
1827 #define TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1828 W1280, N, NEG, OFF, FMT_C, BPP_C, ATTEN) \
1829 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) { \
1830 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1831 const int kHeight = benchmark_height_; \
1832 const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B; \
1833 const int kSizeUV = \
1834 SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y); \
1835 align_buffer_page_end(src_y, kWidth* kHeight + OFF); \
1836 align_buffer_page_end(src_u, kSizeUV + OFF); \
1837 align_buffer_page_end(src_v, kSizeUV + OFF); \
1838 align_buffer_page_end(src_a, kWidth* kHeight + OFF); \
1839 align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF); \
1840 for (int i = 0; i < kWidth * kHeight; ++i) { \
1841 src_y[i + OFF] = (fastrand() & 0xff); \
1842 src_a[i + OFF] = (fastrand() & 0xff); \
1843 } \
1844 for (int i = 0; i < kSizeUV; ++i) { \
1845 src_u[i + OFF] = (fastrand() & 0xff); \
1846 src_v[i + OFF] = (fastrand() & 0xff); \
1847 } \
1848 memset(dst_argb_b + OFF, 1, kStrideB * kHeight); \
1849 for (int i = 0; i < benchmark_iterations_; ++i) { \
1850 FMT_PLANAR##To##FMT_B( \
1851 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), \
1852 src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth, \
1853 dst_argb_b + OFF, kStrideB, kWidth, NEG kHeight, ATTEN); \
1854 } \
1855 /* Convert to a 3rd format in 1 step and 2 steps and compare */ \
1856 const int kStrideC = kWidth * BPP_C; \
1857 align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF); \
1858 align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF); \
1859 memset(dst_argb_c + OFF, 2, kStrideC * kHeight); \
1860 memset(dst_argb_bc + OFF, 3, kStrideC * kHeight); \
1861 FMT_PLANAR##To##FMT_C( \
1862 src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), \
1863 src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X), src_a + OFF, kWidth, \
1864 dst_argb_c + OFF, kStrideC, kWidth, NEG kHeight, ATTEN); \
1865 /* Convert B to C */ \
1866 FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \
1867 kWidth, kHeight); \
1868 for (int i = 0; i < kStrideC * kHeight; ++i) { \
1869 EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]); \
1870 } \
1871 free_aligned_buffer_page_end(src_y); \
1872 free_aligned_buffer_page_end(src_u); \
1873 free_aligned_buffer_page_end(src_v); \
1874 free_aligned_buffer_page_end(src_a); \
1875 free_aligned_buffer_page_end(dst_argb_b); \
1876 free_aligned_buffer_page_end(dst_argb_c); \
1877 free_aligned_buffer_page_end(dst_argb_bc); \
1878 }
1879
1880 #define TESTQPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1881 FMT_C, BPP_C) \
1882 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1883 benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C, 0) \
1884 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1885 benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C, 0) \
1886 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1887 benchmark_width_, _Invert, -, 0, FMT_C, BPP_C, 0) \
1888 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1889 benchmark_width_, _Opt, +, 0, FMT_C, BPP_C, 0) \
1890 TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1891 benchmark_width_, _Premult, +, 0, FMT_C, BPP_C, 1)
1892
1893 TESTQPLANARTOE(I420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
1894 TESTQPLANARTOE(I420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
1895
1896 #define TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, W1280, N, NEG, \
1897 OFF, FMT_C, BPP_C) \
1898 TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_##FMT_C##N) { \
1899 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
1900 const int kHeight = benchmark_height_; \
1901 const int kStrideA = SUBSAMPLE(kWidth, SUB_A) * BPP_A; \
1902 const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B; \
1903 align_buffer_page_end(src_argb_a, kStrideA* kHeight + OFF); \
1904 align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF); \
1905 MemRandomize(src_argb_a + OFF, kStrideA * kHeight); \
1906 memset(dst_argb_b + OFF, 1, kStrideB * kHeight); \
1907 for (int i = 0; i < benchmark_iterations_; ++i) { \
1908 FMT_A##To##FMT_B(src_argb_a + OFF, kStrideA, dst_argb_b + OFF, kStrideB, \
1909 kWidth, NEG kHeight); \
1910 } \
1911 /* Convert to a 3rd format in 1 step and 2 steps and compare */ \
1912 const int kStrideC = kWidth * BPP_C; \
1913 align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF); \
1914 align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF); \
1915 memset(dst_argb_c + OFF, 2, kStrideC * kHeight); \
1916 memset(dst_argb_bc + OFF, 3, kStrideC * kHeight); \
1917 FMT_A##To##FMT_C(src_argb_a + OFF, kStrideA, dst_argb_c + OFF, kStrideC, \
1918 kWidth, NEG kHeight); \
1919 /* Convert B to C */ \
1920 FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \
1921 kWidth, kHeight); \
1922 for (int i = 0; i < kStrideC * kHeight; i += 4) { \
1923 EXPECT_EQ(dst_argb_c[i + OFF + 0], dst_argb_bc[i + OFF + 0]); \
1924 EXPECT_EQ(dst_argb_c[i + OFF + 1], dst_argb_bc[i + OFF + 1]); \
1925 EXPECT_EQ(dst_argb_c[i + OFF + 2], dst_argb_bc[i + OFF + 2]); \
1926 EXPECT_NEAR(dst_argb_c[i + OFF + 3], dst_argb_bc[i + OFF + 3], 64); \
1927 } \
1928 free_aligned_buffer_page_end(src_argb_a); \
1929 free_aligned_buffer_page_end(dst_argb_b); \
1930 free_aligned_buffer_page_end(dst_argb_c); \
1931 free_aligned_buffer_page_end(dst_argb_bc); \
1932 }
1933
1934 #define TESTPLANETOE(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, FMT_C, BPP_C) \
1935 TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, \
1936 benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C) \
1937 TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \
1938 _Unaligned, +, 1, FMT_C, BPP_C) \
1939 TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \
1940 _Invert, -, 0, FMT_C, BPP_C) \
1941 TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \
1942 _Opt, +, 0, FMT_C, BPP_C)
1943
1944 // Caveat: Destination needs to be 4 bytes
1945 TESTPLANETOE(ARGB, 1, 4, AR30, 1, 4, ARGB, 4)
1946 TESTPLANETOE(ABGR, 1, 4, AR30, 1, 4, ABGR, 4)
1947 TESTPLANETOE(AR30, 1, 4, ARGB, 1, 4, ABGR, 4)
1948 TESTPLANETOE(AR30, 1, 4, ABGR, 1, 4, ARGB, 4)
1949 TESTPLANETOE(ARGB, 1, 4, AB30, 1, 4, ARGB, 4)
1950 TESTPLANETOE(ABGR, 1, 4, AB30, 1, 4, ABGR, 4)
1951 TESTPLANETOE(AB30, 1, 4, ARGB, 1, 4, ABGR, 4)
1952 TESTPLANETOE(AB30, 1, 4, ABGR, 1, 4, ARGB, 4)
1953
1954 TEST_F(LibYUVConvertTest, RotateWithARGBSource) {
1955 // 2x2 frames
1956 uint32_t src[4];
1957 uint32_t dst[4];
1958 // some random input
1959 src[0] = 0x11000000;
1960 src[1] = 0x00450000;
1961 src[2] = 0x00009f00;
1962 src[3] = 0x000000ff;
1963 // zeros on destination
1964 dst[0] = 0x00000000;
1965 dst[1] = 0x00000000;
1966 dst[2] = 0x00000000;
1967 dst[3] = 0x00000000;
1968
1969 int r = ConvertToARGB(reinterpret_cast<uint8_t*>(src),
1970 16, // input size
1971 reinterpret_cast<uint8_t*>(dst),
1972 8, // destination stride
1973 0, // crop_x
1974 0, // crop_y
1975 2, // width
1976 2, // height
1977 2, // crop width
1978 2, // crop height
1979 kRotate90, FOURCC_ARGB);
1980
1981 EXPECT_EQ(r, 0);
1982 // 90 degrees rotation, no conversion
1983 EXPECT_EQ(dst[0], src[2]);
1984 EXPECT_EQ(dst[1], src[0]);
1985 EXPECT_EQ(dst[2], src[3]);
1986 EXPECT_EQ(dst[3], src[1]);
1987 }
1988
1989 #ifdef HAS_ARGBTOAR30ROW_AVX2
TEST_F(LibYUVConvertTest,ARGBToAR30Row_Opt)1990 TEST_F(LibYUVConvertTest, ARGBToAR30Row_Opt) {
1991 // ARGBToAR30Row_AVX2 expects a multiple of 8 pixels.
1992 const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7;
1993 align_buffer_page_end(src, kPixels * 4);
1994 align_buffer_page_end(dst_opt, kPixels * 4);
1995 align_buffer_page_end(dst_c, kPixels * 4);
1996 MemRandomize(src, kPixels * 4);
1997 memset(dst_opt, 0, kPixels * 4);
1998 memset(dst_c, 1, kPixels * 4);
1999
2000 ARGBToAR30Row_C(src, dst_c, kPixels);
2001
2002 int has_avx2 = TestCpuFlag(kCpuHasAVX2);
2003 int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
2004 for (int i = 0; i < benchmark_iterations_; ++i) {
2005 if (has_avx2) {
2006 ARGBToAR30Row_AVX2(src, dst_opt, kPixels);
2007 } else if (has_ssse3) {
2008 ARGBToAR30Row_SSSE3(src, dst_opt, kPixels);
2009 } else {
2010 ARGBToAR30Row_C(src, dst_opt, kPixels);
2011 }
2012 }
2013 for (int i = 0; i < kPixels * 4; ++i) {
2014 EXPECT_EQ(dst_opt[i], dst_c[i]);
2015 }
2016
2017 free_aligned_buffer_page_end(src);
2018 free_aligned_buffer_page_end(dst_opt);
2019 free_aligned_buffer_page_end(dst_c);
2020 }
2021 #endif // HAS_ARGBTOAR30ROW_AVX2
2022
2023 #ifdef HAS_ABGRTOAR30ROW_AVX2
TEST_F(LibYUVConvertTest,ABGRToAR30Row_Opt)2024 TEST_F(LibYUVConvertTest, ABGRToAR30Row_Opt) {
2025 // ABGRToAR30Row_AVX2 expects a multiple of 8 pixels.
2026 const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7;
2027 align_buffer_page_end(src, kPixels * 4);
2028 align_buffer_page_end(dst_opt, kPixels * 4);
2029 align_buffer_page_end(dst_c, kPixels * 4);
2030 MemRandomize(src, kPixels * 4);
2031 memset(dst_opt, 0, kPixels * 4);
2032 memset(dst_c, 1, kPixels * 4);
2033
2034 ABGRToAR30Row_C(src, dst_c, kPixels);
2035
2036 int has_avx2 = TestCpuFlag(kCpuHasAVX2);
2037 int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
2038 for (int i = 0; i < benchmark_iterations_; ++i) {
2039 if (has_avx2) {
2040 ABGRToAR30Row_AVX2(src, dst_opt, kPixels);
2041 } else if (has_ssse3) {
2042 ABGRToAR30Row_SSSE3(src, dst_opt, kPixels);
2043 } else {
2044 ABGRToAR30Row_C(src, dst_opt, kPixels);
2045 }
2046 }
2047 for (int i = 0; i < kPixels * 4; ++i) {
2048 EXPECT_EQ(dst_opt[i], dst_c[i]);
2049 }
2050
2051 free_aligned_buffer_page_end(src);
2052 free_aligned_buffer_page_end(dst_opt);
2053 free_aligned_buffer_page_end(dst_c);
2054 }
2055 #endif // HAS_ABGRTOAR30ROW_AVX2
2056
2057 // TODO(fbarchard): Fix clamping issue affected by U channel.
2058 #define TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \
2059 ALIGN, YALIGN, W1280, DIFF, N, NEG, SOFF, DOFF) \
2060 TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \
2061 const int kWidth = ((W1280) > 0) ? (W1280) : 1; \
2062 const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \
2063 const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \
2064 const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \
2065 const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \
2066 const int kBpc = 2; \
2067 align_buffer_page_end(src_y, kWidth* kHeight* kBpc + SOFF); \
2068 align_buffer_page_end(src_u, kSizeUV* kBpc + SOFF); \
2069 align_buffer_page_end(src_v, kSizeUV* kBpc + SOFF); \
2070 align_buffer_page_end(dst_argb_c, kStrideB* kHeight + DOFF); \
2071 align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + DOFF); \
2072 for (int i = 0; i < kWidth * kHeight; ++i) { \
2073 reinterpret_cast<uint16_t*>(src_y + SOFF)[i] = (fastrand() & 0x3ff); \
2074 } \
2075 for (int i = 0; i < kSizeUV; ++i) { \
2076 reinterpret_cast<uint16_t*>(src_u + SOFF)[i] = (fastrand() & 0x3ff); \
2077 reinterpret_cast<uint16_t*>(src_v + SOFF)[i] = (fastrand() & 0x3ff); \
2078 } \
2079 memset(dst_argb_c + DOFF, 1, kStrideB * kHeight); \
2080 memset(dst_argb_opt + DOFF, 101, kStrideB * kHeight); \
2081 MaskCpuFlags(disable_cpu_flags_); \
2082 FMT_PLANAR##To##FMT_B( \
2083 reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth, \
2084 reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV, \
2085 reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV, \
2086 dst_argb_c + DOFF, kStrideB, kWidth, NEG kHeight); \
2087 MaskCpuFlags(benchmark_cpu_info_); \
2088 for (int i = 0; i < benchmark_iterations_; ++i) { \
2089 FMT_PLANAR##To##FMT_B( \
2090 reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth, \
2091 reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV, \
2092 reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV, \
2093 dst_argb_opt + DOFF, kStrideB, kWidth, NEG kHeight); \
2094 } \
2095 int max_diff = 0; \
2096 for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) { \
2097 int abs_diff = abs(static_cast<int>(dst_argb_c[i + DOFF]) - \
2098 static_cast<int>(dst_argb_opt[i + DOFF])); \
2099 if (abs_diff > max_diff) { \
2100 max_diff = abs_diff; \
2101 } \
2102 } \
2103 EXPECT_LE(max_diff, DIFF); \
2104 free_aligned_buffer_page_end(src_y); \
2105 free_aligned_buffer_page_end(src_u); \
2106 free_aligned_buffer_page_end(src_v); \
2107 free_aligned_buffer_page_end(dst_argb_c); \
2108 free_aligned_buffer_page_end(dst_argb_opt); \
2109 }
2110
2111 #define TESTPLANAR16TOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2112 YALIGN, DIFF) \
2113 TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2114 YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0) \
2115 TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2116 YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 1) \
2117 TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2118 YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0) \
2119 TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
2120 YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0)
2121
2122 TESTPLANAR16TOB(I010, 2, 2, ARGB, 4, 4, 1, 2)
2123 TESTPLANAR16TOB(I010, 2, 2, ABGR, 4, 4, 1, 2)
2124 TESTPLANAR16TOB(I010, 2, 2, AR30, 4, 4, 1, 2)
2125 TESTPLANAR16TOB(I010, 2, 2, AB30, 4, 4, 1, 2)
2126 TESTPLANAR16TOB(H010, 2, 2, ARGB, 4, 4, 1, 2)
2127 TESTPLANAR16TOB(H010, 2, 2, ABGR, 4, 4, 1, 2)
2128 TESTPLANAR16TOB(H010, 2, 2, AR30, 4, 4, 1, 2)
2129 TESTPLANAR16TOB(H010, 2, 2, AB30, 4, 4, 1, 2)
2130
Clamp(int y)2131 static int Clamp(int y) {
2132 if (y < 0) {
2133 y = 0;
2134 }
2135 if (y > 255) {
2136 y = 255;
2137 }
2138 return y;
2139 }
2140
Clamp10(int y)2141 static int Clamp10(int y) {
2142 if (y < 0) {
2143 y = 0;
2144 }
2145 if (y > 1023) {
2146 y = 1023;
2147 }
2148 return y;
2149 }
2150
2151 // Test 8 bit YUV to 8 bit RGB
TEST_F(LibYUVConvertTest,TestH420ToARGB)2152 TEST_F(LibYUVConvertTest, TestH420ToARGB) {
2153 const int kSize = 256;
2154 int histogram_b[256];
2155 int histogram_g[256];
2156 int histogram_r[256];
2157 memset(histogram_b, 0, sizeof(histogram_b));
2158 memset(histogram_g, 0, sizeof(histogram_g));
2159 memset(histogram_r, 0, sizeof(histogram_r));
2160 align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2);
2161 align_buffer_page_end(argb_pixels, kSize * 4);
2162 uint8_t* orig_y = orig_yuv;
2163 uint8_t* orig_u = orig_y + kSize;
2164 uint8_t* orig_v = orig_u + kSize / 2;
2165
2166 // Test grey scale
2167 for (int i = 0; i < kSize; ++i) {
2168 orig_y[i] = i;
2169 }
2170 for (int i = 0; i < kSize / 2; ++i) {
2171 orig_u[i] = 128; // 128 is 0.
2172 orig_v[i] = 128;
2173 }
2174
2175 H420ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1);
2176
2177 for (int i = 0; i < kSize; ++i) {
2178 int b = argb_pixels[i * 4 + 0];
2179 int g = argb_pixels[i * 4 + 1];
2180 int r = argb_pixels[i * 4 + 2];
2181 int a = argb_pixels[i * 4 + 3];
2182 ++histogram_b[b];
2183 ++histogram_g[g];
2184 ++histogram_r[r];
2185 int expected_y = Clamp(static_cast<int>((i - 16) * 1.164f));
2186 EXPECT_NEAR(b, expected_y, 1);
2187 EXPECT_NEAR(g, expected_y, 1);
2188 EXPECT_NEAR(r, expected_y, 1);
2189 EXPECT_EQ(a, 255);
2190 }
2191
2192 int count_b = 0;
2193 int count_g = 0;
2194 int count_r = 0;
2195 for (int i = 0; i < kSize; ++i) {
2196 if (histogram_b[i]) {
2197 ++count_b;
2198 }
2199 if (histogram_g[i]) {
2200 ++count_g;
2201 }
2202 if (histogram_r[i]) {
2203 ++count_r;
2204 }
2205 }
2206 printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2207
2208 free_aligned_buffer_page_end(orig_yuv);
2209 free_aligned_buffer_page_end(argb_pixels);
2210 }
2211
2212 // Test 10 bit YUV to 8 bit RGB
TEST_F(LibYUVConvertTest,TestH010ToARGB)2213 TEST_F(LibYUVConvertTest, TestH010ToARGB) {
2214 const int kSize = 1024;
2215 int histogram_b[1024];
2216 int histogram_g[1024];
2217 int histogram_r[1024];
2218 memset(histogram_b, 0, sizeof(histogram_b));
2219 memset(histogram_g, 0, sizeof(histogram_g));
2220 memset(histogram_r, 0, sizeof(histogram_r));
2221 align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
2222 align_buffer_page_end(argb_pixels, kSize * 4);
2223 uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
2224 uint16_t* orig_u = orig_y + kSize;
2225 uint16_t* orig_v = orig_u + kSize / 2;
2226
2227 // Test grey scale
2228 for (int i = 0; i < kSize; ++i) {
2229 orig_y[i] = i;
2230 }
2231 for (int i = 0; i < kSize / 2; ++i) {
2232 orig_u[i] = 512; // 512 is 0.
2233 orig_v[i] = 512;
2234 }
2235
2236 H010ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1);
2237
2238 for (int i = 0; i < kSize; ++i) {
2239 int b = argb_pixels[i * 4 + 0];
2240 int g = argb_pixels[i * 4 + 1];
2241 int r = argb_pixels[i * 4 + 2];
2242 int a = argb_pixels[i * 4 + 3];
2243 ++histogram_b[b];
2244 ++histogram_g[g];
2245 ++histogram_r[r];
2246 int expected_y = Clamp(static_cast<int>((i - 64) * 1.164f / 4));
2247 EXPECT_NEAR(b, expected_y, 1);
2248 EXPECT_NEAR(g, expected_y, 1);
2249 EXPECT_NEAR(r, expected_y, 1);
2250 EXPECT_EQ(a, 255);
2251 }
2252
2253 int count_b = 0;
2254 int count_g = 0;
2255 int count_r = 0;
2256 for (int i = 0; i < kSize; ++i) {
2257 if (histogram_b[i]) {
2258 ++count_b;
2259 }
2260 if (histogram_g[i]) {
2261 ++count_g;
2262 }
2263 if (histogram_r[i]) {
2264 ++count_r;
2265 }
2266 }
2267 printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2268
2269 free_aligned_buffer_page_end(orig_yuv);
2270 free_aligned_buffer_page_end(argb_pixels);
2271 }
2272
2273 // Test 10 bit YUV to 10 bit RGB
2274 // Caveat: Result is near due to float rounding in expected result.
TEST_F(LibYUVConvertTest,TestH010ToAR30)2275 TEST_F(LibYUVConvertTest, TestH010ToAR30) {
2276 const int kSize = 1024;
2277 int histogram_b[1024];
2278 int histogram_g[1024];
2279 int histogram_r[1024];
2280 memset(histogram_b, 0, sizeof(histogram_b));
2281 memset(histogram_g, 0, sizeof(histogram_g));
2282 memset(histogram_r, 0, sizeof(histogram_r));
2283
2284 align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
2285 align_buffer_page_end(ar30_pixels, kSize * 4);
2286 uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
2287 uint16_t* orig_u = orig_y + kSize;
2288 uint16_t* orig_v = orig_u + kSize / 2;
2289
2290 // Test grey scale
2291 for (int i = 0; i < kSize; ++i) {
2292 orig_y[i] = i;
2293 }
2294 for (int i = 0; i < kSize / 2; ++i) {
2295 orig_u[i] = 512; // 512 is 0.
2296 orig_v[i] = 512;
2297 }
2298
2299 H010ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1);
2300
2301 for (int i = 0; i < kSize; ++i) {
2302 int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023;
2303 int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023;
2304 int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023;
2305 int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3;
2306 ++histogram_b[b10];
2307 ++histogram_g[g10];
2308 ++histogram_r[r10];
2309 int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f));
2310 EXPECT_NEAR(b10, expected_y, 4);
2311 EXPECT_NEAR(g10, expected_y, 4);
2312 EXPECT_NEAR(r10, expected_y, 4);
2313 EXPECT_EQ(a2, 3);
2314 }
2315
2316 int count_b = 0;
2317 int count_g = 0;
2318 int count_r = 0;
2319 for (int i = 0; i < kSize; ++i) {
2320 if (histogram_b[i]) {
2321 ++count_b;
2322 }
2323 if (histogram_g[i]) {
2324 ++count_g;
2325 }
2326 if (histogram_r[i]) {
2327 ++count_r;
2328 }
2329 }
2330 printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2331
2332 free_aligned_buffer_page_end(orig_yuv);
2333 free_aligned_buffer_page_end(ar30_pixels);
2334 }
2335
2336 // Test 10 bit YUV to 10 bit RGB
2337 // Caveat: Result is near due to float rounding in expected result.
TEST_F(LibYUVConvertTest,TestH010ToAB30)2338 TEST_F(LibYUVConvertTest, TestH010ToAB30) {
2339 const int kSize = 1024;
2340 int histogram_b[1024];
2341 int histogram_g[1024];
2342 int histogram_r[1024];
2343 memset(histogram_b, 0, sizeof(histogram_b));
2344 memset(histogram_g, 0, sizeof(histogram_g));
2345 memset(histogram_r, 0, sizeof(histogram_r));
2346
2347 align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2);
2348 align_buffer_page_end(ab30_pixels, kSize * 4);
2349 uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv);
2350 uint16_t* orig_u = orig_y + kSize;
2351 uint16_t* orig_v = orig_u + kSize / 2;
2352
2353 // Test grey scale
2354 for (int i = 0; i < kSize; ++i) {
2355 orig_y[i] = i;
2356 }
2357 for (int i = 0; i < kSize / 2; ++i) {
2358 orig_u[i] = 512; // 512 is 0.
2359 orig_v[i] = 512;
2360 }
2361
2362 H010ToAB30(orig_y, 0, orig_u, 0, orig_v, 0, ab30_pixels, 0, kSize, 1);
2363
2364 for (int i = 0; i < kSize; ++i) {
2365 int r10 = reinterpret_cast<uint32_t*>(ab30_pixels)[i] & 1023;
2366 int g10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 10) & 1023;
2367 int b10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 20) & 1023;
2368 int a2 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 30) & 3;
2369 ++histogram_b[b10];
2370 ++histogram_g[g10];
2371 ++histogram_r[r10];
2372 int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f));
2373 EXPECT_NEAR(b10, expected_y, 4);
2374 EXPECT_NEAR(g10, expected_y, 4);
2375 EXPECT_NEAR(r10, expected_y, 4);
2376 EXPECT_EQ(a2, 3);
2377 }
2378
2379 int count_b = 0;
2380 int count_g = 0;
2381 int count_r = 0;
2382 for (int i = 0; i < kSize; ++i) {
2383 if (histogram_b[i]) {
2384 ++count_b;
2385 }
2386 if (histogram_g[i]) {
2387 ++count_g;
2388 }
2389 if (histogram_r[i]) {
2390 ++count_r;
2391 }
2392 }
2393 printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2394
2395 free_aligned_buffer_page_end(orig_yuv);
2396 free_aligned_buffer_page_end(ab30_pixels);
2397 }
2398
2399 // Test 8 bit YUV to 10 bit RGB
TEST_F(LibYUVConvertTest,TestH420ToAR30)2400 TEST_F(LibYUVConvertTest, TestH420ToAR30) {
2401 const int kSize = 256;
2402 const int kHistSize = 1024;
2403 int histogram_b[kHistSize];
2404 int histogram_g[kHistSize];
2405 int histogram_r[kHistSize];
2406 memset(histogram_b, 0, sizeof(histogram_b));
2407 memset(histogram_g, 0, sizeof(histogram_g));
2408 memset(histogram_r, 0, sizeof(histogram_r));
2409 align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2);
2410 align_buffer_page_end(ar30_pixels, kSize * 4);
2411 uint8_t* orig_y = orig_yuv;
2412 uint8_t* orig_u = orig_y + kSize;
2413 uint8_t* orig_v = orig_u + kSize / 2;
2414
2415 // Test grey scale
2416 for (int i = 0; i < kSize; ++i) {
2417 orig_y[i] = i;
2418 }
2419 for (int i = 0; i < kSize / 2; ++i) {
2420 orig_u[i] = 128; // 128 is 0.
2421 orig_v[i] = 128;
2422 }
2423
2424 H420ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1);
2425
2426 for (int i = 0; i < kSize; ++i) {
2427 int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023;
2428 int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023;
2429 int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023;
2430 int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3;
2431 ++histogram_b[b10];
2432 ++histogram_g[g10];
2433 ++histogram_r[r10];
2434 int expected_y = Clamp10(static_cast<int>((i - 16) * 1.164f * 4.f));
2435 EXPECT_NEAR(b10, expected_y, 4);
2436 EXPECT_NEAR(g10, expected_y, 4);
2437 EXPECT_NEAR(r10, expected_y, 4);
2438 EXPECT_EQ(a2, 3);
2439 }
2440
2441 int count_b = 0;
2442 int count_g = 0;
2443 int count_r = 0;
2444 for (int i = 0; i < kHistSize; ++i) {
2445 if (histogram_b[i]) {
2446 ++count_b;
2447 }
2448 if (histogram_g[i]) {
2449 ++count_g;
2450 }
2451 if (histogram_r[i]) {
2452 ++count_r;
2453 }
2454 }
2455 printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r);
2456
2457 free_aligned_buffer_page_end(orig_yuv);
2458 free_aligned_buffer_page_end(ar30_pixels);
2459 }
2460
2461 } // namespace libyuv
2462