Reland ExternalTexture Gamma/Gamut Correction

Adds configurable gamma and gamut correction in Tint's external texture
transform. Adds constants in Dawn to perform correct conversion from
BT.709 to sRGB.

Bug: dawn:1082
Change-Id: I68b7ad7ccec29977c637a0a0d4f526cd47fe73d4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/88367
Commit-Queue: Brandon1 Jones <brandon1.jones@intel.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/tint/transform/multiplanar_external_texture.cc b/src/tint/transform/multiplanar_external_texture.cc
index a5a2134..34df013 100644
--- a/src/tint/transform/multiplanar_external_texture.cc
+++ b/src/tint/transform/multiplanar_external_texture.cc
@@ -51,6 +51,9 @@
   /// as input into the transform.
   const NewBindingPoints* new_binding_points;
 
+  /// Symbol for the GammaTransferParams
+  Symbol gamma_transfer_struct_sym;
+
   /// Symbol for the ExternalTextureParams struct
   Symbol params_struct_sym;
 
@@ -60,6 +63,9 @@
   /// Symbol for the textureSampleExternal function
   Symbol texture_sample_external_sym;
 
+  /// Symbol for the gammaCorrection function
+  Symbol gamma_correction_sym;
+
   /// Storage for new bindings that have been created corresponding to an
   /// original texture_external binding.
   std::unordered_map<const sem::Variable*, NewBindingSymbols>
@@ -96,7 +102,7 @@
       // If we find a texture_external binding, we know we must emit the
       // ExternalTextureParams struct.
       if (!params_struct_sym.IsValid()) {
-        createExtTexParamsStruct();
+        createExtTexParamsStructs();
       }
 
       // The binding points for the newly introduced bindings must have been
@@ -158,7 +164,7 @@
           // If we find a texture_external, we must ensure the
           // ExternalTextureParams struct exists.
           if (!params_struct_sym.IsValid()) {
-            createExtTexParamsStruct();
+            createExtTexParamsStructs();
           }
           // When a texture_external is found, we insert all components
           // the texture_external into the parameter list. We must also place
@@ -236,15 +242,68 @@
         });
   }
 
-  /// Creates the ExternalTextureParams struct.
-  void createExtTexParamsStruct() {
-    ast::StructMemberList member_list = {
+  /// Creates the parameter structs associated with the transform.
+  void createExtTexParamsStructs() {
+    // Create GammaTransferParams struct.
+    ast::StructMemberList gamma_transfer_member_list = {
+        b.Member("G", b.ty.f32()), b.Member("A", b.ty.f32()),
+        b.Member("B", b.ty.f32()), b.Member("C", b.ty.f32()),
+        b.Member("D", b.ty.f32()), b.Member("E", b.ty.f32()),
+        b.Member("F", b.ty.f32()), b.Member("padding", b.ty.u32())};
+
+    gamma_transfer_struct_sym = b.Symbols().New("GammaTransferParams");
+
+    b.Structure(gamma_transfer_struct_sym, gamma_transfer_member_list);
+
+    // Create ExternalTextureParams struct.
+    ast::StructMemberList ext_tex_params_member_list = {
         b.Member("numPlanes", b.ty.u32()),
-        b.Member("yuvToRgbConversionMatrix", b.ty.mat3x4(b.ty.f32()))};
+        b.Member("yuvToRgbConversionMatrix", b.ty.mat3x4(b.ty.f32())),
+        b.Member("gammaDecodeParams", b.ty.type_name("GammaTransferParams")),
+        b.Member("gammaEncodeParams", b.ty.type_name("GammaTransferParams")),
+        b.Member("gamutConversionMatrix", b.ty.mat3x3(b.ty.f32()))};
 
     params_struct_sym = b.Symbols().New("ExternalTextureParams");
 
-    b.Structure(params_struct_sym, member_list);
+    b.Structure(params_struct_sym, ext_tex_params_member_list);
+  }
+
+  /// Creates the gammaCorrection function if needed and returns a call
+  /// expression to it.
+  void createGammaCorrectionFn() {
+    using f32 = ProgramBuilder::f32;
+    ast::VariableList varList = {
+        b.Param("v", b.ty.vec3<f32>()),
+        b.Param("params", b.ty.type_name(gamma_transfer_struct_sym))};
+
+    ast::StatementList statementList = {
+        // let cond = abs(v) < vec3(params.D);
+        b.Decl(b.Let("cond", nullptr,
+                     b.LessThan(b.Call("abs", "v"),
+                                b.vec3<f32>(b.MemberAccessor("params", "D"))))),
+        // let t = sign(v) * ((params.C * abs(v)) + params.F);
+        b.Decl(b.Let("t", nullptr,
+                     b.Mul(b.Call("sign", "v"),
+                           b.Add(b.Mul(b.MemberAccessor("params", "C"),
+                                       b.Call("abs", "v")),
+                                 b.MemberAccessor("params", "F"))))),
+        // let f = (sign(v) * pow(((params.A * abs(v)) + params.B),
+        // vec3(params.G))) + params.E;
+        b.Decl(b.Let(
+            "f", nullptr,
+            b.Mul(b.Call("sign", "v"),
+                  b.Add(b.Call("pow",
+                               b.Add(b.Mul(b.MemberAccessor("params", "A"),
+                                           b.Call("abs", "v")),
+                                     b.MemberAccessor("params", "B")),
+                               b.vec3<f32>(b.MemberAccessor("params", "G"))),
+                        b.MemberAccessor("params", "E"))))),
+        // return select(f, t, cond);
+        b.Return(b.Call("select", "f", "t", "cond"))};
+
+    gamma_correction_sym = b.Symbols().New("gammaCorrection");
+
+    b.Func(gamma_correction_sym, varList, b.ty.vec3<f32>(), statementList, {});
   }
 
   /// Constructs a StatementList containing all the statements making up the
@@ -297,6 +356,18 @@
                                     b.MemberAccessor(plane_1_call, "rg"), 1.0f),
                                 b.MemberAccessor(
                                     "params", "yuvToRgbConversionMatrix"))))),
+        // color = gammaConversion(color, gammaDecodeParams);
+        b.Assign("color",
+                 b.Call("gammaCorrection", "color",
+                        b.MemberAccessor("params", "gammaDecodeParams"))),
+        // color = (params.gamutConversionMatrix * color);
+        b.Assign("color",
+                 b.Mul(b.MemberAccessor("params", "gamutConversionMatrix"),
+                       "color")),
+        // color = gammaConversion(color, gammaEncodeParams);
+        b.Assign("color",
+                 b.Call("gammaCorrection", "color",
+                        b.MemberAccessor("params", "gammaEncodeParams"))),
         // return vec4<f32>(color, 1.0f);
         b.Return(b.vec4<f32>("color", 1.0f))};
   }
@@ -318,6 +389,12 @@
           << expr->args.size() << " parameters";
     }
 
+    // TextureSampleExternal calls the gammaCorrection function, so ensure it
+    // exists.
+    if (!gamma_correction_sym.IsValid()) {
+      createGammaCorrectionFn();
+    }
+
     if (!texture_sample_external_sym.IsValid()) {
       texture_sample_external_sym = b.Symbols().New("textureSampleExternal");
 
@@ -362,6 +439,12 @@
           << expr->args.size() << " parameters";
     }
 
+    // TextureLoadExternal calls the gammaCorrection function, so ensure it
+    // exists.
+    if (!gamma_correction_sym.IsValid()) {
+      createGammaCorrectionFn();
+    }
+
     if (!texture_load_external_sym.IsValid()) {
       texture_load_external_sym = b.Symbols().New("textureLoadExternal");