Bug 1493898 - P1. Add preliminary BT2020 colorspace support. r=mattwoodrow
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 11 Apr 2019 12:40:40 +0000
changeset 527940 529a9a8efae1411d6e858da014db27a48f235b4b
parent 527939 6826a3ede4cab76cf3a9a9d2f94a0ac8252c6cf7
child 527941 a0f4ced9b57c01361ad69f3af5d1a1a1fd93cb40
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
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 - P1. Add preliminary BT2020 colorspace support. r=mattwoodrow Only active with webrender and AL. Differential Revision: https://phabricator.services.mozilla.com/D25342
gfx/layers/ImageTypes.h
gfx/thebes/gfxUtils.cpp
gfx/webrender_bindings/WebRenderTypes.h
gfx/wr/webrender/res/brush_yuv_image.glsl
gfx/wr/webrender_api/src/display_item.rs
--- a/gfx/layers/ImageTypes.h
+++ b/gfx/layers/ImageTypes.h
@@ -99,16 +99,17 @@ enum class StereoMode {
   BOTTOM_TOP,
   TOP_BOTTOM,
   MAX,
 };
 
 enum class YUVColorSpace {
   BT601,
   BT709,
+  BT2020,
   // This represents the unknown format.
   UNKNOWN,
 };
 
 namespace layers {
 
 typedef uint32_t ContainerFrameID;
 constexpr ContainerFrameID kContainerFrameID_Invalid = 0;
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1090,77 +1090,90 @@ static nsCString EncodeSourceSurfaceAsPN
 const float kBT601NarrowYCbCrToRGB_RowMajor[16] = {
     1.16438f,  0.00000f, 1.59603f, -0.87420f, 1.16438f, -0.39176f,
     -0.81297f, 0.53167f, 1.16438f, 2.01723f,  0.00000f, -1.08563f,
     0.00000f,  0.00000f, 0.00000f, 1.00000f};
 const float kBT709NarrowYCbCrToRGB_RowMajor[16] = {
     1.16438f,  0.00000f, 1.79274f, -0.97295f, 1.16438f, -0.21325f,
     -0.53291f, 0.30148f, 1.16438f, 2.11240f,  0.00000f, -1.13340f,
     0.00000f,  0.00000f, 0.00000f, 1.00000f};
+const float kBT2020NarrowYCbCrToRGB_RowMajor[16] = {
+    1.16438f,  0.00000f, 1.67867f, -0.91569f, 1.16438f, -0.18733f,
+    -0.65042f, 0.34746f, 1.16438f, 2.14177f,  0.00000f, -1.14815f,
+    0.00000f,  0.00000f, 0.00000f, 1.00000f};
 
 /* static */ const float* gfxUtils::YuvToRgbMatrix4x3RowMajor(
     YUVColorSpace aYUVColorSpace) {
 #define X(x) \
   { x[0], x[1], x[2], 0.0f, x[4], x[5], x[6], 0.0f, x[8], x[9], x[10], 0.0f }
 
   static const float rec601[12] = X(kBT601NarrowYCbCrToRGB_RowMajor);
   static const float rec709[12] = X(kBT709NarrowYCbCrToRGB_RowMajor);
+  static const float rec2020[12] = X(kBT2020NarrowYCbCrToRGB_RowMajor);
 
 #undef X
 
   switch (aYUVColorSpace) {
     case YUVColorSpace::BT601:
       return rec601;
     case YUVColorSpace::BT709:
       return rec709;
+    case YUVColorSpace::BT2020:
+      return rec2020;
     default:  // YUVColorSpace::UNKNOWN
       MOZ_ASSERT(false, "unknown aYUVColorSpace");
       return rec601;
   }
 }
 
 /* static */ const float* gfxUtils::YuvToRgbMatrix3x3ColumnMajor(
     YUVColorSpace aYUVColorSpace) {
 #define X(x) \
   { x[0], x[4], x[8], x[1], x[5], x[9], x[2], x[6], x[10] }
 
   static const float rec601[9] = X(kBT601NarrowYCbCrToRGB_RowMajor);
   static const float rec709[9] = X(kBT709NarrowYCbCrToRGB_RowMajor);
+  static const float rec2020[9] = X(kBT2020NarrowYCbCrToRGB_RowMajor);
 
 #undef X
 
   switch (aYUVColorSpace) {
     case YUVColorSpace::BT601:
       return rec601;
     case YUVColorSpace::BT709:
       return rec709;
+    case YUVColorSpace::BT2020:
+      return rec2020;
     default:  // YUVColorSpace::UNKNOWN
       MOZ_ASSERT(false, "unknown aYUVColorSpace");
       return rec601;
   }
 }
 
 /* static */ const float* gfxUtils::YuvToRgbMatrix4x4ColumnMajor(
     YUVColorSpace aYUVColorSpace) {
 #define X(x)                                                             \
   {                                                                      \
     x[0], x[4], x[8], x[12], x[1], x[5], x[9], x[13], x[2], x[6], x[10], \
         x[14], x[3], x[7], x[11], x[15]                                  \
   }
 
   static const float rec601[16] = X(kBT601NarrowYCbCrToRGB_RowMajor);
   static const float rec709[16] = X(kBT709NarrowYCbCrToRGB_RowMajor);
+  static const float rec2020[16] = X(kBT2020NarrowYCbCrToRGB_RowMajor);
 
 #undef X
 
   switch (aYUVColorSpace) {
     case YUVColorSpace::BT601:
       return rec601;
     case YUVColorSpace::BT709:
       return rec709;
+    case YUVColorSpace::BT2020:
+      return rec2020;
     default:  // YUVColorSpace::UNKNOWN
       MOZ_ASSERT(false, "unknown aYUVColorSpace");
       return rec601;
   }
 }
 
 /* static */
 void gfxUtils::WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile) {
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -873,16 +873,18 @@ enum class WebRenderError : int8_t {
 
 static inline wr::WrYuvColorSpace ToWrYuvColorSpace(
     YUVColorSpace aYUVColorSpace) {
   switch (aYUVColorSpace) {
     case YUVColorSpace::BT601:
       return wr::WrYuvColorSpace::Rec601;
     case YUVColorSpace::BT709:
       return wr::WrYuvColorSpace::Rec709;
+    case YUVColorSpace::BT2020:
+      return wr::WrYuvColorSpace::Rec2020;
     default:
       MOZ_ASSERT_UNREACHABLE("Tried to convert invalid YUVColorSpace.");
   }
   return wr::WrYuvColorSpace::Rec601;
 }
 
 static inline wr::WrColorDepth ToWrColorDepth(gfx::ColorDepth aColorDepth) {
   switch (aColorDepth) {
--- a/gfx/wr/webrender/res/brush_yuv_image.glsl
+++ b/gfx/wr/webrender/res/brush_yuv_image.glsl
@@ -8,16 +8,17 @@
 
 // TODO(gw): Consider whether we should even have separate shader compilations
 //           for the various YUV modes. To save on the number of shaders we
 //           need to compile, it might be worth just doing this as an
 //           uber-shader instead.
 
 #define YUV_COLOR_SPACE_REC601 0
 #define YUV_COLOR_SPACE_REC709 1
+#define YUV_COLOR_SPACE_REC2020 2
 
 #define YUV_FORMAT_NV12 0
 #define YUV_FORMAT_PLANAR 1
 #define YUV_FORMAT_INTERLEAVED 2
 
 #ifdef WR_FEATURE_ALPHA_PASS
 varying vec2 vLocalPos;
 #endif
@@ -54,29 +55,43 @@ flat varying int vFormat;
 // The matrix is stored in column-major.
 const mat3 YuvColorMatrixRec601 = mat3(
     1.16438,  1.16438, 1.16438,
     0.0,     -0.39176, 2.01723,
     1.59603, -0.81297, 0.0
 );
 
 // From Rec709:
-// [R]   [1.1643835616438356,  4.2781193979771426e-17, 1.7927410714285714]   [Y -  16]
+// [R]   [1.1643835616438356,  0.0,                    1.7927410714285714]   [Y -  16]
 // [G] = [1.1643835616438358, -0.21324861427372963,   -0.532909328559444 ] x [U - 128]
 // [B]   [1.1643835616438356,  2.1124017857142854,     0.0               ]   [V - 128]
 //
 // For the range [0,1] instead of [0,255]:
 //
 // The matrix is stored in column-major.
 const mat3 YuvColorMatrixRec709 = mat3(
     1.16438,  1.16438,  1.16438,
     0.0    , -0.21325,  2.11240,
     1.79274, -0.53291,  0.0
 );
 
+// From Re2020:
+// [R]   [1.16438356164384,  0.0,                    1.678674107142860 ]   [Y -  16]
+// [G] = [1.16438356164384, -0.187326104219343,     -0.650424318505057 ] x [U - 128]
+// [B]   [1.16438356164384,  2.14177232142857,       0.0               ]   [V - 128]
+//
+// For the range [0,1] instead of [0,255]:
+//
+// The matrix is stored in column-major.
+const mat3 YuvColorMatrixRec2020 = mat3(
+    1.16438356164384 ,  1.164383561643840,  1.16438356164384,
+    0.0              , -0.187326104219343,  2.14177232142857,
+    1.67867410714286 , -0.650424318505057,  0.0
+);
+
 void write_uv_rect(
     int resource_id,
     vec2 f,
     vec2 texture_size,
     out vec3 uv,
     out vec4 uv_bounds
 ) {
     ImageResource res = fetch_image_resource(resource_id);
@@ -119,18 +134,20 @@ void brush_vs(
 ) {
     vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
 
     YuvPrimitive prim = fetch_yuv_primitive(prim_address);
     vCoefficient = prim.coefficient;
 
     if (prim.color_space == YUV_COLOR_SPACE_REC601) {
       vYuvColorMatrix = YuvColorMatrixRec601;
+    } else if (prim.color_space == YUV_COLOR_SPACE_REC709) {
+      vYuvColorMatrix = YuvColorMatrixRec709;
     } else {
-      vYuvColorMatrix = YuvColorMatrixRec709;
+      vYuvColorMatrix = YuvColorMatrixRec2020;
     }
     vFormat = prim.yuv_format;
 
 #ifdef WR_FEATURE_ALPHA_PASS
     vLocalPos = vi.local_pos;
 #endif
 
     if (vFormat == YUV_FORMAT_PLANAR) {
--- a/gfx/wr/webrender_api/src/display_item.rs
+++ b/gfx/wr/webrender_api/src/display_item.rs
@@ -800,16 +800,17 @@ pub struct YuvImageDisplayItem {
     pub image_rendering: ImageRendering,
 }
 
 #[repr(u32)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
 pub enum YuvColorSpace {
     Rec601 = 0,
     Rec709 = 1,
+    Rec2020 = 2,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub enum YuvData {
     NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel)
     PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel)
     InterleavedYCbCr(ImageKey), // (YCbCr interleaved channel)
 }