Bug 1493898 - P4. Add BT2020 YUV->RGB conversion. r=jgilbert
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 11 Apr 2019 16:57:39 +0000
changeset 469126 629f949df541783fcf49f2dbbadf90324a143035
parent 469125 a6a750656333e6033ab14c8350705a5950607bca
child 469127 81d979cbbca20d0445cf8251b01b7f36c61f9392
push id35856
push usercsabou@mozilla.com
push dateFri, 12 Apr 2019 03:19:48 +0000
treeherdermozilla-central@940684cd1065 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1493898
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1493898 - P4. Add BT2020 YUV->RGB conversion. r=jgilbert This is used by the basic compositor. Re-using existing logic, however as with other conversion it only handles limited 8 bits ranges (16-235) and to make things worse is rounded aggressively as the focus is on speed. Differential Revision: https://phabricator.services.mozilla.com/D25345
gfx/ycbcr/scale_yuv_argb.cpp
gfx/ycbcr/yuv_convert.cpp
media/libyuv/libyuv/include/libyuv/convert_argb.h
media/libyuv/libyuv/include/libyuv/row.h
media/libyuv/libyuv/source/convert_argb.cc
media/libyuv/libyuv/source/row_common.cc
--- a/gfx/ycbcr/scale_yuv_argb.cpp
+++ b/gfx/ycbcr/scale_yuv_argb.cpp
@@ -49,17 +49,17 @@ extern "C" {
 //
 // -[1] Allocate YUV conversion buffer and use it as source buffer of scaling.
 //      Its usage is borrowed from the libyuv's ScaleYUVToARGBBilinearUp().
 // -[2] Conversion from YUV to RGB was abstracted as YUVBuferIter.
 //      It is for handling multiple yuv color formats.
 // -[3] Modified scaling functions as to handle YUV conversion buffer and
 //      use YUVBuferIter.
 // -[4] Color conversion function selections in YUVBuferIter were borrowed from
-//      I444ToARGBMatrix(), I422ToARGBMatrix() and I420ToARGBMatrix() 
+//      I444ToARGBMatrix(), I422ToARGBMatrix() and I420ToARGBMatrix()
 
 static __inline int Abs(int v) {
   return v >= 0 ? v : -v;
 }
 
 struct YUVBuferIter {
   int src_width;
   int src_height;
@@ -205,20 +205,25 @@ static __inline void YUVBuferIter_Conver
 }
 
 void YUVBuferIter_Init(YUVBuferIter& iter, uint32 src_fourcc, mozilla::YUVColorSpace yuv_color_space) {
   iter.src_fourcc = src_fourcc;
   iter.y_index = 0;
   iter.src_row_y = iter.src_y;
   iter.src_row_u = iter.src_u;
   iter.src_row_v = iter.src_v;
-  if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
-    iter.yuvconstants = &kYuvH709Constants;
-  } else {
-    iter.yuvconstants = &kYuvI601Constants;
+  switch (yuv_color_space) {
+    case mozilla::YUVColorSpace::BT2020:
+      iter.yuvconstants = &kYuv2020Constants;
+      break;
+    case mozilla::YUVColorSpace::BT709:
+      iter.yuvconstants = &kYuvH709Constants;
+      break;
+    default:
+      iter.yuvconstants = &kYuvI601Constants;
   }
 
   if (src_fourcc == FOURCC_I444) {
     YUVBuferIter_InitI444(iter);
     iter.MoveTo = YUVBuferIter_MoveToForI444;
     iter.MoveToNextRow = YUVBuferIter_MoveToNextRowForI444;
   } else if(src_fourcc == FOURCC_I422){
     YUVBuferIter_InitI422(iter);
@@ -526,17 +531,17 @@ static void ScaleYUVToARGBBilinearDown(i
   }
   clip_src_width = (int)(xr - xl) * 4;  // Width aligned to 4.
   const ptrdiff_t xl_offset = xl * 4;
   x -= (int)(xl << 16);
 
   // Allocate 2 row of ARGB for source conversion.
   const int kRowSize = (src_width * 4 + 15) & ~15;
   align_buffer_64(argb_cnv_row, kRowSize * 2);
-  uint8* argb_cnv_rowptr = argb_cnv_row; 
+  uint8* argb_cnv_rowptr = argb_cnv_row;
   int argb_cnv_rowstride = kRowSize;
 
 #if defined(HAS_INTERPOLATEROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     InterpolateRow = InterpolateRow_Any_SSSE3;
     if (IS_ALIGNED(clip_src_width, 16)) {
       InterpolateRow = InterpolateRow_SSSE3;
     }
--- a/gfx/ycbcr/yuv_convert.cpp
+++ b/gfx/ycbcr/yuv_convert.cpp
@@ -59,111 +59,109 @@ libyuv::FourCC FourCCFromYUVType(YUVType
   } else if (aYUVType == YV12) {
     return libyuv::FOURCC_I420;
   } else {
     return libyuv::FOURCC_ANY;
   }
 }
 
 // Convert a frame of YUV to 32 bit ARGB.
-void ConvertYCbCrToRGB32(const uint8* y_buf,
-                         const uint8* u_buf,
-                         const uint8* v_buf,
-                         uint8* rgb_buf,
-                         int pic_x,
-                         int pic_y,
-                         int pic_width,
-                         int pic_height,
-                         int y_pitch,
-                         int uv_pitch,
-                         int rgb_pitch,
-                         YUVType yuv_type,
+void ConvertYCbCrToRGB32(const uint8* y_buf, const uint8* u_buf,
+                         const uint8* v_buf, uint8* rgb_buf, int pic_x,
+                         int pic_y, int pic_width, int pic_height, int y_pitch,
+                         int uv_pitch, int rgb_pitch, YUVType yuv_type,
                          YUVColorSpace yuv_color_space) {
-
-
   // Deprecated function's conversion is accurate.
   // libyuv converion is a bit inaccurate to get performance. It dynamically
-  // calculates RGB from YUV to use simd. In it, signed byte is used for conversion's
-  // coefficient, but it requests 129. libyuv cut 129 to 127. And only 6 bits are
-  // used for a decimal part during the dynamic calculation.
+  // calculates RGB from YUV to use simd. In it, signed byte is used for
+  // conversion's coefficient, but it requests 129. libyuv cut 129 to 127. And
+  // only 6 bits are used for a decimal part during the dynamic calculation.
   //
   // The function is still fast on some old intel chips.
   // See Bug 1256475.
   bool use_deprecated = gfxPrefs::YCbCrAccurateConversion() ||
                         (supports_mmx() && supports_sse() && !supports_sse3() &&
                          yuv_color_space == YUVColorSpace::BT601);
   // The deprecated function only support BT601.
   // See Bug 1210357.
   if (yuv_color_space != YUVColorSpace::BT601) {
     use_deprecated = false;
   }
   if (use_deprecated) {
-    ConvertYCbCrToRGB32_deprecated(y_buf, u_buf, v_buf, rgb_buf,
-                                   pic_x, pic_y, pic_width, pic_height,
-                                   y_pitch, uv_pitch, rgb_pitch, yuv_type);
+    ConvertYCbCrToRGB32_deprecated(y_buf, u_buf, v_buf, rgb_buf, pic_x, pic_y,
+                                   pic_width, pic_height, y_pitch, uv_pitch,
+                                   rgb_pitch, yuv_type);
     return;
   }
 
-  if (yuv_type == YV24) {
-    const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
-    const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x;
-    const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x;
-    if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
-      DebugOnly<int> err = libyuv::H444ToARGB(src_y, y_pitch,
-                                              src_u, uv_pitch,
-                                              src_v, uv_pitch,
-                                              rgb_buf, rgb_pitch,
-                                              pic_width, pic_height);
+  decltype(libyuv::U444ToARGB)* fConvertYUVToARGB = nullptr;
+  switch (yuv_type) {
+    case YV24: {
+      const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
+      const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x;
+      const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x;
+      switch (yuv_color_space) {
+        case mozilla::YUVColorSpace::BT2020:
+          fConvertYUVToARGB = libyuv::U444ToARGB;
+          break;
+        case mozilla::YUVColorSpace::BT709:
+          fConvertYUVToARGB = libyuv::H444ToARGB;
+          break;
+        default:
+          fConvertYUVToARGB = libyuv::I444ToARGB;
+          break;
+      }
+      DebugOnly<int> err =
+          fConvertYUVToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch,
+                            rgb_buf, rgb_pitch, pic_width, pic_height);
       MOZ_ASSERT(!err);
-    } else {
-      DebugOnly<int> err = libyuv::I444ToARGB(src_y, y_pitch,
-                                              src_u, uv_pitch,
-                                              src_v, uv_pitch,
-                                              rgb_buf, rgb_pitch,
-                                              pic_width, pic_height);
-      MOZ_ASSERT(!err);
+      break;
     }
-  } else if (yuv_type == YV16) {
-    const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
-    const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x / 2;
-    const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x / 2;
-    if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
-      DebugOnly<int> err = libyuv::H422ToARGB(src_y, y_pitch,
-                                              src_u, uv_pitch,
-                                              src_v, uv_pitch,
-                                              rgb_buf, rgb_pitch,
-                                              pic_width, pic_height);
+    case YV16: {
+      const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
+      const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x / 2;
+      const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x / 2;
+      switch (yuv_color_space) {
+        case mozilla::YUVColorSpace::BT2020:
+          fConvertYUVToARGB = libyuv::U422ToARGB;
+          break;
+        case mozilla::YUVColorSpace::BT709:
+          fConvertYUVToARGB = libyuv::H422ToARGB;
+          break;
+        default:
+          fConvertYUVToARGB = libyuv::I422ToARGB;
+          break;
+      }
+      DebugOnly<int> err =
+          fConvertYUVToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch,
+                            rgb_buf, rgb_pitch, pic_width, pic_height);
       MOZ_ASSERT(!err);
-    } else {
-      DebugOnly<int> err = libyuv::I422ToARGB(src_y, y_pitch,
-                                              src_u, uv_pitch,
-                                              src_v, uv_pitch,
-                                              rgb_buf, rgb_pitch,
-                                              pic_width, pic_height);
-      MOZ_ASSERT(!err);
+      break;
     }
-  } else {
-    MOZ_ASSERT(yuv_type == YV12);
-    const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
-    const uint8* src_u = u_buf + (uv_pitch * pic_y + pic_x) / 2;
-    const uint8* src_v = v_buf + (uv_pitch * pic_y + pic_x) / 2;
-    if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
-      DebugOnly<int> err = libyuv::H420ToARGB(src_y, y_pitch,
-                                              src_u, uv_pitch,
-                                              src_v, uv_pitch,
-                                              rgb_buf, rgb_pitch,
-                                              pic_width, pic_height);
+    default: {
+      MOZ_ASSERT(yuv_type == YV12);
+      const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
+      const uint8* src_u = u_buf + (uv_pitch * pic_y + pic_x) / 2;
+      const uint8* src_v = v_buf + (uv_pitch * pic_y + pic_x) / 2;
+      switch (yuv_color_space) {
+        case mozilla::YUVColorSpace::BT2020:
+          fConvertYUVToARGB = libyuv::U420ToARGB;
+          break;
+        case mozilla::YUVColorSpace::BT709:
+          fConvertYUVToARGB = libyuv::H420ToARGB;
+          break;
+        default:
+          fConvertYUVToARGB = libyuv::I420ToARGB;
+          break;
+      }
+      DebugOnly<int> err =
+          fConvertYUVToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch,
+                            rgb_buf, rgb_pitch, pic_width, pic_height);
       MOZ_ASSERT(!err);
-    } else {
-      DebugOnly<int> err = libyuv::I420ToARGB(src_y, y_pitch,
-                                              src_u, uv_pitch,
-                                              src_v, uv_pitch,
-                                              rgb_buf, rgb_pitch,
-                                              pic_width, pic_height);
-      MOZ_ASSERT(!err);
+      break;
     }
   }
 }
 
 // Convert a frame of YUV to 32 bit ARGB.
 void ConvertYCbCrToRGB32_deprecated(const uint8* y_buf,
                                     const uint8* u_buf,
                                     const uint8* v_buf,
--- a/media/libyuv/libyuv/include/libyuv/convert_argb.h
+++ b/media/libyuv/libyuv/include/libyuv/convert_argb.h
@@ -161,16 +161,28 @@ int H444ToARGB(const uint8_t* src_y,
                int src_stride_u,
                const uint8_t* src_v,
                int src_stride_v,
                uint8_t* dst_argb,
                int dst_stride_argb,
                int width,
                int height);
 
+LIBYUV_API
+int U444ToARGB(const uint8_t* src_y,
+               int src_stride_y,
+               const uint8_t* src_u,
+               int src_stride_u,
+               const uint8_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_argb,
+               int dst_stride_argb,
+               int width,
+               int height);
+
 // Convert J444 to ARGB.
 LIBYUV_API
 int J444ToARGB(const uint8_t* src_y,
                int src_stride_y,
                const uint8_t* src_u,
                int src_stride_u,
                const uint8_t* src_v,
                int src_stride_v,
@@ -397,29 +409,55 @@ int H420ToARGB(const uint8_t* src_y,
                int src_stride_u,
                const uint8_t* src_v,
                int src_stride_v,
                uint8_t* dst_argb,
                int dst_stride_argb,
                int width,
                int height);
 
+// Convert U420 to ARGB.
+LIBYUV_API
+int U420ToARGB(const uint8_t* src_y,
+               int src_stride_y,
+               const uint8_t* src_u,
+               int src_stride_u,
+               const uint8_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_argb,
+               int dst_stride_argb,
+               int width,
+               int height);
+
 // Convert H422 to ARGB.
 LIBYUV_API
 int H422ToARGB(const uint8_t* src_y,
                int src_stride_y,
                const uint8_t* src_u,
                int src_stride_u,
                const uint8_t* src_v,
                int src_stride_v,
                uint8_t* dst_argb,
                int dst_stride_argb,
                int width,
                int height);
 
+// Convert U422 to ARGB.
+LIBYUV_API
+int U422ToARGB(const uint8_t* src_y,
+               int src_stride_y,
+               const uint8_t* src_u,
+               int src_stride_u,
+               const uint8_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_argb,
+               int dst_stride_argb,
+               int width,
+               int height);
+
 // Convert H420 to ABGR.
 LIBYUV_API
 int H420ToABGR(const uint8_t* src_y,
                int src_stride_y,
                const uint8_t* src_u,
                int src_stride_u,
                const uint8_t* src_v,
                int src_stride_v,
--- a/media/libyuv/libyuv/include/libyuv/row.h
+++ b/media/libyuv/libyuv/include/libyuv/row.h
@@ -553,21 +553,23 @@ struct YuvConstants {
 #define KUVBIASR 160
 #define KYTORGB 192
 #endif
 
 // Conversion matrix for YUV to RGB
 extern const struct YuvConstants SIMD_ALIGNED(kYuvI601Constants);  // BT.601
 extern const struct YuvConstants SIMD_ALIGNED(kYuvJPEGConstants);  // JPeg
 extern const struct YuvConstants SIMD_ALIGNED(kYuvH709Constants);  // BT.709
+extern const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants);  // BT.2020
 
 // Conversion matrix for YVU to BGR
 extern const struct YuvConstants SIMD_ALIGNED(kYvuI601Constants);  // BT.601
 extern const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants);  // JPeg
 extern const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants);  // BT.709
+extern const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants);  // BT.2020
 
 #define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a)-1)))
 
 #define align_buffer_64(var, size)                                           \
   uint8_t* var##_mem = (uint8_t*)(malloc((size) + 63));         /* NOLINT */ \
   uint8_t* var = (uint8_t*)(((intptr_t)(var##_mem) + 63) & ~63) /* NOLINT */
 
 #define free_aligned_buffer_64(var) \
--- a/media/libyuv/libyuv/source/convert_argb.cc
+++ b/media/libyuv/libyuv/source/convert_argb.cc
@@ -221,16 +221,33 @@ int H420ToABGR(const uint8_t* src_y,
                int height) {
   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
                           src_stride_v,  // Swap U and V
                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
                           &kYvuH709Constants,  // Use Yvu matrix
                           width, height);
 }
 
+// Convert U420 to ARGB.
+LIBYUV_API
+int U420ToARGB(const uint8_t* src_y,
+               int src_stride_y,
+               const uint8_t* src_u,
+               int src_stride_u,
+               const uint8_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_argb,
+               int dst_stride_argb,
+               int width,
+               int height) {
+  return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
+                          src_stride_v, dst_argb, dst_stride_argb,
+                          &kYuv2020Constants, width, height);
+}
+
 // Convert I422 to ARGB with matrix
 static int I422ToARGBMatrix(const uint8_t* src_y,
                             int src_stride_y,
                             const uint8_t* src_u,
                             int src_stride_u,
                             const uint8_t* src_v,
                             int src_stride_v,
                             uint8_t* dst_argb,
@@ -655,16 +672,33 @@ int H010ToABGR(const uint16_t* src_y,
                int height) {
   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
                           src_stride_v,  // Swap U and V
                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
                           &kYvuH709Constants,  // Use Yvu matrix
                           width, height);
 }
 
+// Convert U422 to ARGB.
+LIBYUV_API
+int U422ToARGB(const uint8* src_y,
+               int src_stride_y,
+               const uint8* src_u,
+               int src_stride_u,
+               const uint8* src_v,
+               int src_stride_v,
+               uint8* dst_argb,
+               int dst_stride_argb,
+               int width,
+               int height) {
+  return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
+                          src_stride_v, dst_argb, dst_stride_argb,
+                          &kYuv2020Constants, width, height);
+}
+
 // Convert I444 to ARGB with matrix
 static int I444ToARGBMatrix(const uint8_t* src_y,
                             int src_stride_y,
                             const uint8_t* src_u,
                             int src_stride_u,
                             const uint8_t* src_v,
                             int src_stride_v,
                             uint8_t* dst_argb,
@@ -765,16 +799,33 @@ int H444ToARGB(const uint8_t* src_y,
                int dst_stride_argb,
                int width,
                int height) {
   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
                           src_stride_v, dst_argb, dst_stride_argb,
                           &kYuvH709Constants, width, height);
 }
 
+// Convert U444 to ARGB.
+LIBYUV_API
+int U444ToARGB(const uint8* src_y,
+               int src_stride_y,
+               const uint8* src_u,
+               int src_stride_u,
+               const uint8* src_v,
+               int src_stride_v,
+               uint8* dst_argb,
+               int dst_stride_argb,
+               int width,
+               int height) {
+  return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
+                          src_stride_v, dst_argb, dst_stride_argb,
+                          &kYuv2020Constants, width, height);
+}
+
 // Convert I444 to ABGR.
 LIBYUV_API
 int I444ToABGR(const uint8_t* src_y,
                int src_stride_y,
                const uint8_t* src_u,
                int src_stride_u,
                const uint8_t* src_v,
                int src_stride_v,
--- a/media/libyuv/libyuv/source/row_common.cc
+++ b/media/libyuv/libyuv/source/row_common.cc
@@ -1301,16 +1301,96 @@ const struct YuvConstants SIMD_ALIGNED(k
 #undef BR
 #undef YGB
 #undef UB
 #undef UG
 #undef VG
 #undef VR
 #undef YG
 
+// BT.2020 YUV to RGB reference
+//  R = (Y - 16) * 1.164384                - V * -1.67867
+//  G = (Y - 16) * 1.164384 - U * 0.187326 - V * -0.65042
+//  B = (Y - 16) * 1.164384 - U * -2.14177
+
+// Y contribution to R,G,B.  Scale and bias.
+#define YG 19003  /* round(1.164384 * 64 * 256 * 256 / 257) */
+#define YGB -1160 /* 1.164384 * 64 * -16 + 64 / 2 */
+
+#define UB -128 /* max(-128, round(-2.142 * 64)) */
+#define UG 12   /* round(0.187326 * 64) */
+#define VG 42   /* round(0.65042 * 64) */
+#define VR -107 /* round(-1.67867 * 64) */
+
+// Bias values to round, and subtract 128 from U and V.
+#define BB (UB * 128 + YGB)
+#define BG (UG * 128 + VG * 128 + YGB)
+#define BR (VR * 128 + YGB)
+
+#if defined(__aarch64__)
+const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants) = {
+    {-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
+    {-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
+    {UG, VG, UG, VG, UG, VG, UG, VG},
+    {UG, VG, UG, VG, UG, VG, UG, VG},
+    {BB, BG, BR, 0, 0, 0, 0, 0},
+    {0x0101 * YG, 0, 0, 0}};
+const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants) = {
+    {-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
+    {-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
+    {VG, UG, VG, UG, VG, UG, VG, UG},
+    {VG, UG, VG, UG, VG, UG, VG, UG},
+    {BR, BG, BB, 0, 0, 0, 0, 0},
+    {0x0101 * YG, 0, 0, 0}};
+#elif defined(__arm__)
+const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants) = {
+    {-UB, -UB, -UB, -UB, -VR, -VR, -VR, -VR, 0, 0, 0, 0, 0, 0, 0, 0},
+    {UG, UG, UG, UG, VG, VG, VG, VG, 0, 0, 0, 0, 0, 0, 0, 0},
+    {BB, BG, BR, 0, 0, 0, 0, 0},
+    {0x0101 * YG, 0, 0, 0}};
+const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants) = {
+    {-VR, -VR, -VR, -VR, -UB, -UB, -UB, -UB, 0, 0, 0, 0, 0, 0, 0, 0},
+    {VG, VG, VG, VG, UG, UG, UG, UG, 0, 0, 0, 0, 0, 0, 0, 0},
+    {BR, BG, BB, 0, 0, 0, 0, 0},
+    {0x0101 * YG, 0, 0, 0}};
+#else
+const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants) = {
+    {UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0,
+     UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0},
+    {UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG,
+     UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG},
+    {0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR,
+     0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR},
+    {BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
+    {BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
+    {BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
+    {YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG}};
+const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants) = {
+    {VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0,
+     VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0},
+    {VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG,
+     VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG},
+    {0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB,
+     0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB},
+    {BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
+    {BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
+    {BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
+    {YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG}};
+#endif
+
+#undef BB
+#undef BG
+#undef BR
+#undef YGB
+#undef UB
+#undef UG
+#undef VG
+#undef VR
+#undef YG
+
 // C reference code that mimics the YUV assembly.
 // Reads 8 bit YUV and leaves result as 16 bit.
 
 static __inline void YuvPixel(uint8_t y,
                               uint8_t u,
                               uint8_t v,
                               uint8_t* b,
                               uint8_t* g,