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 <stdlib.h>
12#include <time.h>
13
14#include "libyuv/basic_types.h"
15#include "libyuv/compare.h"
16#include "libyuv/convert.h"
17#include "libyuv/convert_argb.h"
18#include "libyuv/convert_from.h"
19#include "libyuv/convert_from_argb.h"
20#include "libyuv/cpu_id.h"
21#ifdef HAVE_JPEG
22#include "libyuv/mjpeg_decoder.h"
23#endif
24#include "libyuv/planar_functions.h"
25#include "libyuv/rotate.h"
26#include "libyuv/video_common.h"
27#include "../unit_test/unit_test.h"
28
29namespace libyuv {
30
31#define SUBSAMPLE(v, a) ((((v) + (a) - 1)) / (a))
32
33#define TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,           \
34                       FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF)   \
35TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {                 \
36  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
37  const int kHeight = benchmark_height_;                                       \
38  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
39  align_buffer_page_end(src_u,                                                 \
40                        SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *                     \
41                        SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + OFF);              \
42  align_buffer_page_end(src_v,                                                 \
43                        SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *                     \
44                        SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + OFF);              \
45  align_buffer_page_end(dst_y_c, kWidth * kHeight);                            \
46  align_buffer_page_end(dst_u_c,                                               \
47                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
48                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
49  align_buffer_page_end(dst_v_c,                                               \
50                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
51                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
52  align_buffer_page_end(dst_y_opt, kWidth * kHeight);                          \
53  align_buffer_page_end(dst_u_opt,                                             \
54                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
55                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
56  align_buffer_page_end(dst_v_opt,                                             \
57                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
58                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
59  for (int i = 0; i < kHeight; ++i)                                            \
60    for (int j = 0; j < kWidth; ++j)                                           \
61      src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                       \
62  for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {                \
63    for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {               \
64      src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =                \
65          (fastrand() & 0xff);                                                 \
66      src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =                \
67          (fastrand() & 0xff);                                                 \
68    }                                                                          \
69  }                                                                            \
70  memset(dst_y_c, 1, kWidth * kHeight);                                        \
71  memset(dst_u_c, 2, SUBSAMPLE(kWidth, SUBSAMP_X) *                            \
72                     SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
73  memset(dst_v_c, 3, SUBSAMPLE(kWidth, SUBSAMP_X) *                            \
74                     SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
75  memset(dst_y_opt, 101, kWidth * kHeight);                                    \
76  memset(dst_u_opt, 102, SUBSAMPLE(kWidth, SUBSAMP_X) *                        \
77                         SUBSAMPLE(kHeight, SUBSAMP_Y));                       \
78  memset(dst_v_opt, 103, SUBSAMPLE(kWidth, SUBSAMP_X) *                        \
79                         SUBSAMPLE(kHeight, SUBSAMP_Y));                       \
80  MaskCpuFlags(disable_cpu_flags_);                                            \
81  SRC_FMT_PLANAR##To##FMT_PLANAR(src_y + OFF, kWidth,                          \
82                                 src_u + OFF,                                  \
83                                 SUBSAMPLE(kWidth, SRC_SUBSAMP_X),             \
84                                 src_v + OFF,                                  \
85                                 SUBSAMPLE(kWidth, SRC_SUBSAMP_X),             \
86                                 dst_y_c, kWidth,                              \
87                                 dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X),        \
88                                 dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X),        \
89                                 kWidth, NEG kHeight);                         \
90  MaskCpuFlags(benchmark_cpu_info_);                                           \
91  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
92    SRC_FMT_PLANAR##To##FMT_PLANAR(src_y + OFF, kWidth,                        \
93                                   src_u + OFF,                                \
94                                       SUBSAMPLE(kWidth, SRC_SUBSAMP_X),       \
95                                   src_v + OFF,                                \
96                                       SUBSAMPLE(kWidth, SRC_SUBSAMP_X),       \
97                                   dst_y_opt, kWidth,                          \
98                                   dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X),    \
99                                   dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X),    \
100                                   kWidth, NEG kHeight);                       \
101  }                                                                            \
102  int max_diff = 0;                                                            \
103  for (int i = 0; i < kHeight; ++i) {                                          \
104    for (int j = 0; j < kWidth; ++j) {                                         \
105      int abs_diff =                                                           \
106          abs(static_cast<int>(dst_y_c[i * kWidth + j]) -                      \
107              static_cast<int>(dst_y_opt[i * kWidth + j]));                    \
108      if (abs_diff > max_diff) {                                               \
109        max_diff = abs_diff;                                                   \
110      }                                                                        \
111    }                                                                          \
112  }                                                                            \
113  EXPECT_EQ(0, max_diff);                                                      \
114  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
115    for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                   \
116      int abs_diff =                                                           \
117          abs(static_cast<int>(dst_u_c[i *                                     \
118                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -            \
119              static_cast<int>(dst_u_opt[i *                                   \
120                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]));            \
121      if (abs_diff > max_diff) {                                               \
122        max_diff = abs_diff;                                                   \
123      }                                                                        \
124    }                                                                          \
125  }                                                                            \
126  EXPECT_LE(max_diff, 3);                                                      \
127  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
128    for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                   \
129      int abs_diff =                                                           \
130          abs(static_cast<int>(dst_v_c[i *                                     \
131                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -            \
132              static_cast<int>(dst_v_opt[i *                                   \
133                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]));            \
134      if (abs_diff > max_diff) {                                               \
135        max_diff = abs_diff;                                                   \
136      }                                                                        \
137    }                                                                          \
138  }                                                                            \
139  EXPECT_LE(max_diff, 3);                                                      \
140  free_aligned_buffer_page_end(dst_y_c);                                       \
141  free_aligned_buffer_page_end(dst_u_c);                                       \
142  free_aligned_buffer_page_end(dst_v_c);                                       \
143  free_aligned_buffer_page_end(dst_y_opt);                                     \
144  free_aligned_buffer_page_end(dst_u_opt);                                     \
145  free_aligned_buffer_page_end(dst_v_opt);                                     \
146  free_aligned_buffer_page_end(src_y);                                         \
147  free_aligned_buffer_page_end(src_u);                                         \
148  free_aligned_buffer_page_end(src_v);                                         \
149}
150
151#define TESTPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,            \
152                      FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                        \
153    TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,               \
154                   FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                           \
155                   benchmark_width_ - 4, _Any, +, 0)                           \
156    TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,               \
157                   FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                           \
158                   benchmark_width_, _Unaligned, +, 1)                         \
159    TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,               \
160                   FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                           \
161                   benchmark_width_, _Invert, -, 0)                            \
162    TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,               \
163                   FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                           \
164                   benchmark_width_, _Opt, +, 0)
165
166TESTPLANARTOP(I420, 2, 2, I420, 2, 2)
167TESTPLANARTOP(I422, 2, 1, I420, 2, 2)
168TESTPLANARTOP(I444, 1, 1, I420, 2, 2)
169TESTPLANARTOP(I411, 4, 1, I420, 2, 2)
170TESTPLANARTOP(I420, 2, 2, I422, 2, 1)
171TESTPLANARTOP(I420, 2, 2, I444, 1, 1)
172TESTPLANARTOP(I420, 2, 2, I411, 4, 1)
173TESTPLANARTOP(I420, 2, 2, I420Mirror, 2, 2)
174TESTPLANARTOP(I422, 2, 1, I422, 2, 1)
175TESTPLANARTOP(I444, 1, 1, I444, 1, 1)
176
177#define TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,          \
178                       FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF)   \
179TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {                 \
180  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
181  const int kHeight = benchmark_height_;                                       \
182  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
183  align_buffer_page_end(src_u,                                                 \
184                        SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *                     \
185                        SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + OFF);              \
186  align_buffer_page_end(src_v,                                                 \
187                        SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *                     \
188                        SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + OFF);              \
189  align_buffer_page_end(dst_y_c, kWidth * kHeight);                            \
190  align_buffer_page_end(dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X) *           \
191                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
192  align_buffer_page_end(dst_y_opt, kWidth * kHeight);                          \
193  align_buffer_page_end(dst_uv_opt, SUBSAMPLE(kWidth * 2, SUBSAMP_X) *         \
194                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
195  for (int i = 0; i < kHeight; ++i)                                            \
196    for (int j = 0; j < kWidth; ++j)                                           \
197      src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                       \
198  for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {                \
199    for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {               \
200      src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =                \
201          (fastrand() & 0xff);                                                 \
202      src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =                \
203          (fastrand() & 0xff);                                                 \
204    }                                                                          \
205  }                                                                            \
206  memset(dst_y_c, 1, kWidth * kHeight);                                        \
207  memset(dst_uv_c, 2, SUBSAMPLE(kWidth * 2, SUBSAMP_X) *                       \
208                      SUBSAMPLE(kHeight, SUBSAMP_Y));                          \
209  memset(dst_y_opt, 101, kWidth * kHeight);                                    \
210  memset(dst_uv_opt, 102, SUBSAMPLE(kWidth * 2, SUBSAMP_X) *                   \
211                          SUBSAMPLE(kHeight, SUBSAMP_Y));                      \
212  MaskCpuFlags(disable_cpu_flags_);                                            \
213  SRC_FMT_PLANAR##To##FMT_PLANAR(src_y + OFF, kWidth,                          \
214                                 src_u + OFF,                                  \
215                                 SUBSAMPLE(kWidth, SRC_SUBSAMP_X),             \
216                                 src_v + OFF,                                  \
217                                 SUBSAMPLE(kWidth, SRC_SUBSAMP_X),             \
218                                 dst_y_c, kWidth,                              \
219                                 dst_uv_c, SUBSAMPLE(kWidth * 2, SUBSAMP_X),   \
220                                 kWidth, NEG kHeight);                         \
221  MaskCpuFlags(benchmark_cpu_info_);                                           \
222  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
223    SRC_FMT_PLANAR##To##FMT_PLANAR(src_y + OFF, kWidth,                        \
224                                   src_u + OFF,                                \
225                                   SUBSAMPLE(kWidth, SRC_SUBSAMP_X),           \
226                                   src_v + OFF,                                \
227                                   SUBSAMPLE(kWidth, SRC_SUBSAMP_X),           \
228                                   dst_y_opt, kWidth,                          \
229                                   dst_uv_opt,                                 \
230                                   SUBSAMPLE(kWidth * 2, SUBSAMP_X),           \
231                                   kWidth, NEG kHeight);                       \
232  }                                                                            \
233  int max_diff = 0;                                                            \
234  for (int i = 0; i < kHeight; ++i) {                                          \
235    for (int j = 0; j < kWidth; ++j) {                                         \
236      int abs_diff =                                                           \
237          abs(static_cast<int>(dst_y_c[i * kWidth + j]) -                      \
238              static_cast<int>(dst_y_opt[i * kWidth + j]));                    \
239      if (abs_diff > max_diff) {                                               \
240        max_diff = abs_diff;                                                   \
241      }                                                                        \
242    }                                                                          \
243  }                                                                            \
244  EXPECT_LE(max_diff, 1);                                                      \
245  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
246    for (int j = 0; j < SUBSAMPLE(kWidth * 2, SUBSAMP_X); ++j) {               \
247      int abs_diff =                                                           \
248          abs(static_cast<int>(dst_uv_c[i *                                    \
249                               SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j]) -        \
250              static_cast<int>(dst_uv_opt[i *                                  \
251                               SUBSAMPLE(kWidth * 2, SUBSAMP_X) + j]));        \
252      if (abs_diff > max_diff) {                                               \
253        max_diff = abs_diff;                                                   \
254      }                                                                        \
255    }                                                                          \
256  }                                                                            \
257  EXPECT_LE(max_diff, 1);                                                      \
258  free_aligned_buffer_page_end(dst_y_c);                                       \
259  free_aligned_buffer_page_end(dst_uv_c);                                      \
260  free_aligned_buffer_page_end(dst_y_opt);                                     \
261  free_aligned_buffer_page_end(dst_uv_opt);                                    \
262  free_aligned_buffer_page_end(src_y);                                         \
263  free_aligned_buffer_page_end(src_u);                                         \
264  free_aligned_buffer_page_end(src_v);                                         \
265}
266
267#define TESTPLANARTOBP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,           \
268                       FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                       \
269    TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,              \
270                    FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                          \
271                    benchmark_width_ - 4, _Any, +, 0)                          \
272    TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,              \
273                    FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                          \
274                    benchmark_width_, _Unaligned, +, 1)                        \
275    TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,              \
276                    FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                          \
277                    benchmark_width_, _Invert, -, 0)                           \
278    TESTPLANARTOBPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,              \
279                    FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                          \
280                    benchmark_width_, _Opt, +, 0)
281
282TESTPLANARTOBP(I420, 2, 2, NV12, 2, 2)
283TESTPLANARTOBP(I420, 2, 2, NV21, 2, 2)
284
285#define TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,         \
286                         FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \
287TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) {                 \
288  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
289  const int kHeight = benchmark_height_;                                       \
290  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
291  align_buffer_page_end(src_uv, 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X) *         \
292                        SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + OFF);              \
293  align_buffer_page_end(dst_y_c, kWidth * kHeight);                            \
294  align_buffer_page_end(dst_u_c,                                               \
295                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
296                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
297  align_buffer_page_end(dst_v_c,                                               \
298                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
299                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
300  align_buffer_page_end(dst_y_opt, kWidth * kHeight);                          \
301  align_buffer_page_end(dst_u_opt,                                             \
302                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
303                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
304  align_buffer_page_end(dst_v_opt,                                             \
305                        SUBSAMPLE(kWidth, SUBSAMP_X) *                         \
306                        SUBSAMPLE(kHeight, SUBSAMP_Y));                        \
307  for (int i = 0; i < kHeight; ++i)                                            \
308    for (int j = 0; j < kWidth; ++j)                                           \
309      src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                       \
310  for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) {                \
311    for (int j = 0; j < 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) {           \
312      src_uv[(i * 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] =           \
313          (fastrand() & 0xff);                                                 \
314    }                                                                          \
315  }                                                                            \
316  memset(dst_y_c, 1, kWidth * kHeight);                                        \
317  memset(dst_u_c, 2, SUBSAMPLE(kWidth, SUBSAMP_X) *                            \
318                     SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
319  memset(dst_v_c, 3, SUBSAMPLE(kWidth, SUBSAMP_X) *                            \
320                     SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
321  memset(dst_y_opt, 101, kWidth * kHeight);                                    \
322  memset(dst_u_opt, 102, SUBSAMPLE(kWidth, SUBSAMP_X) *                        \
323                         SUBSAMPLE(kHeight, SUBSAMP_Y));                       \
324  memset(dst_v_opt, 103, SUBSAMPLE(kWidth, SUBSAMP_X) *                        \
325                         SUBSAMPLE(kHeight, SUBSAMP_Y));                       \
326  MaskCpuFlags(disable_cpu_flags_);                                            \
327  SRC_FMT_PLANAR##To##FMT_PLANAR(src_y + OFF, kWidth,                          \
328                                 src_uv + OFF,                                 \
329                                 2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X),         \
330                                 dst_y_c, kWidth,                              \
331                                 dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X),        \
332                                 dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X),        \
333                                 kWidth, NEG kHeight);                         \
334  MaskCpuFlags(benchmark_cpu_info_);                                           \
335  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
336    SRC_FMT_PLANAR##To##FMT_PLANAR(src_y + OFF, kWidth,                        \
337                                   src_uv + OFF,                               \
338                                   2 * SUBSAMPLE(kWidth, SRC_SUBSAMP_X),       \
339                                   dst_y_opt, kWidth,                          \
340                                   dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X),    \
341                                   dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X),    \
342                                   kWidth, NEG kHeight);                       \
343  }                                                                            \
344  int max_diff = 0;                                                            \
345  for (int i = 0; i < kHeight; ++i) {                                          \
346    for (int j = 0; j < kWidth; ++j) {                                         \
347      int abs_diff =                                                           \
348          abs(static_cast<int>(dst_y_c[i * kWidth + j]) -                      \
349              static_cast<int>(dst_y_opt[i * kWidth + j]));                    \
350      if (abs_diff > max_diff) {                                               \
351        max_diff = abs_diff;                                                   \
352      }                                                                        \
353    }                                                                          \
354  }                                                                            \
355  EXPECT_LE(max_diff, 1);                                                      \
356  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
357    for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                   \
358      int abs_diff =                                                           \
359          abs(static_cast<int>(dst_u_c[i *                                     \
360                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -            \
361              static_cast<int>(dst_u_opt[i *                                   \
362                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]));            \
363      if (abs_diff > max_diff) {                                               \
364        max_diff = abs_diff;                                                   \
365      }                                                                        \
366    }                                                                          \
367  }                                                                            \
368  EXPECT_LE(max_diff, 1);                                                      \
369  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
370    for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) {                   \
371      int abs_diff =                                                           \
372          abs(static_cast<int>(dst_v_c[i *                                     \
373                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]) -            \
374              static_cast<int>(dst_v_opt[i *                                   \
375                               SUBSAMPLE(kWidth, SUBSAMP_X) + j]));            \
376      if (abs_diff > max_diff) {                                               \
377        max_diff = abs_diff;                                                   \
378      }                                                                        \
379    }                                                                          \
380  }                                                                            \
381  EXPECT_LE(max_diff, 1);                                                      \
382  free_aligned_buffer_page_end(dst_y_c);                                       \
383  free_aligned_buffer_page_end(dst_u_c);                                       \
384  free_aligned_buffer_page_end(dst_v_c);                                       \
385  free_aligned_buffer_page_end(dst_y_opt);                                     \
386  free_aligned_buffer_page_end(dst_u_opt);                                     \
387  free_aligned_buffer_page_end(dst_v_opt);                                     \
388  free_aligned_buffer_page_end(src_y);                                         \
389  free_aligned_buffer_page_end(src_uv);                                        \
390}
391
392#define TESTBIPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,          \
393                        FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y)                      \
394    TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,             \
395                     FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                         \
396                     benchmark_width_ - 4, _Any, +, 0)                         \
397    TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,             \
398                     FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                         \
399                     benchmark_width_, _Unaligned, +, 1)                       \
400    TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,             \
401                     FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                         \
402                     benchmark_width_, _Invert, -, 0)                          \
403    TESTBIPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y,             \
404                     FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,                         \
405                     benchmark_width_, _Opt, +, 0)
406
407TESTBIPLANARTOP(NV12, 2, 2, I420, 2, 2)
408TESTBIPLANARTOP(NV21, 2, 2, I420, 2, 2)
409
410#define ALIGNINT(V, ALIGN) (((V) + (ALIGN) - 1) / (ALIGN) * (ALIGN))
411
412#define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,  \
413                       YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C)         \
414TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                          \
415  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
416  const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                     \
417  const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                        \
418  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                          \
419  const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);               \
420  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
421  align_buffer_page_end(src_u, kSizeUV + OFF);                                 \
422  align_buffer_page_end(src_v, kSizeUV + OFF);                                 \
423  align_buffer_page_end(dst_argb_c, kStrideB * kHeight + OFF);                 \
424  align_buffer_page_end(dst_argb_opt, kStrideB * kHeight + OFF);               \
425  for (int i = 0; i < kWidth * kHeight; ++i) {                                 \
426    src_y[i + OFF] = (fastrand() & 0xff);                                      \
427  }                                                                            \
428  for (int i = 0; i < kSizeUV; ++i) {                                          \
429    src_u[i + OFF] = (fastrand() & 0xff);                                      \
430    src_v[i + OFF] = (fastrand() & 0xff);                                      \
431  }                                                                            \
432  memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                             \
433  memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                         \
434  MaskCpuFlags(disable_cpu_flags_);                                            \
435  FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                   \
436                        src_u + OFF, kStrideUV,                                \
437                        src_v + OFF, kStrideUV,                                \
438                        dst_argb_c + OFF, kStrideB,                            \
439                        kWidth, NEG kHeight);                                  \
440  MaskCpuFlags(benchmark_cpu_info_);                                           \
441  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
442    FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                 \
443                          src_u + OFF, kStrideUV,                              \
444                          src_v + OFF, kStrideUV,                              \
445                          dst_argb_opt + OFF, kStrideB,                        \
446                          kWidth, NEG kHeight);                                \
447  }                                                                            \
448  int max_diff = 0;                                                            \
449  /* Convert to ARGB so 565 is expanded to bytes that can be compared. */      \
450  align_buffer_page_end(dst_argb32_c, kWidth * BPP_C  * kHeight);              \
451  align_buffer_page_end(dst_argb32_opt, kWidth * BPP_C  * kHeight);            \
452  memset(dst_argb32_c, 2, kWidth * BPP_C  * kHeight);                          \
453  memset(dst_argb32_opt, 102, kWidth * BPP_C  * kHeight);                      \
454  FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB,                                 \
455                   dst_argb32_c, kWidth * BPP_C ,                              \
456                   kWidth, kHeight);                                           \
457  FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB,                               \
458                   dst_argb32_opt, kWidth * BPP_C ,                            \
459                   kWidth, kHeight);                                           \
460  for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) {                         \
461    int abs_diff =                                                             \
462        abs(static_cast<int>(dst_argb32_c[i]) -                                \
463            static_cast<int>(dst_argb32_opt[i]));                              \
464    if (abs_diff > max_diff) {                                                 \
465      max_diff = abs_diff;                                                     \
466    }                                                                          \
467  }                                                                            \
468  EXPECT_LE(max_diff, DIFF);                                                   \
469  free_aligned_buffer_page_end(src_y);                                         \
470  free_aligned_buffer_page_end(src_u);                                         \
471  free_aligned_buffer_page_end(src_v);                                         \
472  free_aligned_buffer_page_end(dst_argb_c);                                    \
473  free_aligned_buffer_page_end(dst_argb_opt);                                  \
474  free_aligned_buffer_page_end(dst_argb32_c);                                  \
475  free_aligned_buffer_page_end(dst_argb32_opt);                                \
476}
477
478#define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,   \
479                      YALIGN, DIFF, FMT_C, BPP_C)                              \
480    TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
481        YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C, BPP_C)          \
482    TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
483        YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C, BPP_C)        \
484    TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
485        YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C)           \
486    TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,      \
487        YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C)
488
489TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4)
490TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4)
491TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4)
492TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4)
493TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4)
494TESTPLANARTOB(I420, 2, 2, BGRA, 4, 4, 1, 2, ARGB, 4)
495TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4)
496TESTPLANARTOB(I420, 2, 2, RGBA, 4, 4, 1, 2, ARGB, 4)
497TESTPLANARTOB(I420, 2, 2, RAW, 3, 3, 1, 2, ARGB, 4)
498TESTPLANARTOB(I420, 2, 2, RGB24, 3, 3, 1, 2, ARGB, 4)
499TESTPLANARTOB(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4)
500TESTPLANARTOB(I420, 2, 2, ARGB1555, 2, 2, 1, 9, ARGB, 4)
501TESTPLANARTOB(I420, 2, 2, ARGB4444, 2, 2, 1, 17, ARGB, 4)
502TESTPLANARTOB(I422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
503TESTPLANARTOB(J422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
504TESTPLANARTOB(J422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
505TESTPLANARTOB(H422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
506TESTPLANARTOB(H422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
507TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1, 2, ARGB, 4)
508TESTPLANARTOB(I422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
509TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1, 2, ARGB, 4)
510TESTPLANARTOB(I411, 4, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
511TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
512TESTPLANARTOB(J444, 1, 1, ARGB, 4, 4, 1, 2, ARGB, 4)
513TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1, 2, ARGB, 4)
514TESTPLANARTOB(I420, 2, 2, YUY2, 2, 4, 1, 1, ARGB, 4)
515TESTPLANARTOB(I420, 2, 2, UYVY, 2, 4, 1, 1, ARGB, 4)
516TESTPLANARTOB(I422, 2, 1, YUY2, 2, 4, 1, 0, ARGB, 4)
517TESTPLANARTOB(I422, 2, 1, UYVY, 2, 4, 1, 0, ARGB, 4)
518TESTPLANARTOB(I420, 2, 2, I400, 1, 1, 1, 0, ARGB, 4)
519TESTPLANARTOB(J420, 2, 2, J400, 1, 1, 1, 0, ARGB, 4)
520
521#define TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
522                       YALIGN, W1280, DIFF, N, NEG, OFF, ATTEN)                \
523TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                          \
524  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
525  const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                     \
526  const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                        \
527  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                          \
528  const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);               \
529  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
530  align_buffer_page_end(src_u, kSizeUV + OFF);                                 \
531  align_buffer_page_end(src_v, kSizeUV + OFF);                                 \
532  align_buffer_page_end(src_a, kWidth * kHeight + OFF);                        \
533  align_buffer_page_end(dst_argb_c, kStrideB * kHeight + OFF);                 \
534  align_buffer_page_end(dst_argb_opt, kStrideB * kHeight + OFF);               \
535  for (int i = 0; i < kWidth * kHeight; ++i) {                                 \
536    src_y[i + OFF] = (fastrand() & 0xff);                                      \
537    src_a[i + OFF] = (fastrand() & 0xff);                                      \
538  }                                                                            \
539  for (int i = 0; i < kSizeUV; ++i) {                                          \
540    src_u[i + OFF] = (fastrand() & 0xff);                                      \
541    src_v[i + OFF] = (fastrand() & 0xff);                                      \
542  }                                                                            \
543  memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                             \
544  memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                         \
545  MaskCpuFlags(disable_cpu_flags_);                                            \
546  FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                   \
547                        src_u + OFF, kStrideUV,                                \
548                        src_v + OFF, kStrideUV,                                \
549                        src_a + OFF, kWidth,                                   \
550                        dst_argb_c + OFF, kStrideB,                            \
551                        kWidth, NEG kHeight, ATTEN);                           \
552  MaskCpuFlags(benchmark_cpu_info_);                                           \
553  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
554    FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                 \
555                          src_u + OFF, kStrideUV,                              \
556                          src_v + OFF, kStrideUV,                              \
557                          src_a + OFF, kWidth,                                 \
558                          dst_argb_opt + OFF, kStrideB,                        \
559                          kWidth, NEG kHeight, ATTEN);                         \
560  }                                                                            \
561  int max_diff = 0;                                                            \
562  for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) {                         \
563    int abs_diff =                                                             \
564        abs(static_cast<int>(dst_argb_c[i + OFF]) -                            \
565            static_cast<int>(dst_argb_opt[i + OFF]));                          \
566    if (abs_diff > max_diff) {                                                 \
567      max_diff = abs_diff;                                                     \
568    }                                                                          \
569  }                                                                            \
570  EXPECT_LE(max_diff, DIFF);                                                   \
571  free_aligned_buffer_page_end(src_y);                                         \
572  free_aligned_buffer_page_end(src_u);                                         \
573  free_aligned_buffer_page_end(src_v);                                         \
574  free_aligned_buffer_page_end(src_a);                                         \
575  free_aligned_buffer_page_end(dst_argb_c);                                    \
576  free_aligned_buffer_page_end(dst_argb_opt);                                  \
577}
578
579#define TESTQPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,  \
580                       YALIGN, DIFF)                                           \
581    TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
582        YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0)                     \
583    TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
584        YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 0)                   \
585    TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
586        YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0)                      \
587    TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
588        YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0)                         \
589    TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
590        YALIGN, benchmark_width_, DIFF, _Premult, +, 0, 1)
591
592TESTQPLANARTOB(I420Alpha, 2, 2, ARGB, 4, 4, 1, 2)
593TESTQPLANARTOB(I420Alpha, 2, 2, ABGR, 4, 4, 1, 2)
594
595#define TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,       \
596                         W1280, DIFF, N, NEG, OFF)                             \
597TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) {                          \
598  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
599  const int kHeight = benchmark_height_;                                       \
600  const int kStrideB = kWidth * BPP_B;                                         \
601  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                          \
602  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
603  align_buffer_page_end(src_uv,                                                \
604                        kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2 + OFF);  \
605  align_buffer_page_end(dst_argb_c, kStrideB * kHeight);                       \
606  align_buffer_page_end(dst_argb_opt, kStrideB * kHeight);                     \
607  for (int i = 0; i < kHeight; ++i)                                            \
608    for (int j = 0; j < kWidth; ++j)                                           \
609      src_y[i * kWidth + j + OFF] = (fastrand() & 0xff);                       \
610  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
611    for (int j = 0; j < kStrideUV * 2; ++j) {                                  \
612      src_uv[i * kStrideUV * 2 + j + OFF] = (fastrand() & 0xff);               \
613    }                                                                          \
614  }                                                                            \
615  memset(dst_argb_c, 1, kStrideB * kHeight);                                   \
616  memset(dst_argb_opt, 101, kStrideB * kHeight);                               \
617  MaskCpuFlags(disable_cpu_flags_);                                            \
618  FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                   \
619                        src_uv + OFF, kStrideUV * 2,                           \
620                        dst_argb_c, kWidth * BPP_B,                            \
621                        kWidth, NEG kHeight);                                  \
622  MaskCpuFlags(benchmark_cpu_info_);                                           \
623  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
624    FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                 \
625                          src_uv + OFF, kStrideUV * 2,                         \
626                          dst_argb_opt, kWidth * BPP_B,                        \
627                          kWidth, NEG kHeight);                                \
628  }                                                                            \
629  /* Convert to ARGB so 565 is expanded to bytes that can be compared. */      \
630  align_buffer_page_end(dst_argb32_c, kWidth * 4 * kHeight);                   \
631  align_buffer_page_end(dst_argb32_opt, kWidth * 4 * kHeight);                 \
632  memset(dst_argb32_c, 2, kWidth * 4 * kHeight);                               \
633  memset(dst_argb32_opt, 102, kWidth * 4 * kHeight);                           \
634  FMT_B##ToARGB(dst_argb_c, kStrideB,                                          \
635                dst_argb32_c, kWidth * 4,                                      \
636                kWidth, kHeight);                                              \
637  FMT_B##ToARGB(dst_argb_opt, kStrideB,                                        \
638                dst_argb32_opt, kWidth * 4,                                    \
639                kWidth, kHeight);                                              \
640  int max_diff = 0;                                                            \
641  for (int i = 0; i < kHeight; ++i) {                                          \
642    for (int j = 0; j < kWidth * 4; ++j) {                                     \
643      int abs_diff =                                                           \
644          abs(static_cast<int>(dst_argb32_c[i * kWidth * 4 + j]) -             \
645              static_cast<int>(dst_argb32_opt[i * kWidth * 4 + j]));           \
646      if (abs_diff > max_diff) {                                               \
647        max_diff = abs_diff;                                                   \
648      }                                                                        \
649    }                                                                          \
650  }                                                                            \
651  EXPECT_LE(max_diff, DIFF);                                                   \
652  free_aligned_buffer_page_end(src_y);                                         \
653  free_aligned_buffer_page_end(src_uv);                                        \
654  free_aligned_buffer_page_end(dst_argb_c);                                    \
655  free_aligned_buffer_page_end(dst_argb_opt);                                  \
656  free_aligned_buffer_page_end(dst_argb32_c);                                  \
657  free_aligned_buffer_page_end(dst_argb32_opt);                                \
658}
659
660#define TESTBIPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, DIFF)  \
661    TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,           \
662                     benchmark_width_ - 4, DIFF, _Any, +, 0)                   \
663    TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,           \
664                     benchmark_width_, DIFF, _Unaligned, +, 1)                 \
665    TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,           \
666                     benchmark_width_, DIFF, _Invert, -, 0)                    \
667    TESTBIPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B,           \
668                     benchmark_width_, DIFF, _Opt, +, 0)
669
670TESTBIPLANARTOB(NV12, 2, 2, ARGB, 4, 2)
671TESTBIPLANARTOB(NV21, 2, 2, ARGB, 4, 2)
672TESTBIPLANARTOB(NV12, 2, 2, RGB565, 2, 9)
673
674#define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
675                       W1280, DIFF, N, NEG, OFF)                               \
676TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) {                          \
677  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
678  const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                     \
679  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                          \
680  const int kStride =                                                          \
681      (kStrideUV * SUBSAMP_X * 8 * BPP_A + 7) / 8;                             \
682  align_buffer_page_end(src_argb, kStride * kHeight + OFF);                    \
683  align_buffer_page_end(dst_y_c, kWidth * kHeight);                            \
684  align_buffer_page_end(dst_u_c,                                               \
685                        kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y));            \
686  align_buffer_page_end(dst_v_c,                                               \
687                        kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y));            \
688  align_buffer_page_end(dst_y_opt, kWidth * kHeight);                          \
689  align_buffer_page_end(dst_u_opt,                                             \
690                        kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y));            \
691  align_buffer_page_end(dst_v_opt,                                             \
692                  kStrideUV *                                                  \
693                  SUBSAMPLE(kHeight, SUBSAMP_Y));                              \
694  memset(dst_y_c, 1, kWidth * kHeight);                                        \
695  memset(dst_u_c, 2,                                                           \
696         kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
697  memset(dst_v_c, 3,                                                           \
698         kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
699  memset(dst_y_opt, 101, kWidth * kHeight);                                    \
700  memset(dst_u_opt, 102,                                                       \
701         kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
702  memset(dst_v_opt, 103,                                                       \
703         kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y));                           \
704  for (int i = 0; i < kHeight; ++i)                                            \
705    for (int j = 0; j < kStride; ++j)                                          \
706      src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff);                 \
707  MaskCpuFlags(disable_cpu_flags_);                                            \
708  FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride,                               \
709                        dst_y_c, kWidth,                                       \
710                        dst_u_c, kStrideUV,                                    \
711                        dst_v_c, kStrideUV,                                    \
712                        kWidth, NEG kHeight);                                  \
713  MaskCpuFlags(benchmark_cpu_info_);                                           \
714  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
715    FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride,                             \
716                          dst_y_opt, kWidth,                                   \
717                          dst_u_opt, kStrideUV,                                \
718                          dst_v_opt, kStrideUV,                                \
719                          kWidth, NEG kHeight);                                \
720  }                                                                            \
721  for (int i = 0; i < kHeight; ++i) {                                          \
722    for (int j = 0; j < kWidth; ++j) {                                         \
723      EXPECT_NEAR(static_cast<int>(dst_y_c[i * kWidth + j]),                   \
724                  static_cast<int>(dst_y_opt[i * kWidth + j]), DIFF);          \
725    }                                                                          \
726  }                                                                            \
727  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
728    for (int j = 0; j < kStrideUV; ++j) {                                      \
729      EXPECT_NEAR(static_cast<int>(dst_u_c[i * kStrideUV + j]),                \
730                  static_cast<int>(dst_u_opt[i * kStrideUV + j]), DIFF);       \
731    }                                                                          \
732  }                                                                            \
733  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
734    for (int j = 0; j < kStrideUV; ++j) {                                      \
735      EXPECT_NEAR(static_cast<int>(dst_v_c[i *                                 \
736                                   kStrideUV + j]),                            \
737                  static_cast<int>(dst_v_opt[i *                               \
738                                   kStrideUV + j]), DIFF);                     \
739    }                                                                          \
740  }                                                                            \
741  free_aligned_buffer_page_end(dst_y_c);                                       \
742  free_aligned_buffer_page_end(dst_u_c);                                       \
743  free_aligned_buffer_page_end(dst_v_c);                                       \
744  free_aligned_buffer_page_end(dst_y_opt);                                     \
745  free_aligned_buffer_page_end(dst_u_opt);                                     \
746  free_aligned_buffer_page_end(dst_v_opt);                                     \
747  free_aligned_buffer_page_end(src_argb);                                      \
748}
749
750#define TESTATOPLANAR(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,  \
751                      DIFF)                                                    \
752    TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,     \
753                   benchmark_width_ - 4, DIFF, _Any, +, 0)                     \
754    TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,     \
755                   benchmark_width_, DIFF, _Unaligned, +, 1)                   \
756    TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,     \
757                   benchmark_width_, DIFF, _Invert, -, 0)                      \
758    TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,     \
759                   benchmark_width_, DIFF, _Opt, +, 0)
760
761TESTATOPLANAR(ARGB, 4, 1, I420, 2, 2, 4)
762#if defined(__arm__) || defined (__aarch64__)
763// arm version subsamples by summing 4 pixels then multiplying by matrix with
764// 4x smaller coefficients which are rounded to nearest integer.
765TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, 4)
766TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, 4)
767#else
768TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, 0)
769TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, 0)
770#endif
771TESTATOPLANAR(BGRA, 4, 1, I420, 2, 2, 4)
772TESTATOPLANAR(ABGR, 4, 1, I420, 2, 2, 4)
773TESTATOPLANAR(RGBA, 4, 1, I420, 2, 2, 4)
774TESTATOPLANAR(RAW, 3, 1, I420, 2, 2, 4)
775TESTATOPLANAR(RGB24, 3, 1, I420, 2, 2, 4)
776TESTATOPLANAR(RGB565, 2, 1, I420, 2, 2, 5)
777// TODO(fbarchard): Make 1555 neon work same as C code, reduce to diff 9.
778TESTATOPLANAR(ARGB1555, 2, 1, I420, 2, 2, 15)
779TESTATOPLANAR(ARGB4444, 2, 1, I420, 2, 2, 17)
780TESTATOPLANAR(ARGB, 4, 1, I411, 4, 1, 4)
781TESTATOPLANAR(ARGB, 4, 1, I422, 2, 1, 2)
782TESTATOPLANAR(ARGB, 4, 1, I444, 1, 1, 2)
783TESTATOPLANAR(YUY2, 2, 1, I420, 2, 2, 2)
784TESTATOPLANAR(UYVY, 2, 1, I420, 2, 2, 2)
785TESTATOPLANAR(YUY2, 2, 1, I422, 2, 1, 2)
786TESTATOPLANAR(UYVY, 2, 1, I422, 2, 1, 2)
787TESTATOPLANAR(I400, 1, 1, I420, 2, 2, 2)
788TESTATOPLANAR(J400, 1, 1, J420, 2, 2, 2)
789
790#define TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR,                      \
791                         SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF)             \
792TEST_F(LibYUVConvertTest, FMT_A##To##FMT_PLANAR##N) {                          \
793  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
794  const int kHeight = benchmark_height_;                                       \
795  const int kStride = SUBSAMPLE(kWidth, SUB_A) * BPP_A;                        \
796  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                          \
797  align_buffer_page_end(src_argb, kStride * kHeight + OFF);                    \
798  align_buffer_page_end(dst_y_c, kWidth * kHeight);                            \
799  align_buffer_page_end(dst_uv_c,                                              \
800                        kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));        \
801  align_buffer_page_end(dst_y_opt, kWidth * kHeight);                          \
802  align_buffer_page_end(dst_uv_opt,                                            \
803                        kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));        \
804  for (int i = 0; i < kHeight; ++i)                                            \
805    for (int j = 0; j < kStride; ++j)                                          \
806      src_argb[(i * kStride) + j + OFF] = (fastrand() & 0xff);                 \
807  memset(dst_y_c, 1, kWidth * kHeight);                                        \
808  memset(dst_uv_c, 2, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));          \
809  memset(dst_y_opt, 101, kWidth * kHeight);                                    \
810  memset(dst_uv_opt, 102, kStrideUV * 2 * SUBSAMPLE(kHeight, SUBSAMP_Y));      \
811  MaskCpuFlags(disable_cpu_flags_);                                            \
812  FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride,                               \
813                        dst_y_c, kWidth, dst_uv_c, kStrideUV * 2,              \
814                        kWidth, NEG kHeight);                                  \
815  MaskCpuFlags(benchmark_cpu_info_);                                           \
816  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
817    FMT_A##To##FMT_PLANAR(src_argb + OFF, kStride,                             \
818                          dst_y_opt, kWidth,                                   \
819                          dst_uv_opt, kStrideUV * 2, kWidth, NEG kHeight);     \
820  }                                                                            \
821  int max_diff = 0;                                                            \
822  for (int i = 0; i < kHeight; ++i) {                                          \
823    for (int j = 0; j < kWidth; ++j) {                                         \
824      int abs_diff =                                                           \
825          abs(static_cast<int>(dst_y_c[i * kWidth + j]) -                      \
826              static_cast<int>(dst_y_opt[i * kWidth + j]));                    \
827      if (abs_diff > max_diff) {                                               \
828        max_diff = abs_diff;                                                   \
829      }                                                                        \
830    }                                                                          \
831  }                                                                            \
832  EXPECT_LE(max_diff, 4);                                                      \
833  for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) {                    \
834    for (int j = 0; j < kStrideUV * 2; ++j) {                                  \
835      int abs_diff =                                                           \
836          abs(static_cast<int>(dst_uv_c[i * kStrideUV * 2 + j]) -              \
837              static_cast<int>(dst_uv_opt[i * kStrideUV * 2 + j]));            \
838      if (abs_diff > max_diff) {                                               \
839        max_diff = abs_diff;                                                   \
840      }                                                                        \
841    }                                                                          \
842  }                                                                            \
843  EXPECT_LE(max_diff, 4);                                                      \
844  free_aligned_buffer_page_end(dst_y_c);                                       \
845  free_aligned_buffer_page_end(dst_uv_c);                                      \
846  free_aligned_buffer_page_end(dst_y_opt);                                     \
847  free_aligned_buffer_page_end(dst_uv_opt);                                    \
848  free_aligned_buffer_page_end(src_argb);                                      \
849}
850
851#define TESTATOBIPLANAR(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \
852    TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,    \
853                     benchmark_width_ - 4, _Any, +, 0)                         \
854    TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,    \
855                     benchmark_width_, _Unaligned, +, 1)                       \
856    TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,    \
857                     benchmark_width_, _Invert, -, 0)                          \
858    TESTATOBIPLANARI(FMT_A, SUB_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y,    \
859                     benchmark_width_, _Opt, +, 0)
860
861TESTATOBIPLANAR(ARGB, 1, 4, NV12, 2, 2)
862TESTATOBIPLANAR(ARGB, 1, 4, NV21, 2, 2)
863TESTATOBIPLANAR(YUY2, 2, 4, NV12, 2, 2)
864TESTATOBIPLANAR(UYVY, 2, 4, NV12, 2, 2)
865
866#define TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                            \
867                  FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                            \
868                  W1280, DIFF, N, NEG, OFF)                                    \
869TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##N) {                               \
870  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
871  const int kHeight = benchmark_height_;                                       \
872  const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;         \
873  const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;         \
874  const int kStrideA = (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;  \
875  const int kStrideB = (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;  \
876  align_buffer_page_end(src_argb, kStrideA * kHeightA + OFF);                  \
877  align_buffer_page_end(dst_argb_c, kStrideB * kHeightB);                      \
878  align_buffer_page_end(dst_argb_opt, kStrideB * kHeightB);                    \
879  for (int i = 0; i < kStrideA * kHeightA; ++i) {                              \
880    src_argb[i + OFF] = (fastrand() & 0xff);                                   \
881  }                                                                            \
882  memset(dst_argb_c, 1, kStrideB * kHeightB);                                  \
883  memset(dst_argb_opt, 101, kStrideB * kHeightB);                              \
884  MaskCpuFlags(disable_cpu_flags_);                                            \
885  FMT_A##To##FMT_B(src_argb + OFF, kStrideA,                                   \
886                   dst_argb_c, kStrideB,                                       \
887                   kWidth, NEG kHeight);                                       \
888  MaskCpuFlags(benchmark_cpu_info_);                                           \
889  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
890    FMT_A##To##FMT_B(src_argb + OFF, kStrideA,                                 \
891                     dst_argb_opt, kStrideB,                                   \
892                     kWidth, NEG kHeight);                                     \
893  }                                                                            \
894  int max_diff = 0;                                                            \
895  for (int i = 0; i < kStrideB * kHeightB; ++i) {                              \
896    int abs_diff =                                                             \
897        abs(static_cast<int>(dst_argb_c[i]) -                                  \
898            static_cast<int>(dst_argb_opt[i]));                                \
899    if (abs_diff > max_diff) {                                                 \
900      max_diff = abs_diff;                                                     \
901    }                                                                          \
902  }                                                                            \
903  EXPECT_LE(max_diff, DIFF);                                                   \
904  free_aligned_buffer_page_end(src_argb);                                      \
905  free_aligned_buffer_page_end(dst_argb_c);                                    \
906  free_aligned_buffer_page_end(dst_argb_opt);                                  \
907}
908
909#define TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                       \
910                       FMT_B, BPP_B, STRIDE_B, HEIGHT_B, DIFF)                 \
911TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_Random) {                         \
912  for (int times = 0; times < benchmark_iterations_; ++times) {                \
913    const int kWidth = (fastrand() & 63) + 1;                                  \
914    const int kHeight = (fastrand() & 31) + 1;                                 \
915    const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;       \
916    const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;       \
917    const int kStrideA = (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;\
918    const int kStrideB = (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;\
919    align_buffer_page_end(src_argb, kStrideA * kHeightA);                      \
920    align_buffer_page_end(dst_argb_c, kStrideB * kHeightB);                    \
921    align_buffer_page_end(dst_argb_opt, kStrideB * kHeightB);                  \
922    for (int i = 0; i < kStrideA * kHeightA; ++i) {                            \
923      src_argb[i] = (fastrand() & 0xff);                                       \
924    }                                                                          \
925    memset(dst_argb_c, 123, kStrideB * kHeightB);                              \
926    memset(dst_argb_opt, 123, kStrideB * kHeightB);                            \
927    MaskCpuFlags(disable_cpu_flags_);                                          \
928    FMT_A##To##FMT_B(src_argb, kStrideA,                                       \
929                     dst_argb_c, kStrideB,                                     \
930                     kWidth, kHeight);                                         \
931    MaskCpuFlags(benchmark_cpu_info_);                                         \
932    FMT_A##To##FMT_B(src_argb, kStrideA,                                       \
933                     dst_argb_opt, kStrideB,                                   \
934                     kWidth, kHeight);                                         \
935    int max_diff = 0;                                                          \
936    for (int i = 0; i < kStrideB * kHeightB; ++i) {                            \
937      int abs_diff =                                                           \
938          abs(static_cast<int>(dst_argb_c[i]) -                                \
939              static_cast<int>(dst_argb_opt[i]));                              \
940      if (abs_diff > max_diff) {                                               \
941        max_diff = abs_diff;                                                   \
942      }                                                                        \
943    }                                                                          \
944    EXPECT_LE(max_diff, DIFF);                                                 \
945    free_aligned_buffer_page_end(src_argb);                                    \
946    free_aligned_buffer_page_end(dst_argb_c);                                  \
947    free_aligned_buffer_page_end(dst_argb_opt);                                \
948  }                                                                            \
949}
950
951#define TESTATOB(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                             \
952                 FMT_B, BPP_B, STRIDE_B, HEIGHT_B, DIFF)                       \
953    TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                                \
954              FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                                \
955              benchmark_width_ - 4, DIFF, _Any, +, 0)                          \
956    TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                                \
957              FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                                \
958              benchmark_width_, DIFF, _Unaligned, +, 1)                        \
959    TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                                \
960              FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                                \
961              benchmark_width_, DIFF, _Invert, -, 0)                           \
962    TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                                \
963              FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                                \
964              benchmark_width_, DIFF, _Opt, +, 0)                              \
965    TESTATOBRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                           \
966                   FMT_B, BPP_B, STRIDE_B, HEIGHT_B, DIFF)
967
968TESTATOB(ARGB, 4, 4, 1, ARGB, 4, 4, 1, 0)
969TESTATOB(ARGB, 4, 4, 1, BGRA, 4, 4, 1, 0)
970TESTATOB(ARGB, 4, 4, 1, ABGR, 4, 4, 1, 0)
971TESTATOB(ARGB, 4, 4, 1, RGBA, 4, 4, 1, 0)
972TESTATOB(ARGB, 4, 4, 1, RAW, 3, 3, 1, 0)
973TESTATOB(ARGB, 4, 4, 1, RGB24, 3, 3, 1, 0)
974TESTATOB(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
975TESTATOB(ARGB, 4, 4, 1, ARGB1555, 2, 2, 1, 0)
976TESTATOB(ARGB, 4, 4, 1, ARGB4444, 2, 2, 1, 0)
977TESTATOB(ARGB, 4, 4, 1, YUY2, 2, 4, 1, 4)
978TESTATOB(ARGB, 4, 4, 1, UYVY, 2, 4, 1, 4)
979TESTATOB(ARGB, 4, 4, 1, I400, 1, 1, 1, 2)
980TESTATOB(ARGB, 4, 4, 1, J400, 1, 1, 1, 2)
981TESTATOB(BGRA, 4, 4, 1, ARGB, 4, 4, 1, 0)
982TESTATOB(ABGR, 4, 4, 1, ARGB, 4, 4, 1, 0)
983TESTATOB(RGBA, 4, 4, 1, ARGB, 4, 4, 1, 0)
984TESTATOB(RAW, 3, 3, 1, ARGB, 4, 4, 1, 0)
985TESTATOB(RAW, 3, 3, 1, RGB24, 3, 3, 1, 0)
986TESTATOB(RGB24, 3, 3, 1, ARGB, 4, 4, 1, 0)
987TESTATOB(RGB565, 2, 2, 1, ARGB, 4, 4, 1, 0)
988TESTATOB(ARGB1555, 2, 2, 1, ARGB, 4, 4, 1, 0)
989TESTATOB(ARGB4444, 2, 2, 1, ARGB, 4, 4, 1, 0)
990TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, 4)
991TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, 4)
992TESTATOB(I400, 1, 1, 1, ARGB, 4, 4, 1, 0)
993TESTATOB(J400, 1, 1, 1, ARGB, 4, 4, 1, 0)
994TESTATOB(I400, 1, 1, 1, I400, 1, 1, 1, 0)
995TESTATOB(J400, 1, 1, 1, J400, 1, 1, 1, 0)
996TESTATOB(I400, 1, 1, 1, I400Mirror, 1, 1, 1, 0)
997TESTATOB(ARGB, 4, 4, 1, ARGBMirror, 4, 4, 1, 0)
998
999#define TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                           \
1000                   FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                           \
1001                   W1280, DIFF, N, NEG, OFF)                                   \
1002TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither##N) {                       \
1003  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
1004  const int kHeight = benchmark_height_;                                       \
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 = (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;  \
1008  const int kStrideB = (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;  \
1009  align_buffer_page_end(src_argb, kStrideA * kHeightA + OFF);                  \
1010  align_buffer_page_end(dst_argb_c, kStrideB * kHeightB);                      \
1011  align_buffer_page_end(dst_argb_opt, kStrideB * kHeightB);                    \
1012  for (int i = 0; i < kStrideA * kHeightA; ++i) {                              \
1013    src_argb[i + OFF] = (fastrand() & 0xff);                                   \
1014  }                                                                            \
1015  memset(dst_argb_c, 1, kStrideB * kHeightB);                                  \
1016  memset(dst_argb_opt, 101, kStrideB * kHeightB);                              \
1017  MaskCpuFlags(disable_cpu_flags_);                                            \
1018  FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA,                           \
1019                           dst_argb_c, kStrideB,                               \
1020                           NULL, kWidth, NEG kHeight);                         \
1021  MaskCpuFlags(benchmark_cpu_info_);                                           \
1022  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
1023    FMT_A##To##FMT_B##Dither(src_argb + OFF, kStrideA,                         \
1024                             dst_argb_opt, kStrideB,                           \
1025                             NULL, kWidth, NEG kHeight);                       \
1026  }                                                                            \
1027  int max_diff = 0;                                                            \
1028  for (int i = 0; i < kStrideB * kHeightB; ++i) {                              \
1029    int abs_diff =                                                             \
1030        abs(static_cast<int>(dst_argb_c[i]) -                                  \
1031            static_cast<int>(dst_argb_opt[i]));                                \
1032    if (abs_diff > max_diff) {                                                 \
1033      max_diff = abs_diff;                                                     \
1034    }                                                                          \
1035  }                                                                            \
1036  EXPECT_LE(max_diff, DIFF);                                                   \
1037  free_aligned_buffer_page_end(src_argb);                                      \
1038  free_aligned_buffer_page_end(dst_argb_c);                                    \
1039  free_aligned_buffer_page_end(dst_argb_opt);                                  \
1040}
1041
1042#define TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                      \
1043                       FMT_B, BPP_B, STRIDE_B, HEIGHT_B, DIFF)                 \
1044TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##Dither_Random) {                   \
1045  for (int times = 0; times < benchmark_iterations_; ++times) {                \
1046    const int kWidth = (fastrand() & 63) + 1;                                  \
1047    const int kHeight = (fastrand() & 31) + 1;                                 \
1048    const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;       \
1049    const int kHeightB = (kHeight + HEIGHT_B - 1) / HEIGHT_B * HEIGHT_B;       \
1050    const int kStrideA = (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;\
1051    const int kStrideB = (kWidth * BPP_B + STRIDE_B - 1) / STRIDE_B * STRIDE_B;\
1052    align_buffer_page_end(src_argb, kStrideA * kHeightA);                      \
1053    align_buffer_page_end(dst_argb_c, kStrideB * kHeightB);                    \
1054    align_buffer_page_end(dst_argb_opt, kStrideB * kHeightB);                  \
1055    for (int i = 0; i < kStrideA * kHeightA; ++i) {                            \
1056      src_argb[i] = (fastrand() & 0xff);                                       \
1057    }                                                                          \
1058    memset(dst_argb_c, 123, kStrideB * kHeightB);                              \
1059    memset(dst_argb_opt, 123, kStrideB * kHeightB);                            \
1060    MaskCpuFlags(disable_cpu_flags_);                                          \
1061    FMT_A##To##FMT_B##Dither(src_argb, kStrideA,                               \
1062                             dst_argb_c, kStrideB,                             \
1063                             NULL, kWidth, kHeight);                           \
1064    MaskCpuFlags(benchmark_cpu_info_);                                         \
1065    FMT_A##To##FMT_B##Dither(src_argb, kStrideA,                               \
1066                             dst_argb_opt, kStrideB,                           \
1067                             NULL, kWidth, kHeight);                           \
1068    int max_diff = 0;                                                          \
1069    for (int i = 0; i < kStrideB * kHeightB; ++i) {                            \
1070      int abs_diff =                                                           \
1071          abs(static_cast<int>(dst_argb_c[i]) -                                \
1072              static_cast<int>(dst_argb_opt[i]));                              \
1073      if (abs_diff > max_diff) {                                               \
1074        max_diff = abs_diff;                                                   \
1075      }                                                                        \
1076    }                                                                          \
1077    EXPECT_LE(max_diff, DIFF);                                                 \
1078    free_aligned_buffer_page_end(src_argb);                                    \
1079    free_aligned_buffer_page_end(dst_argb_c);                                  \
1080    free_aligned_buffer_page_end(dst_argb_opt);                                \
1081  }                                                                            \
1082}
1083
1084#define TESTATOBD(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                            \
1085                  FMT_B, BPP_B, STRIDE_B, HEIGHT_B, DIFF)                      \
1086    TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                               \
1087               FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                               \
1088               benchmark_width_ - 4, DIFF, _Any, +, 0)                         \
1089    TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                               \
1090               FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                               \
1091               benchmark_width_, DIFF, _Unaligned, +, 1)                       \
1092    TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                               \
1093               FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                               \
1094               benchmark_width_, DIFF, _Invert, -, 0)                          \
1095    TESTATOBDI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                               \
1096               FMT_B, BPP_B, STRIDE_B, HEIGHT_B,                               \
1097               benchmark_width_, DIFF, _Opt, +, 0)                             \
1098    TESTATOBDRANDOM(FMT_A, BPP_A, STRIDE_A, HEIGHT_A,                          \
1099                    FMT_B, BPP_B, STRIDE_B, HEIGHT_B, DIFF)
1100
1101TESTATOBD(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0)
1102
1103#define TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A,                          \
1104                 W1280, N, NEG, OFF)                                           \
1105TEST_F(LibYUVConvertTest, FMT_ATOB##_Symetric##N) {                            \
1106  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
1107  const int kHeight = benchmark_height_;                                       \
1108  const int kHeightA = (kHeight + HEIGHT_A - 1) / HEIGHT_A * HEIGHT_A;         \
1109  const int kStrideA = (kWidth * BPP_A + STRIDE_A - 1) / STRIDE_A * STRIDE_A;  \
1110  align_buffer_page_end(src_argb, kStrideA * kHeightA + OFF);                  \
1111  align_buffer_page_end(dst_argb_c, kStrideA * kHeightA);                      \
1112  align_buffer_page_end(dst_argb_opt, kStrideA * kHeightA);                    \
1113  for (int i = 0; i < kStrideA * kHeightA; ++i) {                              \
1114    src_argb[i + OFF] = (fastrand() & 0xff);                                   \
1115  }                                                                            \
1116  memset(dst_argb_c, 1, kStrideA * kHeightA);                                  \
1117  memset(dst_argb_opt, 101, kStrideA * kHeightA);                              \
1118  MaskCpuFlags(disable_cpu_flags_);                                            \
1119  FMT_ATOB(src_argb + OFF, kStrideA,                                           \
1120           dst_argb_c, kStrideA,                                               \
1121           kWidth, NEG kHeight);                                               \
1122  MaskCpuFlags(benchmark_cpu_info_);                                           \
1123  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
1124    FMT_ATOB(src_argb + OFF, kStrideA,                                         \
1125             dst_argb_opt, kStrideA,                                           \
1126             kWidth, NEG kHeight);                                             \
1127  }                                                                            \
1128  MaskCpuFlags(disable_cpu_flags_);                                            \
1129  FMT_ATOB(dst_argb_c, kStrideA,                                               \
1130           dst_argb_c, kStrideA,                                               \
1131           kWidth, NEG kHeight);                                               \
1132  MaskCpuFlags(benchmark_cpu_info_);                                           \
1133  FMT_ATOB(dst_argb_opt, kStrideA,                                             \
1134           dst_argb_opt, kStrideA,                                             \
1135           kWidth, NEG kHeight);                                               \
1136  for (int i = 0; i < kStrideA * kHeightA; ++i) {                              \
1137    EXPECT_EQ(src_argb[i + OFF], dst_argb_opt[i]);                             \
1138    EXPECT_EQ(dst_argb_c[i], dst_argb_opt[i]);                                 \
1139  }                                                                            \
1140  free_aligned_buffer_page_end(src_argb);                                      \
1141  free_aligned_buffer_page_end(dst_argb_c);                                    \
1142  free_aligned_buffer_page_end(dst_argb_opt);                                  \
1143}
1144
1145#define TESTSYM(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A)                           \
1146    TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A,                              \
1147             benchmark_width_ - 4, _Any, +, 0)                                 \
1148    TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A,                              \
1149             benchmark_width_, _Unaligned, +, 1)                               \
1150    TESTSYMI(FMT_ATOB, BPP_A, STRIDE_A, HEIGHT_A,                              \
1151             benchmark_width_, _Opt, +, 0)
1152
1153TESTSYM(ARGBToARGB, 4, 4, 1)
1154TESTSYM(ARGBToBGRA, 4, 4, 1)
1155TESTSYM(ARGBToABGR, 4, 4, 1)
1156TESTSYM(BGRAToARGB, 4, 4, 1)
1157TESTSYM(ABGRToARGB, 4, 4, 1)
1158
1159TEST_F(LibYUVConvertTest, Test565) {
1160  SIMD_ALIGNED(uint8 orig_pixels[256][4]);
1161  SIMD_ALIGNED(uint8 pixels565[256][2]);
1162
1163  for (int i = 0; i < 256; ++i) {
1164    for (int j = 0; j < 4; ++j) {
1165      orig_pixels[i][j] = i;
1166    }
1167  }
1168  ARGBToRGB565(&orig_pixels[0][0], 0, &pixels565[0][0], 0, 256, 1);
1169  uint32 checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381);
1170  EXPECT_EQ(610919429u, checksum);
1171}
1172
1173#ifdef HAVE_JPEG
1174TEST_F(LibYUVConvertTest, ValidateJpeg) {
1175  const int kOff = 10;
1176  const int kMinJpeg = 64;
1177  const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg ?
1178    benchmark_width_ * benchmark_height_ : kMinJpeg;
1179  const int kSize = kImageSize + kOff;
1180  align_buffer_page_end(orig_pixels, kSize);
1181
1182  // No SOI or EOI. Expect fail.
1183  memset(orig_pixels, 0, kSize);
1184  EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1185
1186  // Test special value that matches marker start.
1187  memset(orig_pixels, 0xff, kSize);
1188  EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1189
1190  // EOI, SOI. Expect pass.
1191  orig_pixels[0] = 0xff;
1192  orig_pixels[1] = 0xd8;  // SOI.
1193  orig_pixels[kSize - kOff + 0] = 0xff;
1194  orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1195  for (int times = 0; times < benchmark_iterations_; ++times) {
1196    EXPECT_TRUE(ValidateJpeg(orig_pixels, kSize));
1197  }
1198  free_aligned_buffer_page_end(orig_pixels);
1199}
1200
1201TEST_F(LibYUVConvertTest, ValidateJpegLarge) {
1202  const int kOff = 10;
1203  const int kMinJpeg = 64;
1204  const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg ?
1205    benchmark_width_ * benchmark_height_ : kMinJpeg;
1206  const int kSize = kImageSize + kOff;
1207  const int kMultiple = 10;
1208  const int kBufSize = kImageSize * kMultiple + kOff;
1209  align_buffer_page_end(orig_pixels, kBufSize);
1210
1211  // No SOI or EOI. Expect fail.
1212  memset(orig_pixels, 0, kBufSize);
1213  EXPECT_FALSE(ValidateJpeg(orig_pixels, kBufSize));
1214
1215  // EOI, SOI. Expect pass.
1216  orig_pixels[0] = 0xff;
1217  orig_pixels[1] = 0xd8;  // SOI.
1218  orig_pixels[kSize - kOff + 0] = 0xff;
1219  orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1220  for (int times = 0; times < benchmark_iterations_; ++times) {
1221    EXPECT_TRUE(ValidateJpeg(orig_pixels, kBufSize));
1222  }
1223  free_aligned_buffer_page_end(orig_pixels);
1224}
1225
1226TEST_F(LibYUVConvertTest, InvalidateJpeg) {
1227  const int kOff = 10;
1228  const int kMinJpeg = 64;
1229  const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg ?
1230    benchmark_width_ * benchmark_height_ : kMinJpeg;
1231  const int kSize = kImageSize + kOff;
1232  align_buffer_page_end(orig_pixels, kSize);
1233
1234  // NULL pointer. Expect fail.
1235  EXPECT_FALSE(ValidateJpeg(NULL, kSize));
1236
1237  // Negative size. Expect fail.
1238  EXPECT_FALSE(ValidateJpeg(orig_pixels, -1));
1239
1240  // Too large size. Expect fail.
1241  EXPECT_FALSE(ValidateJpeg(orig_pixels, 0xfb000000ull));
1242
1243  // No SOI or EOI. Expect fail.
1244  memset(orig_pixels, 0, kSize);
1245  EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1246
1247  // SOI but no EOI. Expect fail.
1248  orig_pixels[0] = 0xff;
1249  orig_pixels[1] = 0xd8;  // SOI.
1250  for (int times = 0; times < benchmark_iterations_; ++times) {
1251    EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1252  }
1253
1254  // EOI but no SOI. Expect fail.
1255  orig_pixels[0] = 0;
1256  orig_pixels[1] = 0;
1257  orig_pixels[kSize - kOff + 0] = 0xff;
1258  orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1259  EXPECT_FALSE(ValidateJpeg(orig_pixels, kSize));
1260
1261  free_aligned_buffer_page_end(orig_pixels);
1262}
1263
1264TEST_F(LibYUVConvertTest, FuzzJpeg) {
1265  // SOI but no EOI. Expect fail.
1266  for (int times = 0; times < benchmark_iterations_; ++times) {
1267    const int kSize = fastrand() % 5000 + 2;
1268    align_buffer_page_end(orig_pixels, kSize);
1269    MemRandomize(orig_pixels, kSize);
1270
1271    // Add SOI so frame will be scanned.
1272    orig_pixels[0] = 0xff;
1273    orig_pixels[1] = 0xd8;  // SOI.
1274    orig_pixels[kSize - 1] = 0xff;
1275    ValidateJpeg(orig_pixels, kSize);  // Failure normally expected.
1276    free_aligned_buffer_page_end(orig_pixels);
1277  }
1278}
1279
1280TEST_F(LibYUVConvertTest, MJPGToI420) {
1281  const int kOff = 10;
1282  const int kMinJpeg = 64;
1283  const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg ?
1284    benchmark_width_ * benchmark_height_ : kMinJpeg;
1285  const int kSize = kImageSize + kOff;
1286  align_buffer_page_end(orig_pixels, kSize);
1287  align_buffer_page_end(dst_y_opt, benchmark_width_ * benchmark_height_);
1288  align_buffer_page_end(dst_u_opt,
1289                        SUBSAMPLE(benchmark_width_, 2) *
1290                        SUBSAMPLE(benchmark_height_, 2));
1291  align_buffer_page_end(dst_v_opt,
1292                        SUBSAMPLE(benchmark_width_, 2) *
1293                        SUBSAMPLE(benchmark_height_, 2));
1294
1295  // EOI, SOI to make MJPG appear valid.
1296  memset(orig_pixels, 0, kSize);
1297  orig_pixels[0] = 0xff;
1298  orig_pixels[1] = 0xd8;  // SOI.
1299  orig_pixels[kSize - kOff + 0] = 0xff;
1300  orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1301
1302  for (int times = 0; times < benchmark_iterations_; ++times) {
1303    int ret = MJPGToI420(orig_pixels, kSize,
1304                         dst_y_opt, benchmark_width_,
1305                         dst_u_opt, SUBSAMPLE(benchmark_width_, 2),
1306                         dst_v_opt, SUBSAMPLE(benchmark_width_, 2),
1307                         benchmark_width_, benchmark_height_,
1308                         benchmark_width_, benchmark_height_);
1309    // Expect failure because image is not really valid.
1310    EXPECT_EQ(1, ret);
1311  }
1312
1313  free_aligned_buffer_page_end(dst_y_opt);
1314  free_aligned_buffer_page_end(dst_u_opt);
1315  free_aligned_buffer_page_end(dst_v_opt);
1316  free_aligned_buffer_page_end(orig_pixels);
1317}
1318
1319TEST_F(LibYUVConvertTest, MJPGToARGB) {
1320  const int kOff = 10;
1321  const int kMinJpeg = 64;
1322  const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg ?
1323    benchmark_width_ * benchmark_height_ : kMinJpeg;
1324  const int kSize = kImageSize + kOff;
1325  align_buffer_page_end(orig_pixels, kSize);
1326  align_buffer_page_end(dst_argb_opt, benchmark_width_ * benchmark_height_ * 4);
1327
1328  // EOI, SOI to make MJPG appear valid.
1329  memset(orig_pixels, 0, kSize);
1330  orig_pixels[0] = 0xff;
1331  orig_pixels[1] = 0xd8;  // SOI.
1332  orig_pixels[kSize - kOff + 0] = 0xff;
1333  orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.
1334
1335  for (int times = 0; times < benchmark_iterations_; ++times) {
1336    int ret = MJPGToARGB(orig_pixels, kSize,
1337                         dst_argb_opt, benchmark_width_ * 4,
1338                         benchmark_width_, benchmark_height_,
1339                         benchmark_width_, benchmark_height_);
1340    // Expect failure because image is not really valid.
1341    EXPECT_EQ(1, ret);
1342  }
1343
1344  free_aligned_buffer_page_end(dst_argb_opt);
1345  free_aligned_buffer_page_end(orig_pixels);
1346}
1347
1348#endif  // HAVE_JPEG
1349
1350TEST_F(LibYUVConvertTest, NV12Crop) {
1351  const int SUBSAMP_X = 2;
1352  const int SUBSAMP_Y = 2;
1353  const int kWidth = benchmark_width_;
1354  const int kHeight = benchmark_height_;
1355  const int crop_y =
1356    ((benchmark_height_ - (benchmark_height_ * 360 / 480)) / 2 + 1) & ~1;
1357  const int kDestWidth = benchmark_width_;
1358  const int kDestHeight = benchmark_height_ - crop_y * 2;
1359  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);
1360  const int sample_size = kWidth * kHeight +
1361    kStrideUV *
1362    SUBSAMPLE(kHeight, SUBSAMP_Y) * 2;
1363  align_buffer_page_end(src_y, sample_size);
1364  uint8* src_uv = src_y + kWidth * kHeight;
1365
1366  align_buffer_page_end(dst_y, kDestWidth * kDestHeight);
1367  align_buffer_page_end(dst_u,
1368                  SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1369                  SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1370  align_buffer_page_end(dst_v,
1371                  SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1372                  SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1373
1374  align_buffer_page_end(dst_y_2, kDestWidth * kDestHeight);
1375  align_buffer_page_end(dst_u_2,
1376                  SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1377                  SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1378  align_buffer_page_end(dst_v_2,
1379                  SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1380                  SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1381
1382  for (int i = 0; i < kHeight * kWidth; ++i) {
1383    src_y[i] = (fastrand() & 0xff);
1384  }
1385  for (int i = 0; i < (SUBSAMPLE(kHeight, SUBSAMP_Y) *
1386       kStrideUV) * 2; ++i) {
1387    src_uv[i] = (fastrand() & 0xff);
1388  }
1389  memset(dst_y, 1, kDestWidth * kDestHeight);
1390  memset(dst_u, 2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1391                   SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1392  memset(dst_v, 3, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1393                   SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1394  memset(dst_y_2, 1, kDestWidth * kDestHeight);
1395  memset(dst_u_2, 2, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1396                     SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1397  memset(dst_v_2, 3, SUBSAMPLE(kDestWidth, SUBSAMP_X) *
1398                     SUBSAMPLE(kDestHeight, SUBSAMP_Y));
1399
1400  ConvertToI420(src_y, sample_size,
1401                dst_y_2, kDestWidth,
1402                dst_u_2, SUBSAMPLE(kDestWidth, SUBSAMP_X),
1403                dst_v_2, SUBSAMPLE(kDestWidth, SUBSAMP_X),
1404                0, crop_y,
1405                kWidth, kHeight,
1406                kDestWidth, kDestHeight,
1407                libyuv::kRotate0, libyuv::FOURCC_NV12);
1408
1409  NV12ToI420(src_y + crop_y * kWidth, kWidth,
1410             src_uv + (crop_y / 2) * kStrideUV * 2,
1411               kStrideUV * 2,
1412             dst_y, kDestWidth,
1413             dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X),
1414             dst_v, SUBSAMPLE(kDestWidth, SUBSAMP_X),
1415             kDestWidth, kDestHeight);
1416
1417  for (int i = 0; i < kDestHeight; ++i) {
1418    for (int j = 0; j < kDestWidth; ++j) {
1419      EXPECT_EQ(dst_y[i * kWidth + j], dst_y_2[i * kWidth + j]);
1420    }
1421  }
1422  for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1423    for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1424      EXPECT_EQ(dst_u[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1425                dst_u_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1426    }
1427  }
1428  for (int i = 0; i < SUBSAMPLE(kDestHeight, SUBSAMP_Y); ++i) {
1429    for (int j = 0; j < SUBSAMPLE(kDestWidth, SUBSAMP_X); ++j) {
1430      EXPECT_EQ(dst_v[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j],
1431                dst_v_2[i * SUBSAMPLE(kDestWidth, SUBSAMP_X) + j]);
1432    }
1433  }
1434  free_aligned_buffer_page_end(dst_y);
1435  free_aligned_buffer_page_end(dst_u);
1436  free_aligned_buffer_page_end(dst_v);
1437  free_aligned_buffer_page_end(dst_y_2);
1438  free_aligned_buffer_page_end(dst_u_2);
1439  free_aligned_buffer_page_end(dst_v_2);
1440  free_aligned_buffer_page_end(src_y);
1441}
1442
1443TEST_F(LibYUVConvertTest, TestYToARGB) {
1444  uint8 y[32];
1445  uint8 expectedg[32];
1446  for (int i = 0; i < 32; ++i) {
1447    y[i] = i * 5 + 17;
1448    expectedg[i] = static_cast<int>((y[i] - 16) * 1.164f + 0.5f);
1449  }
1450  uint8 argb[32 * 4];
1451  YToARGB(y, 0, argb, 0, 32, 1);
1452
1453  for (int i = 0; i < 32; ++i) {
1454    printf("%2d %d: %d <-> %d,%d,%d,%d\n", i, y[i], expectedg[i],
1455           argb[i * 4 + 0],
1456           argb[i * 4 + 1],
1457           argb[i * 4 + 2],
1458           argb[i * 4 + 3]);
1459  }
1460  for (int i = 0; i < 32; ++i) {
1461    EXPECT_EQ(expectedg[i], argb[i * 4 + 0]);
1462  }
1463}
1464
1465static const uint8 kNoDither4x4[16] = {
1466  0, 0, 0, 0,
1467  0, 0, 0, 0,
1468  0, 0, 0, 0,
1469  0, 0, 0, 0,
1470};
1471
1472TEST_F(LibYUVConvertTest, TestNoDither) {
1473  align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1474  align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1475  align_buffer_page_end(dst_rgb565dither,
1476                        benchmark_width_ * benchmark_height_ * 2);
1477  MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1478  MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1479  MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1480  ARGBToRGB565(src_argb, benchmark_width_ * 4,
1481               dst_rgb565, benchmark_width_ * 2,
1482               benchmark_width_, benchmark_height_);
1483  ARGBToRGB565Dither(src_argb, benchmark_width_ * 4,
1484                     dst_rgb565dither, benchmark_width_ * 2,
1485                     kNoDither4x4, benchmark_width_, benchmark_height_);
1486  for (int i = 0; i < benchmark_width_ * benchmark_height_ * 2; ++i) {
1487    EXPECT_EQ(dst_rgb565[i], dst_rgb565dither[i]);
1488  }
1489
1490  free_aligned_buffer_page_end(src_argb);
1491  free_aligned_buffer_page_end(dst_rgb565);
1492  free_aligned_buffer_page_end(dst_rgb565dither);
1493}
1494
1495// Ordered 4x4 dither for 888 to 565.  Values from 0 to 7.
1496static const uint8 kDither565_4x4[16] = {
1497  0, 4, 1, 5,
1498  6, 2, 7, 3,
1499  1, 5, 0, 4,
1500  7, 3, 6, 2,
1501};
1502
1503TEST_F(LibYUVConvertTest, TestDither) {
1504  align_buffer_page_end(src_argb, benchmark_width_ * benchmark_height_ * 4);
1505  align_buffer_page_end(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1506  align_buffer_page_end(dst_rgb565dither,
1507                        benchmark_width_ * benchmark_height_ * 2);
1508  align_buffer_page_end(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1509  align_buffer_page_end(dst_argbdither,
1510                        benchmark_width_ * benchmark_height_ * 4);
1511  MemRandomize(src_argb, benchmark_width_ * benchmark_height_ * 4);
1512  MemRandomize(dst_rgb565, benchmark_width_ * benchmark_height_ * 2);
1513  MemRandomize(dst_rgb565dither, benchmark_width_ * benchmark_height_ * 2);
1514  MemRandomize(dst_argb, benchmark_width_ * benchmark_height_ * 4);
1515  MemRandomize(dst_argbdither, benchmark_width_ * benchmark_height_ * 4);
1516  ARGBToRGB565(src_argb, benchmark_width_ * 4,
1517               dst_rgb565, benchmark_width_ * 2,
1518               benchmark_width_, benchmark_height_);
1519  ARGBToRGB565Dither(src_argb, benchmark_width_ * 4,
1520                     dst_rgb565dither, benchmark_width_ * 2,
1521                     kDither565_4x4, benchmark_width_, benchmark_height_);
1522  RGB565ToARGB(dst_rgb565, benchmark_width_ * 2,
1523               dst_argb, benchmark_width_ * 4,
1524               benchmark_width_, benchmark_height_);
1525  RGB565ToARGB(dst_rgb565dither, benchmark_width_ * 2,
1526               dst_argbdither, benchmark_width_ * 4,
1527               benchmark_width_, benchmark_height_);
1528
1529  for (int i = 0; i < benchmark_width_ * benchmark_height_ * 4; ++i) {
1530    EXPECT_NEAR(dst_argb[i], dst_argbdither[i], 9);
1531  }
1532  free_aligned_buffer_page_end(src_argb);
1533  free_aligned_buffer_page_end(dst_rgb565);
1534  free_aligned_buffer_page_end(dst_rgb565dither);
1535  free_aligned_buffer_page_end(dst_argb);
1536  free_aligned_buffer_page_end(dst_argbdither);
1537}
1538
1539#define TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
1540                       YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C)         \
1541TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##Dither##N) {                  \
1542  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
1543  const int kHeight = ALIGNINT(benchmark_height_, YALIGN);                     \
1544  const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN);                        \
1545  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                          \
1546  const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);               \
1547  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
1548  align_buffer_page_end(src_u, kSizeUV + OFF);                                 \
1549  align_buffer_page_end(src_v, kSizeUV + OFF);                                 \
1550  align_buffer_page_end(dst_argb_c, kStrideB * kHeight + OFF);                 \
1551  align_buffer_page_end(dst_argb_opt, kStrideB * kHeight + OFF);               \
1552  for (int i = 0; i < kWidth * kHeight; ++i) {                                 \
1553    src_y[i + OFF] = (fastrand() & 0xff);                                      \
1554  }                                                                            \
1555  for (int i = 0; i < kSizeUV; ++i) {                                          \
1556    src_u[i + OFF] = (fastrand() & 0xff);                                      \
1557    src_v[i + OFF] = (fastrand() & 0xff);                                      \
1558  }                                                                            \
1559  memset(dst_argb_c + OFF, 1, kStrideB * kHeight);                             \
1560  memset(dst_argb_opt + OFF, 101, kStrideB * kHeight);                         \
1561  MaskCpuFlags(disable_cpu_flags_);                                            \
1562  FMT_PLANAR##To##FMT_B##Dither(src_y + OFF, kWidth,                           \
1563                        src_u + OFF, kStrideUV,                                \
1564                        src_v + OFF, kStrideUV,                                \
1565                        dst_argb_c + OFF, kStrideB,                            \
1566                        NULL, kWidth, NEG kHeight);                            \
1567  MaskCpuFlags(benchmark_cpu_info_);                                           \
1568  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
1569    FMT_PLANAR##To##FMT_B##Dither(src_y + OFF, kWidth,                         \
1570                          src_u + OFF, kStrideUV,                              \
1571                          src_v + OFF, kStrideUV,                              \
1572                          dst_argb_opt + OFF, kStrideB,                        \
1573                          NULL, kWidth, NEG kHeight);                          \
1574  }                                                                            \
1575  int max_diff = 0;                                                            \
1576  /* Convert to ARGB so 565 is expanded to bytes that can be compared. */      \
1577  align_buffer_page_end(dst_argb32_c, kWidth * BPP_C  * kHeight);              \
1578  align_buffer_page_end(dst_argb32_opt, kWidth * BPP_C  * kHeight);            \
1579  memset(dst_argb32_c, 2, kWidth * BPP_C  * kHeight);                          \
1580  memset(dst_argb32_opt, 102, kWidth * BPP_C  * kHeight);                      \
1581  FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB,                                 \
1582                   dst_argb32_c, kWidth * BPP_C ,                              \
1583                   kWidth, kHeight);                                           \
1584  FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB,                               \
1585                   dst_argb32_opt, kWidth * BPP_C ,                            \
1586                   kWidth, kHeight);                                           \
1587  for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) {                         \
1588    int abs_diff =                                                             \
1589        abs(static_cast<int>(dst_argb32_c[i]) -                                \
1590            static_cast<int>(dst_argb32_opt[i]));                              \
1591    if (abs_diff > max_diff) {                                                 \
1592      max_diff = abs_diff;                                                     \
1593    }                                                                          \
1594  }                                                                            \
1595  EXPECT_LE(max_diff, DIFF);                                                   \
1596  free_aligned_buffer_page_end(src_y);                                         \
1597  free_aligned_buffer_page_end(src_u);                                         \
1598  free_aligned_buffer_page_end(src_v);                                         \
1599  free_aligned_buffer_page_end(dst_argb_c);                                    \
1600  free_aligned_buffer_page_end(dst_argb_opt);                                  \
1601  free_aligned_buffer_page_end(dst_argb32_c);                                  \
1602  free_aligned_buffer_page_end(dst_argb32_opt);                                \
1603}
1604
1605#define TESTPLANARTOBD(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,  \
1606                      YALIGN, DIFF, FMT_C, BPP_C)                              \
1607    TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
1608        YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C, BPP_C)          \
1609    TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
1610        YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C, BPP_C)        \
1611    TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
1612        YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C)           \
1613    TESTPLANARTOBID(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN,     \
1614        YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C)
1615
1616TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4)
1617
1618#define TESTPTOB(NAME, UYVYTOI420, UYVYTONV12)                                 \
1619TEST_F(LibYUVConvertTest, NAME) {                                              \
1620  const int kWidth = benchmark_width_;                                         \
1621  const int kHeight = benchmark_height_;                                       \
1622                                                                               \
1623  align_buffer_page_end(orig_uyvy,                                             \
1624                  4 * SUBSAMPLE(kWidth, 2) * kHeight);                         \
1625  align_buffer_page_end(orig_y, kWidth * kHeight);                             \
1626  align_buffer_page_end(orig_u,                                                \
1627                  SUBSAMPLE(kWidth, 2) *                                       \
1628                  SUBSAMPLE(kHeight, 2));                                      \
1629  align_buffer_page_end(orig_v,                                                \
1630                  SUBSAMPLE(kWidth, 2) *                                       \
1631                  SUBSAMPLE(kHeight, 2));                                      \
1632                                                                               \
1633  align_buffer_page_end(dst_y_orig, kWidth * kHeight);                         \
1634  align_buffer_page_end(dst_uv_orig, 2 *                                       \
1635                  SUBSAMPLE(kWidth, 2) *                                       \
1636                  SUBSAMPLE(kHeight, 2));                                      \
1637                                                                               \
1638  align_buffer_page_end(dst_y, kWidth * kHeight);                              \
1639  align_buffer_page_end(dst_uv, 2 *                                            \
1640                  SUBSAMPLE(kWidth, 2) *                                       \
1641                  SUBSAMPLE(kHeight, 2));                                      \
1642                                                                               \
1643  MemRandomize(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2) * kHeight);                 \
1644                                                                               \
1645  /* Convert UYVY to NV12 in 2 steps for reference */                          \
1646  libyuv::UYVYTOI420(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2),                      \
1647                     orig_y, kWidth,                                           \
1648                     orig_u, SUBSAMPLE(kWidth, 2),                             \
1649                     orig_v, SUBSAMPLE(kWidth, 2),                             \
1650                     kWidth, kHeight);                                         \
1651  libyuv::I420ToNV12(orig_y, kWidth,                                           \
1652                     orig_u, SUBSAMPLE(kWidth, 2),                             \
1653                     orig_v, SUBSAMPLE(kWidth, 2),                             \
1654                     dst_y_orig, kWidth,                                       \
1655                     dst_uv_orig, 2 * SUBSAMPLE(kWidth, 2),                    \
1656                     kWidth, kHeight);                                         \
1657                                                                               \
1658  /* Convert to NV12 */                                                        \
1659  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
1660    libyuv::UYVYTONV12(orig_uyvy, 4 * SUBSAMPLE(kWidth, 2),                    \
1661                       dst_y, kWidth,                                          \
1662                       dst_uv, 2 * SUBSAMPLE(kWidth, 2),                       \
1663                       kWidth, kHeight);                                       \
1664  }                                                                            \
1665                                                                               \
1666  for (int i = 0; i < kWidth * kHeight; ++i) {                                 \
1667    EXPECT_EQ(orig_y[i], dst_y[i]);                                            \
1668  }                                                                            \
1669  for (int i = 0; i < kWidth * kHeight; ++i) {                                 \
1670    EXPECT_EQ(dst_y_orig[i], dst_y[i]);                                        \
1671  }                                                                            \
1672  for (int i = 0; i < 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2); ++i) { \
1673    EXPECT_EQ(dst_uv_orig[i], dst_uv[i]);                                      \
1674  }                                                                            \
1675                                                                               \
1676  free_aligned_buffer_page_end(orig_uyvy);                                     \
1677  free_aligned_buffer_page_end(orig_y);                                        \
1678  free_aligned_buffer_page_end(orig_u);                                        \
1679  free_aligned_buffer_page_end(orig_v);                                        \
1680  free_aligned_buffer_page_end(dst_y_orig);                                    \
1681  free_aligned_buffer_page_end(dst_uv_orig);                                   \
1682  free_aligned_buffer_page_end(dst_y);                                         \
1683  free_aligned_buffer_page_end(dst_uv);                                        \
1684}
1685
1686TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12)
1687TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12)
1688
1689#define TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,  \
1690                       W1280, N, NEG, OFF, FMT_C, BPP_C)                       \
1691TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) {                \
1692  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
1693  const int kHeight = benchmark_height_;                                       \
1694  const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                       \
1695  const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X);                          \
1696  const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y);               \
1697  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
1698  align_buffer_page_end(src_u, kSizeUV + OFF);                                 \
1699  align_buffer_page_end(src_v, kSizeUV + OFF);                                 \
1700  align_buffer_page_end(dst_argb_b, kStrideB * kHeight + OFF);                 \
1701  for (int i = 0; i < kWidth * kHeight; ++i) {                                 \
1702    src_y[i + OFF] = (fastrand() & 0xff);                                      \
1703  }                                                                            \
1704  for (int i = 0; i < kSizeUV; ++i) {                                          \
1705    src_u[i + OFF] = (fastrand() & 0xff);                                      \
1706    src_v[i + OFF] = (fastrand() & 0xff);                                      \
1707  }                                                                            \
1708  memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                             \
1709  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
1710    FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                 \
1711                          src_u + OFF, kStrideUV,                              \
1712                          src_v + OFF, kStrideUV,                              \
1713                          dst_argb_b + OFF, kStrideB,                          \
1714                          kWidth, NEG kHeight);                                \
1715  }                                                                            \
1716  /* Convert to a 3rd format in 1 step and 2 steps and compare  */             \
1717  const int kStrideC = kWidth * BPP_C;                                         \
1718  align_buffer_page_end(dst_argb_c, kStrideC * kHeight + OFF);                 \
1719  align_buffer_page_end(dst_argb_bc, kStrideC * kHeight + OFF);                \
1720  memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                             \
1721  memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                            \
1722  FMT_PLANAR##To##FMT_C(src_y + OFF, kWidth,                                   \
1723                        src_u + OFF, kStrideUV,                                \
1724                        src_v + OFF, kStrideUV,                                \
1725                        dst_argb_c + OFF, kStrideC,                            \
1726                        kWidth, NEG kHeight);                                  \
1727  /* Convert B to C */                                                         \
1728  FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB,                                 \
1729                   dst_argb_bc + OFF, kStrideC,                                \
1730                   kWidth, kHeight);                                           \
1731  for (int i = 0; i < kStrideC * kHeight; ++i) {                               \
1732    EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]);                      \
1733  }                                                                            \
1734  free_aligned_buffer_page_end(src_y);                                         \
1735  free_aligned_buffer_page_end(src_u);                                         \
1736  free_aligned_buffer_page_end(src_v);                                         \
1737  free_aligned_buffer_page_end(dst_argb_b);                                    \
1738  free_aligned_buffer_page_end(dst_argb_c);                                    \
1739  free_aligned_buffer_page_end(dst_argb_bc);                                   \
1740}
1741
1742#define TESTPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,   \
1743                      FMT_C, BPP_C)                                            \
1744    TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1745        benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C)                        \
1746    TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1747        benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C)                      \
1748    TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1749        benchmark_width_, _Invert, -, 0, FMT_C, BPP_C)                         \
1750    TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,      \
1751        benchmark_width_, _Opt, +, 0, FMT_C, BPP_C)
1752
1753TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ABGR, 4)
1754TESTPLANARTOE(J420, 2, 2, ARGB, 1, 4, ARGB, 4)
1755TESTPLANARTOE(J420, 2, 2, ABGR, 1, 4, ARGB, 4)
1756TESTPLANARTOE(H420, 2, 2, ARGB, 1, 4, ARGB, 4)
1757TESTPLANARTOE(H420, 2, 2, ABGR, 1, 4, ARGB, 4)
1758TESTPLANARTOE(I420, 2, 2, BGRA, 1, 4, ARGB, 4)
1759TESTPLANARTOE(I420, 2, 2, ABGR, 1, 4, ARGB, 4)
1760TESTPLANARTOE(I420, 2, 2, RGBA, 1, 4, ARGB, 4)
1761TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, ARGB, 4)
1762TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, RGB24, 3)
1763TESTPLANARTOE(I420, 2, 2, RGB24, 1, 3, RAW, 3)
1764TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RAW, 3)
1765TESTPLANARTOE(I420, 2, 2, RAW, 1, 3, ARGB, 4)
1766TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, RGB565, 2)
1767TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB1555, 2)
1768TESTPLANARTOE(I420, 2, 2, ARGB, 1, 4, ARGB4444, 2)
1769TESTPLANARTOE(I422, 2, 1, ARGB, 1, 4, ARGB, 4)
1770TESTPLANARTOE(J422, 2, 1, ARGB, 1, 4, ARGB, 4)
1771TESTPLANARTOE(J422, 2, 1, ABGR, 1, 4, ARGB, 4)
1772TESTPLANARTOE(H422, 2, 1, ARGB, 1, 4, ARGB, 4)
1773TESTPLANARTOE(H422, 2, 1, ABGR, 1, 4, ARGB, 4)
1774TESTPLANARTOE(I422, 2, 1, BGRA, 1, 4, ARGB, 4)
1775TESTPLANARTOE(I422, 2, 1, ABGR, 1, 4, ARGB, 4)
1776TESTPLANARTOE(I422, 2, 1, RGBA, 1, 4, ARGB, 4)
1777TESTPLANARTOE(I411, 4, 1, ARGB, 1, 4, ARGB, 4)
1778TESTPLANARTOE(I444, 1, 1, ARGB, 1, 4, ARGB, 4)
1779TESTPLANARTOE(J444, 1, 1, ARGB, 1, 4, ARGB, 4)
1780TESTPLANARTOE(I444, 1, 1, ABGR, 1, 4, ARGB, 4)
1781TESTPLANARTOE(I420, 2, 2, YUY2, 2, 4, ARGB, 4)
1782TESTPLANARTOE(I420, 2, 2, UYVY, 2, 4, ARGB, 4)
1783TESTPLANARTOE(I422, 2, 1, YUY2, 2, 4, ARGB, 4)
1784TESTPLANARTOE(I422, 2, 1, UYVY, 2, 4, ARGB, 4)
1785
1786#define TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \
1787                       W1280, N, NEG, OFF, FMT_C, BPP_C, ATTEN)                \
1788TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) {                \
1789  const int kWidth = ((W1280) > 0) ? (W1280) : 1;                              \
1790  const int kHeight = benchmark_height_;                                       \
1791  const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B;                       \
1792  const int kSizeUV =                                                          \
1793    SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y);              \
1794  align_buffer_page_end(src_y, kWidth * kHeight + OFF);                        \
1795  align_buffer_page_end(src_u, kSizeUV + OFF);                                 \
1796  align_buffer_page_end(src_v, kSizeUV + OFF);                                 \
1797  align_buffer_page_end(src_a, kWidth * kHeight + OFF);                        \
1798  align_buffer_page_end(dst_argb_b, kStrideB * kHeight + OFF);                 \
1799  for (int i = 0; i < kWidth * kHeight; ++i) {                                 \
1800    src_y[i + OFF] = (fastrand() & 0xff);                                      \
1801    src_a[i + OFF] = (fastrand() & 0xff);                                      \
1802  }                                                                            \
1803  for (int i = 0; i < kSizeUV; ++i) {                                          \
1804    src_u[i + OFF] = (fastrand() & 0xff);                                      \
1805    src_v[i + OFF] = (fastrand() & 0xff);                                      \
1806  }                                                                            \
1807  memset(dst_argb_b + OFF, 1, kStrideB * kHeight);                             \
1808  for (int i = 0; i < benchmark_iterations_; ++i) {                            \
1809    FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth,                                 \
1810                          src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),           \
1811                          src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),           \
1812                          src_a + OFF, kWidth,                                 \
1813                          dst_argb_b + OFF, kStrideB,                          \
1814                          kWidth, NEG kHeight, ATTEN);                         \
1815  }                                                                            \
1816  int max_diff = 0;                                                            \
1817  /* Convert to a 3rd format in 1 step and 2 steps and compare  */             \
1818  const int kStrideC = kWidth * BPP_C;                                         \
1819  align_buffer_page_end(dst_argb_c, kStrideC * kHeight + OFF);                 \
1820  align_buffer_page_end(dst_argb_bc, kStrideC * kHeight + OFF);                \
1821  memset(dst_argb_c + OFF, 2, kStrideC * kHeight);                             \
1822  memset(dst_argb_bc + OFF, 3, kStrideC * kHeight);                            \
1823  FMT_PLANAR##To##FMT_C(src_y + OFF, kWidth,                                   \
1824                        src_u + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),             \
1825                        src_v + OFF, SUBSAMPLE(kWidth, SUBSAMP_X),             \
1826                        src_a + OFF, kWidth,                                   \
1827                        dst_argb_c + OFF, kStrideC,                            \
1828                        kWidth, NEG kHeight, ATTEN);                           \
1829  /* Convert B to C */                                                         \
1830  FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB,                                 \
1831                   dst_argb_bc + OFF, kStrideC,                                \
1832                   kWidth, kHeight);                                           \
1833  for (int i = 0; i < kStrideC * kHeight; ++i) {                               \
1834    EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_bc[i + OFF]);                      \
1835  }                                                                            \
1836  free_aligned_buffer_page_end(src_y);                                         \
1837  free_aligned_buffer_page_end(src_u);                                         \
1838  free_aligned_buffer_page_end(src_v);                                         \
1839  free_aligned_buffer_page_end(src_a);                                         \
1840  free_aligned_buffer_page_end(dst_argb_b);                                    \
1841  free_aligned_buffer_page_end(dst_argb_c);                                    \
1842  free_aligned_buffer_page_end(dst_argb_bc);                                   \
1843}
1844
1845#define TESTQPLANARTOE(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,  \
1846                      FMT_C, BPP_C)                                            \
1847    TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,     \
1848        benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C, 0)                     \
1849    TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,     \
1850        benchmark_width_, _Unaligned, +, 1, FMT_C, BPP_C, 0)                   \
1851    TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,     \
1852        benchmark_width_, _Invert, -, 0, FMT_C, BPP_C, 0)                      \
1853    TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,     \
1854        benchmark_width_, _Opt, +, 0, FMT_C, BPP_C, 0)                         \
1855      TESTQPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B,   \
1856          benchmark_width_, _Premult, +, 0, FMT_C, BPP_C, 1)
1857
1858TESTQPLANARTOE(I420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
1859TESTQPLANARTOE(I420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
1860
1861}  // namespace libyuv
1862