123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie/*
223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie *  Copyright 2015 The LibYuv Project Authors. All rights reserved.
323d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie *
423d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie *  Use of this source code is governed by a BSD-style license
523d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie *  that can be found in the LICENSE file in the root of the source
623d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie *  tree. An additional intellectual property rights grant can be found
723d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie *  in the file PATENTS. All contributing project authors may
823d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie *  be found in the AUTHORS file in the root of the source tree.
923d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie */
1023d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie
1123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include <stdlib.h>
1223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie
1323d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "../unit_test/unit_test.h"
1423d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/basic_types.h"
1523d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert.h"
1623d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert_argb.h"
1723d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert_from.h"
1823d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert_from_argb.h"
1923d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/cpu_id.h"
2023d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie
2123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlienamespace libyuv {
2223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie
2323d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie// TODO(fbarchard): Port high accuracy YUV to RGB to Neon.
2423d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#if !defined(LIBYUV_DISABLE_NEON) && \
2523d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie    (defined(__aarch64__) || defined(__ARM_NEON__) || defined(LIBYUV_NEON))
2623d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_R 1
2723d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_G 1
2823d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_B 3
2923d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_FULL 6
3023d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_J420 5
3123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#else
3223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_R 1
331f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul#define ERROR_G 1
341f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul#define ERROR_B 3
351f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul#define ERROR_FULL 5
3671fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller#define ERROR_J420 3
3771fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller#endif
3871fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller
3971fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller#define TESTCS(TESTNAME, YUVTOARGB, ARGBTOYUV, HS1, HS, HN, DIFF)              \
4071fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller  TEST_F(LibYUVColorTest, TESTNAME) {                                          \
4171fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller    const int kPixels = benchmark_width_ * benchmark_height_;                  \
42c2711cdfb68d92ede740e2cc1fd7d78f604dc201Kristian Høgsberg    const int kHalfPixels =                                                    \
43c2711cdfb68d92ede740e2cc1fd7d78f604dc201Kristian Høgsberg        ((benchmark_width_ + 1) / 2) * ((benchmark_height_ + HS1) / HS);       \
4423ec7c457483aae1e0d399e9b570f1860c27c780Maciej Cencora    align_buffer_page_end(orig_y, kPixels);                                    \
4523ec7c457483aae1e0d399e9b570f1860c27c780Maciej Cencora    align_buffer_page_end(orig_u, kHalfPixels);                                \
46f9995b30756140724f41daf963fa06167912be7fKristian Høgsberg    align_buffer_page_end(orig_v, kHalfPixels);                                \
470bb29949ba8a9e5a15dc0640dbb0a4e7990a1d57Eric Anholt    align_buffer_page_end(orig_pixels, kPixels * 4);                           \
48e0ec3243e87cbdfb5db2657fe791748e145930e8Dave Airlie    align_buffer_page_end(temp_y, kPixels);                                    \
496f6bd8aedcf2b2f0e1ca9a1fa7ded1cb1f5a88edPauli Nieminen    align_buffer_page_end(temp_u, kHalfPixels);                                \
506f6bd8aedcf2b2f0e1ca9a1fa7ded1cb1f5a88edPauli Nieminen    align_buffer_page_end(temp_v, kHalfPixels);                                \
516f6bd8aedcf2b2f0e1ca9a1fa7ded1cb1f5a88edPauli Nieminen    align_buffer_page_end(dst_pixels_opt, kPixels * 4);                        \
521f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul    align_buffer_page_end(dst_pixels_c, kPixels * 4);                          \
53b2596c36c8f73e8bb7a0b1679b491662aeb2f9d9Dave Airlie                                                                               \
5471fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller    MemRandomize(orig_pixels, kPixels * 4);                                    \
55d47a6ada9ca9670c60fc141fabadf40c63031c08Brian Paul    MemRandomize(orig_y, kPixels);                                             \
561f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul    MemRandomize(orig_u, kHalfPixels);                                         \
571f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul    MemRandomize(orig_v, kHalfPixels);                                         \
581f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul    MemRandomize(temp_y, kPixels);                                             \
591f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul    MemRandomize(temp_u, kHalfPixels);                                         \
6071fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller    MemRandomize(temp_v, kHalfPixels);                                         \
611f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul    MemRandomize(dst_pixels_opt, kPixels * 4);                                 \
621f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul    MemRandomize(dst_pixels_c, kPixels * 4);                                   \
631f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul                                                                               \
6461bb82636f7b1681b5509e1a9038bbcc1feea35cDave Airlie    /* The test is overall for color conversion matrix being reversible, so */ \
65cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul    /* this initializes the pixel with 2x2 blocks to eliminate subsampling. */ \
66cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul    uint8* p = orig_y;                                                         \
67cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul    for (int y = 0; y < benchmark_height_ - HS1; y += HS) {                    \
68cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul      for (int x = 0; x < benchmark_width_ - 1; x += 2) {                      \
69cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul        uint8 r = static_cast<uint8>(fastrand());                              \
70cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul        p[0] = r;                                                              \
718a4d7393bd8a752eba2ee687c1c3e2df5c82745dMaciej Cencora        p[1] = r;                                                              \
7271fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller        p[HN] = r;                                                             \
73a17563c7ddfa58fe7f09d22a62a10f3488ef3147Maciej Cencora        p[HN + 1] = r;                                                         \
74d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff        p += 2;                                                                \
75d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff      }                                                                        \
76d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff      if (benchmark_width_ & 1) {                                              \
77d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff        uint8 r = static_cast<uint8>(fastrand());                              \
78d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff        p[0] = r;                                                              \
79ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt        p[HN] = r;                                                             \
80ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt        p += 1;                                                                \
81ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt      }                                                                        \
82ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt      p += HN;                                                                 \
83d29e96bf33e91d071770b86d87ffc4ef4dfc2f70Dave Airlie    }                                                                          \
84    if ((benchmark_height_ & 1) && HS == 2) {                                  \
85      for (int x = 0; x < benchmark_width_ - 1; x += 2) {                      \
86        uint8 r = static_cast<uint8>(fastrand());                              \
87        p[0] = r;                                                              \
88        p[1] = r;                                                              \
89        p += 2;                                                                \
90      }                                                                        \
91      if (benchmark_width_ & 1) {                                              \
92        uint8 r = static_cast<uint8>(fastrand());                              \
93        p[0] = r;                                                              \
94        p += 1;                                                                \
95      }                                                                        \
96    }                                                                          \
97    /* Start with YUV converted to ARGB. */                                    \
98    YUVTOARGB(orig_y, benchmark_width_, orig_u, (benchmark_width_ + 1) / 2,    \
99              orig_v, (benchmark_width_ + 1) / 2, orig_pixels,                 \
100              benchmark_width_ * 4, benchmark_width_, benchmark_height_);      \
101                                                                               \
102    ARGBTOYUV(orig_pixels, benchmark_width_ * 4, temp_y, benchmark_width_,     \
103              temp_u, (benchmark_width_ + 1) / 2, temp_v,                      \
104              (benchmark_width_ + 1) / 2, benchmark_width_,                    \
105              benchmark_height_);                                              \
106                                                                               \
107    MaskCpuFlags(disable_cpu_flags_);                                          \
108    YUVTOARGB(temp_y, benchmark_width_, temp_u, (benchmark_width_ + 1) / 2,    \
109              temp_v, (benchmark_width_ + 1) / 2, dst_pixels_c,                \
110              benchmark_width_ * 4, benchmark_width_, benchmark_height_);      \
111    MaskCpuFlags(benchmark_cpu_info_);                                         \
112                                                                               \
113    for (int i = 0; i < benchmark_iterations_; ++i) {                          \
114      YUVTOARGB(temp_y, benchmark_width_, temp_u, (benchmark_width_ + 1) / 2,  \
115                temp_v, (benchmark_width_ + 1) / 2, dst_pixels_opt,            \
116                benchmark_width_ * 4, benchmark_width_, benchmark_height_);    \
117    }                                                                          \
118    /* Test C and SIMD match. */                                               \
119    for (int i = 0; i < kPixels * 4; ++i) {                                    \
120      EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);                           \
121    }                                                                          \
122    /* Test SIMD is close to original. */                                      \
123    for (int i = 0; i < kPixels * 4; ++i) {                                    \
124      EXPECT_NEAR(static_cast<int>(orig_pixels[i]),                            \
125                  static_cast<int>(dst_pixels_opt[i]), DIFF);                  \
126    }                                                                          \
127                                                                               \
128    free_aligned_buffer_page_end(orig_pixels);                                 \
129    free_aligned_buffer_page_end(orig_y);                                      \
130    free_aligned_buffer_page_end(orig_u);                                      \
131    free_aligned_buffer_page_end(orig_v);                                      \
132    free_aligned_buffer_page_end(temp_y);                                      \
133    free_aligned_buffer_page_end(temp_u);                                      \
134    free_aligned_buffer_page_end(temp_v);                                      \
135    free_aligned_buffer_page_end(dst_pixels_opt);                              \
136    free_aligned_buffer_page_end(dst_pixels_c);                                \
137  }
138
139TESTCS(TestI420, I420ToARGB, ARGBToI420, 1, 2, benchmark_width_, ERROR_FULL)
140TESTCS(TestI422, I422ToARGB, ARGBToI422, 0, 1, 0, ERROR_FULL)
141TESTCS(TestJ420, J420ToARGB, ARGBToJ420, 1, 2, benchmark_width_, ERROR_J420)
142TESTCS(TestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, ERROR_J420)
143
144static void YUVToRGB(int y, int u, int v, int* r, int* g, int* b) {
145  const int kWidth = 16;
146  const int kHeight = 1;
147  const int kPixels = kWidth * kHeight;
148  const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2);
149
150  SIMD_ALIGNED(uint8 orig_y[16]);
151  SIMD_ALIGNED(uint8 orig_u[8]);
152  SIMD_ALIGNED(uint8 orig_v[8]);
153  SIMD_ALIGNED(uint8 orig_pixels[16 * 4]);
154  memset(orig_y, y, kPixels);
155  memset(orig_u, u, kHalfPixels);
156  memset(orig_v, v, kHalfPixels);
157
158  /* YUV converted to ARGB. */
159  I422ToARGB(orig_y, kWidth, orig_u, (kWidth + 1) / 2, orig_v, (kWidth + 1) / 2,
160             orig_pixels, kWidth * 4, kWidth, kHeight);
161
162  *b = orig_pixels[0];
163  *g = orig_pixels[1];
164  *r = orig_pixels[2];
165}
166
167static void YUVJToRGB(int y, int u, int v, int* r, int* g, int* b) {
168  const int kWidth = 16;
169  const int kHeight = 1;
170  const int kPixels = kWidth * kHeight;
171  const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2);
172
173  SIMD_ALIGNED(uint8 orig_y[16]);
174  SIMD_ALIGNED(uint8 orig_u[8]);
175  SIMD_ALIGNED(uint8 orig_v[8]);
176  SIMD_ALIGNED(uint8 orig_pixels[16 * 4]);
177  memset(orig_y, y, kPixels);
178  memset(orig_u, u, kHalfPixels);
179  memset(orig_v, v, kHalfPixels);
180
181  /* YUV converted to ARGB. */
182  J422ToARGB(orig_y, kWidth, orig_u, (kWidth + 1) / 2, orig_v, (kWidth + 1) / 2,
183             orig_pixels, kWidth * 4, kWidth, kHeight);
184
185  *b = orig_pixels[0];
186  *g = orig_pixels[1];
187  *r = orig_pixels[2];
188}
189
190static void YToRGB(int y, int* r, int* g, int* b) {
191  const int kWidth = 16;
192  const int kHeight = 1;
193  const int kPixels = kWidth * kHeight;
194
195  SIMD_ALIGNED(uint8 orig_y[16]);
196  SIMD_ALIGNED(uint8 orig_pixels[16 * 4]);
197  memset(orig_y, y, kPixels);
198
199  /* YUV converted to ARGB. */
200  I400ToARGB(orig_y, kWidth, orig_pixels, kWidth * 4, kWidth, kHeight);
201
202  *b = orig_pixels[0];
203  *g = orig_pixels[1];
204  *r = orig_pixels[2];
205}
206
207static void YJToRGB(int y, int* r, int* g, int* b) {
208  const int kWidth = 16;
209  const int kHeight = 1;
210  const int kPixels = kWidth * kHeight;
211
212  SIMD_ALIGNED(uint8 orig_y[16]);
213  SIMD_ALIGNED(uint8 orig_pixels[16 * 4]);
214  memset(orig_y, y, kPixels);
215
216  /* YUV converted to ARGB. */
217  J400ToARGB(orig_y, kWidth, orig_pixels, kWidth * 4, kWidth, kHeight);
218
219  *b = orig_pixels[0];
220  *g = orig_pixels[1];
221  *r = orig_pixels[2];
222}
223
224// Pick a method for clamping.
225//  #define CLAMPMETHOD_IF 1
226//  #define CLAMPMETHOD_TABLE 1
227#define CLAMPMETHOD_TERNARY 1
228//  #define CLAMPMETHOD_MASK 1
229
230// Pick a method for rounding.
231#define ROUND(f) static_cast<int>(f + 0.5f)
232//  #define ROUND(f) lrintf(f)
233//  #define ROUND(f) static_cast<int>(round(f))
234//  #define ROUND(f) _mm_cvt_ss2si(_mm_load_ss(&f))
235
236#if defined(CLAMPMETHOD_IF)
237static int RoundToByte(float f) {
238  int i = ROUND(f);
239  if (i < 0) {
240    i = 0;
241  }
242  if (i > 255) {
243    i = 255;
244  }
245  return i;
246}
247#elif defined(CLAMPMETHOD_TABLE)
248static const unsigned char clamptable[811] = {
249    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
250    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
251    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
252    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
253    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
254    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
255    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
256    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
257    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
258    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
259    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
260    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
261    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
262    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
263    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
264    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
265    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
266    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
267    0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   4,   5,   6,   7,   8,
268    9,   10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,
269    24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
270    39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,
271    54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,
272    69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
273    84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,
274    99,  100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
275    114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
276    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
277    144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158,
278    159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
279    174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
280    189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
281    204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218,
282    219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
283    234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
284    249, 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255,
285    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
286    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
287    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
288    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
289    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
290    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
291    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
292    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
293    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
294    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
295    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
296    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
297    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
298    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
299    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
300    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
301    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
302    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
303    255};
304
305static int RoundToByte(float f) {
306  return clamptable[ROUND(f) + 276];
307}
308#elif defined(CLAMPMETHOD_TERNARY)
309static int RoundToByte(float f) {
310  int i = ROUND(f);
311  return (i < 0) ? 0 : ((i > 255) ? 255 : i);
312}
313#elif defined(CLAMPMETHOD_MASK)
314static int RoundToByte(float f) {
315  int i = ROUND(f);
316  i = ((-(i) >> 31) & (i));                  // clamp to 0.
317  return (((255 - (i)) >> 31) | (i)) & 255;  // clamp to 255.
318}
319#endif
320
321#define RANDOM256(s) ((s & 1) ? ((s >> 1) ^ 0xb8) : (s >> 1))
322
323TEST_F(LibYUVColorTest, TestRoundToByte) {
324  int allb = 0;
325  int count = benchmark_width_ * benchmark_height_;
326  for (int i = 0; i < benchmark_iterations_; ++i) {
327    float f = (fastrand() & 255) * 3.14f - 260.f;
328    for (int j = 0; j < count; ++j) {
329      int b = RoundToByte(f);
330      f += 0.91f;
331      allb |= b;
332    }
333  }
334  EXPECT_GE(allb, 0);
335  EXPECT_LE(allb, 255);
336}
337
338static void YUVToRGBReference(int y, int u, int v, int* r, int* g, int* b) {
339  *r = RoundToByte((y - 16) * 1.164 - (v - 128) * -1.596);
340  *g = RoundToByte((y - 16) * 1.164 - (u - 128) * 0.391 - (v - 128) * 0.813);
341  *b = RoundToByte((y - 16) * 1.164 - (u - 128) * -2.018);
342}
343
344static void YUVJToRGBReference(int y, int u, int v, int* r, int* g, int* b) {
345  *r = RoundToByte(y - (v - 128) * -1.40200);
346  *g = RoundToByte(y - (u - 128) * 0.34414 - (v - 128) * 0.71414);
347  *b = RoundToByte(y - (u - 128) * -1.77200);
348}
349
350TEST_F(LibYUVColorTest, TestYUV) {
351  int r0, g0, b0, r1, g1, b1;
352
353  // cyan (less red)
354  YUVToRGBReference(240, 255, 0, &r0, &g0, &b0);
355  EXPECT_EQ(56, r0);
356  EXPECT_EQ(255, g0);
357  EXPECT_EQ(255, b0);
358
359  YUVToRGB(240, 255, 0, &r1, &g1, &b1);
360  EXPECT_EQ(57, r1);
361  EXPECT_EQ(255, g1);
362  EXPECT_EQ(255, b1);
363
364  // green (less red and blue)
365  YUVToRGBReference(240, 0, 0, &r0, &g0, &b0);
366  EXPECT_EQ(56, r0);
367  EXPECT_EQ(255, g0);
368  EXPECT_EQ(2, b0);
369
370  YUVToRGB(240, 0, 0, &r1, &g1, &b1);
371  EXPECT_EQ(57, r1);
372  EXPECT_EQ(255, g1);
373  EXPECT_EQ(5, b1);
374
375  for (int i = 0; i < 256; ++i) {
376    YUVToRGBReference(i, 128, 128, &r0, &g0, &b0);
377    YUVToRGB(i, 128, 128, &r1, &g1, &b1);
378    EXPECT_NEAR(r0, r1, ERROR_R);
379    EXPECT_NEAR(g0, g1, ERROR_G);
380    EXPECT_NEAR(b0, b1, ERROR_B);
381
382    YUVToRGBReference(i, 0, 0, &r0, &g0, &b0);
383    YUVToRGB(i, 0, 0, &r1, &g1, &b1);
384    EXPECT_NEAR(r0, r1, ERROR_R);
385    EXPECT_NEAR(g0, g1, ERROR_G);
386    EXPECT_NEAR(b0, b1, ERROR_B);
387
388    YUVToRGBReference(i, 0, 255, &r0, &g0, &b0);
389    YUVToRGB(i, 0, 255, &r1, &g1, &b1);
390    EXPECT_NEAR(r0, r1, ERROR_R);
391    EXPECT_NEAR(g0, g1, ERROR_G);
392    EXPECT_NEAR(b0, b1, ERROR_B);
393  }
394}
395
396TEST_F(LibYUVColorTest, TestGreyYUV) {
397  int r0, g0, b0, r1, g1, b1, r2, g2, b2;
398
399  // black
400  YUVToRGBReference(16, 128, 128, &r0, &g0, &b0);
401  EXPECT_EQ(0, r0);
402  EXPECT_EQ(0, g0);
403  EXPECT_EQ(0, b0);
404
405  YUVToRGB(16, 128, 128, &r1, &g1, &b1);
406  EXPECT_EQ(0, r1);
407  EXPECT_EQ(0, g1);
408  EXPECT_EQ(0, b1);
409
410  // white
411  YUVToRGBReference(240, 128, 128, &r0, &g0, &b0);
412  EXPECT_EQ(255, r0);
413  EXPECT_EQ(255, g0);
414  EXPECT_EQ(255, b0);
415
416  YUVToRGB(240, 128, 128, &r1, &g1, &b1);
417  EXPECT_EQ(255, r1);
418  EXPECT_EQ(255, g1);
419  EXPECT_EQ(255, b1);
420
421  // grey
422  YUVToRGBReference(128, 128, 128, &r0, &g0, &b0);
423  EXPECT_EQ(130, r0);
424  EXPECT_EQ(130, g0);
425  EXPECT_EQ(130, b0);
426
427  YUVToRGB(128, 128, 128, &r1, &g1, &b1);
428  EXPECT_EQ(130, r1);
429  EXPECT_EQ(130, g1);
430  EXPECT_EQ(130, b1);
431
432  for (int y = 0; y < 256; ++y) {
433    YUVToRGBReference(y, 128, 128, &r0, &g0, &b0);
434    YUVToRGB(y, 128, 128, &r1, &g1, &b1);
435    YToRGB(y, &r2, &g2, &b2);
436    EXPECT_EQ(r0, r1);
437    EXPECT_EQ(g0, g1);
438    EXPECT_EQ(b0, b1);
439    EXPECT_EQ(r0, r2);
440    EXPECT_EQ(g0, g2);
441    EXPECT_EQ(b0, b2);
442  }
443}
444
445static void PrintHistogram(int rh[256], int gh[256], int bh[256]) {
446  int i;
447  printf("hist");
448  for (i = 0; i < 256; ++i) {
449    if (rh[i] || gh[i] || bh[i]) {
450      printf("\t%8d", i - 128);
451    }
452  }
453  printf("\nred");
454  for (i = 0; i < 256; ++i) {
455    if (rh[i] || gh[i] || bh[i]) {
456      printf("\t%8d", rh[i]);
457    }
458  }
459  printf("\ngreen");
460  for (i = 0; i < 256; ++i) {
461    if (rh[i] || gh[i] || bh[i]) {
462      printf("\t%8d", gh[i]);
463    }
464  }
465  printf("\nblue");
466  for (i = 0; i < 256; ++i) {
467    if (rh[i] || gh[i] || bh[i]) {
468      printf("\t%8d", bh[i]);
469    }
470  }
471  printf("\n");
472}
473
474TEST_F(LibYUVColorTest, TestFullYUV) {
475  int rh[256] =
476      {
477          0,
478      },
479      gh[256] =
480          {
481              0,
482          },
483      bh[256] = {
484          0,
485      };
486  for (int u = 0; u < 256; ++u) {
487    for (int v = 0; v < 256; ++v) {
488      for (int y2 = 0; y2 < 256; ++y2) {
489        int r0, g0, b0, r1, g1, b1;
490        int y = RANDOM256(y2);
491        YUVToRGBReference(y, u, v, &r0, &g0, &b0);
492        YUVToRGB(y, u, v, &r1, &g1, &b1);
493        EXPECT_NEAR(r0, r1, ERROR_R);
494        EXPECT_NEAR(g0, g1, ERROR_G);
495        EXPECT_NEAR(b0, b1, ERROR_B);
496        ++rh[r1 - r0 + 128];
497        ++gh[g1 - g0 + 128];
498        ++bh[b1 - b0 + 128];
499      }
500    }
501  }
502  PrintHistogram(rh, gh, bh);
503}
504
505TEST_F(LibYUVColorTest, TestFullYUVJ) {
506  int rh[256] =
507      {
508          0,
509      },
510      gh[256] =
511          {
512              0,
513          },
514      bh[256] = {
515          0,
516      };
517  for (int u = 0; u < 256; ++u) {
518    for (int v = 0; v < 256; ++v) {
519      for (int y2 = 0; y2 < 256; ++y2) {
520        int r0, g0, b0, r1, g1, b1;
521        int y = RANDOM256(y2);
522        YUVJToRGBReference(y, u, v, &r0, &g0, &b0);
523        YUVJToRGB(y, u, v, &r1, &g1, &b1);
524        EXPECT_NEAR(r0, r1, 1);
525        EXPECT_NEAR(g0, g1, 1);
526        EXPECT_NEAR(b0, b1, 1);
527        ++rh[r1 - r0 + 128];
528        ++gh[g1 - g0 + 128];
529        ++bh[b1 - b0 + 128];
530      }
531    }
532  }
533  PrintHistogram(rh, gh, bh);
534}
535
536TEST_F(LibYUVColorTest, TestGreyYUVJ) {
537  int r0, g0, b0, r1, g1, b1, r2, g2, b2;
538
539  // black
540  YUVJToRGBReference(0, 128, 128, &r0, &g0, &b0);
541  EXPECT_EQ(0, r0);
542  EXPECT_EQ(0, g0);
543  EXPECT_EQ(0, b0);
544
545  YUVJToRGB(0, 128, 128, &r1, &g1, &b1);
546  EXPECT_EQ(0, r1);
547  EXPECT_EQ(0, g1);
548  EXPECT_EQ(0, b1);
549
550  // white
551  YUVJToRGBReference(255, 128, 128, &r0, &g0, &b0);
552  EXPECT_EQ(255, r0);
553  EXPECT_EQ(255, g0);
554  EXPECT_EQ(255, b0);
555
556  YUVJToRGB(255, 128, 128, &r1, &g1, &b1);
557  EXPECT_EQ(255, r1);
558  EXPECT_EQ(255, g1);
559  EXPECT_EQ(255, b1);
560
561  // grey
562  YUVJToRGBReference(128, 128, 128, &r0, &g0, &b0);
563  EXPECT_EQ(128, r0);
564  EXPECT_EQ(128, g0);
565  EXPECT_EQ(128, b0);
566
567  YUVJToRGB(128, 128, 128, &r1, &g1, &b1);
568  EXPECT_EQ(128, r1);
569  EXPECT_EQ(128, g1);
570  EXPECT_EQ(128, b1);
571
572  for (int y = 0; y < 256; ++y) {
573    YUVJToRGBReference(y, 128, 128, &r0, &g0, &b0);
574    YUVJToRGB(y, 128, 128, &r1, &g1, &b1);
575    YJToRGB(y, &r2, &g2, &b2);
576    EXPECT_EQ(r0, r1);
577    EXPECT_EQ(g0, g1);
578    EXPECT_EQ(b0, b1);
579    EXPECT_EQ(r0, r2);
580    EXPECT_EQ(g0, g2);
581    EXPECT_EQ(b0, b2);
582  }
583}
584
585}  // namespace libyuv
586