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/dawn/native/ExternalTexture.cpp b/src/dawn/native/ExternalTexture.cpp
index 7b3ae85..f9e7044 100644
--- a/src/dawn/native/ExternalTexture.cpp
+++ b/src/dawn/native/ExternalTexture.cpp
@@ -150,16 +150,38 @@
         ExternalTextureParams params;
         params.numPlanes = descriptor->plane1 == nullptr ? 1 : 2;
 
+        // TODO(dawn:1082): Make this field configurable from outside of Dawn.
+        // Conversion matrix for BT.709 limited range. Columns 1, 2 and 3 are copied
+        // directly from the corresponding matrix in SkYUVMath.cpp. Column 4 is the range
+        // bias (for RGB) found in column 5 of the same SkYUVMath.cpp matrix.
+        params.yuvToRgbConversionMatrix = {1.164384f, 0.0f,       1.792741f,  -0.972945f,
+                                           1.164384f, -0.213249f, -0.532909f, 0.301483f,
+                                           1.164384f, 2.112402f,  0.0f,       -1.133402f};
+
+        // TODO(dawn:1082): Make this field configurable from outside of Dawn.
+        // Use an identity matrix when converting BT.709 to sRGB because they shared the
+        // same primaries.
+        params.gamutConversionMatrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+                                        0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
+
         switch (descriptor->colorSpace) {
-            case wgpu::PredefinedColorSpace::Srgb:
-                // Conversion matrix for BT.709 limited range. Columns 1, 2 and 3 are copied
-                // directly from the corresponding matrix in SkYUVMath.cpp. Column 4 is the range
-                // bias (for RGB) found in column 5 of the same SkYUVMath.cpp matrix.
-                params.yuvToRgbConversion = {1.164384f, 0.0f,       1.792741f,  -0.972945f,
-                                             1.164384f, -0.213249f, -0.532909f, 0.301483f,
-                                             1.164384f, 2.112402f,  0.0f,       -1.133402f};
-                break;
             case wgpu::PredefinedColorSpace::Undefined:
+                // Undefined color space should eventually produce an error. For now, these
+                // constants will effectively perform no gamma correction so tests can continue
+                // passing.
+                params.gammaDecodingParams = {1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0};
+                params.gammaEncodingParams = {1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0};
+                break;
+            case wgpu::PredefinedColorSpace::Srgb:
+                // TODO(dawn:1082): Make this field configurable from outside of Dawn.
+                // These are the inverted parameters as specified by Rec. ITU-R BT.1886 for BT.709
+                params.gammaDecodingParams = {2.2, 1.0 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081,
+                                              0.0, 0.0};
+
+                // Constants for sRGB transfer function pulled from
+                // https://en.wikipedia.org/wiki/SRGB
+                params.gammaEncodingParams = {
+                    1 / 2.4, 1.137119 /*1.055^2.4*/, 0.0, 12.92, 0.0031308, -0.055, 0.0};
                 break;
         }
 
diff --git a/src/dawn/native/ExternalTexture.h b/src/dawn/native/ExternalTexture.h
index e752ca5..86b6886 100644
--- a/src/dawn/native/ExternalTexture.h
+++ b/src/dawn/native/ExternalTexture.h
@@ -26,10 +26,24 @@
 
     class TextureViewBase;
 
+    struct GammaTransferParams {
+        float G = 0.0;
+        float A = 0.0;
+        float B = 0.0;
+        float C = 0.0;
+        float D = 0.0;
+        float E = 0.0;
+        float F = 0.0;
+        uint32_t padding = 0;
+    };
+
     struct ExternalTextureParams {
         uint32_t numPlanes;
         std::array<uint32_t, 3> padding;
-        std::array<float, 12> yuvToRgbConversion;
+        std::array<float, 12> yuvToRgbConversionMatrix;
+        GammaTransferParams gammaDecodingParams = {};
+        GammaTransferParams gammaEncodingParams = {};
+        std::array<float, 12> gamutConversionMatrix = {};
     };
 
     MaybeError ValidateExternalTextureDescriptor(const DeviceBase* device,
diff --git a/src/dawn/tests/end2end/ExternalTextureTests.cpp b/src/dawn/tests/end2end/ExternalTextureTests.cpp
index 80cf6ce..afe28f8 100644
--- a/src/dawn/tests/end2end/ExternalTextureTests.cpp
+++ b/src/dawn/tests/end2end/ExternalTextureTests.cpp
@@ -191,10 +191,15 @@
         RGBA8 rgba;
     };
 
-    std::array<ConversionExpectation, 4> expectations = {{{0.0, .5, .5, RGBA8::kBlack},
-                                                          {0.2126, 0.4172, 1.0, RGBA8::kRed},
-                                                          {0.7152, 0.1402, 0.0175, RGBA8::kGreen},
-                                                          {0.0722, 1.0, 0.4937, RGBA8::kBlue}}};
+    // Conversion expectations for BT.709 YUV source and sRGB destination.
+    std::array<ConversionExpectation, 7> expectations = {
+        {{0.0, .5, .5, RGBA8::kBlack},
+         {0.2126, 0.4172, 1.0, RGBA8::kRed},
+         {0.7152, 0.1402, 0.0175, RGBA8::kGreen},
+         {0.0722, 1.0, 0.4937, RGBA8::kBlue},
+         {0.6382, 0.3232, 0.6644, {246, 169, 90, 255}},
+         {0.5423, 0.5323, 0.4222, {120, 162, 169, 255}},
+         {0.2345, 0.4383, 0.6342, {126, 53, 33, 255}}}};
 
     for (ConversionExpectation expectation : expectations) {
         // Initialize the texture planes with YUV data
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");
 
diff --git a/src/tint/transform/multiplanar_external_texture_test.cc b/src/tint/transform/multiplanar_external_texture_test.cc
index df3b837..77448a7 100644
--- a/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/transform/multiplanar_external_texture_test.cc
@@ -106,9 +106,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -146,9 +160,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -185,9 +213,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -198,6 +240,13 @@
 
 @group(0) @binding(1) var ext_tex : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -205,6 +254,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -234,15 +286,36 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -250,6 +323,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -282,9 +358,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -293,6 +383,13 @@
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -300,6 +397,9 @@
   } else {
     color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -328,15 +428,36 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -344,6 +465,9 @@
   } else {
     color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -376,9 +500,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -389,6 +527,13 @@
 
 @group(0) @binding(1) var ext_tex : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -396,6 +541,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -406,6 +554,9 @@
   } else {
     color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -436,15 +587,36 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -452,6 +624,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -462,6 +637,9 @@
   } else {
     color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -498,9 +676,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(4) var ext_tex_plane_1 : texture_2d<f32>;
@@ -529,6 +721,13 @@
 
 @group(1) @binding(0) var ext_tex_3 : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -536,6 +735,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -575,15 +777,36 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -591,6 +814,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -635,9 +861,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -649,6 +889,13 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -656,6 +903,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -694,15 +944,36 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -710,6 +981,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -755,9 +1029,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -768,6 +1056,13 @@
 
 @group(0) @binding(6) var<uniform> ext_tex_params_1 : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -775,6 +1070,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -826,9 +1124,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -844,6 +1156,13 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp, ext_tex2, ext_tex_plane_1_1, ext_tex_params_1);
 }
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -851,6 +1170,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -897,15 +1219,36 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -913,6 +1256,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -965,15 +1311,36 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -981,6 +1348,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -1021,9 +1391,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 fn f(ext_tex : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams) -> vec2<i32> {
@@ -1057,9 +1441,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1068,6 +1466,13 @@
 
 type ET = texture_external;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -1075,6 +1480,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
@@ -1119,9 +1527,23 @@
 )";
 
   auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
   yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1133,6 +1555,13 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
   var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
@@ -1140,6 +1569,9 @@
   } else {
     color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return vec4<f32>(color, 1.0);
 }
 
diff --git a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl
index ee6f776..a1cf7d7 100644
--- a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl
@@ -1,13 +1,30 @@
 #version 310 es
 
+struct GammaTransferParams {
+  float G;
+  float A;
+  float B;
+  float C;
+  float D;
+  float E;
+  float F;
+  uint padding;
+};
+
 struct ExternalTextureParams {
   uint numPlanes;
   mat3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  mat3 gamutConversionMatrix;
 };
 
 layout(binding = 2) uniform ExternalTextureParams_1 {
   uint numPlanes;
   mat3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  mat3 gamutConversionMatrix;
 } ext_tex_params;
 
 uniform highp sampler2D arg_0_1;
@@ -31,14 +48,31 @@
 #version 310 es
 precision mediump float;
 
+struct GammaTransferParams {
+  float G;
+  float A;
+  float B;
+  float C;
+  float D;
+  float E;
+  float F;
+  uint padding;
+};
+
 struct ExternalTextureParams {
   uint numPlanes;
   mat3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  mat3 gamutConversionMatrix;
 };
 
 layout(binding = 2) uniform ExternalTextureParams_1 {
   uint numPlanes;
   mat3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  mat3 gamutConversionMatrix;
 } ext_tex_params;
 
 uniform highp sampler2D arg_0_1;
@@ -56,14 +90,31 @@
 }
 #version 310 es
 
+struct GammaTransferParams {
+  float G;
+  float A;
+  float B;
+  float C;
+  float D;
+  float E;
+  float F;
+  uint padding;
+};
+
 struct ExternalTextureParams {
   uint numPlanes;
   mat3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  mat3 gamutConversionMatrix;
 };
 
 layout(binding = 2) uniform ExternalTextureParams_1 {
   uint numPlanes;
   mat3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  mat3 gamutConversionMatrix;
 } ext_tex_params;
 
 uniform highp sampler2D arg_0_1;
diff --git a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.hlsl b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.hlsl
index 78d6e70..108fe85 100644
--- a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.hlsl
+++ b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.hlsl
@@ -1,6 +1,6 @@
 Texture2D<float4> ext_tex_plane_1 : register(t1, space1);
 cbuffer cbuffer_ext_tex_params : register(b2, space1) {
-  uint4 ext_tex_params[4];
+  uint4 ext_tex_params[11];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
 
diff --git a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.msl b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.msl
index 6a4127b..1d4eb71 100644
--- a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.msl
+++ b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.msl
@@ -1,9 +1,23 @@
 #include <metal_stdlib>
 
 using namespace metal;
+struct GammaTransferParams {
+  float G;
+  float A;
+  float B;
+  float C;
+  float D;
+  float E;
+  float F;
+  uint padding;
+};
+
 struct ExternalTextureParams {
   uint numPlanes;
   float3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  float3x3 gamutConversionMatrix;
 };
 
 void textureDimensions_ba1481(texture2d<float, access::sample> tint_symbol_1) {
diff --git a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.spvasm b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.spvasm
index 9ff8d5a..c0f550a 100644
--- a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 44
+; Bound: 47
 ; Schema: 0
                OpCapability Shader
                OpCapability ImageQuery
@@ -17,6 +17,18 @@
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
                OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
+               OpMemberName %ExternalTextureParams 2 "gammaDecodeParams"
+               OpName %GammaTransferParams "GammaTransferParams"
+               OpMemberName %GammaTransferParams 0 "G"
+               OpMemberName %GammaTransferParams 1 "A"
+               OpMemberName %GammaTransferParams 2 "B"
+               OpMemberName %GammaTransferParams 3 "C"
+               OpMemberName %GammaTransferParams 4 "D"
+               OpMemberName %GammaTransferParams 5 "E"
+               OpMemberName %GammaTransferParams 6 "F"
+               OpMemberName %GammaTransferParams 7 "padding"
+               OpMemberName %ExternalTextureParams 3 "gammaEncodeParams"
+               OpMemberName %ExternalTextureParams 4 "gamutConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
                OpName %textureDimensions_ba1481 "textureDimensions_ba1481"
@@ -34,6 +46,19 @@
                OpMemberDecorate %ExternalTextureParams 1 Offset 16
                OpMemberDecorate %ExternalTextureParams 1 ColMajor
                OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
+               OpMemberDecorate %ExternalTextureParams 2 Offset 64
+               OpMemberDecorate %GammaTransferParams 0 Offset 0
+               OpMemberDecorate %GammaTransferParams 1 Offset 4
+               OpMemberDecorate %GammaTransferParams 2 Offset 8
+               OpMemberDecorate %GammaTransferParams 3 Offset 12
+               OpMemberDecorate %GammaTransferParams 4 Offset 16
+               OpMemberDecorate %GammaTransferParams 5 Offset 20
+               OpMemberDecorate %GammaTransferParams 6 Offset 24
+               OpMemberDecorate %GammaTransferParams 7 Offset 28
+               OpMemberDecorate %ExternalTextureParams 3 Offset 96
+               OpMemberDecorate %ExternalTextureParams 4 Offset 128
+               OpMemberDecorate %ExternalTextureParams 4 ColMajor
+               OpMemberDecorate %ExternalTextureParams 4 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 2
@@ -52,46 +77,49 @@
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
 %mat3v4float = OpTypeMatrix %v4float 3
-%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
+%GammaTransferParams = OpTypeStruct %float %float %float %float %float %float %float %uint
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float %GammaTransferParams %GammaTransferParams %mat3v3float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %void = OpTypeVoid
-         %18 = OpTypeFunction %void
+         %21 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
       %int_0 = OpConstant %int 0
 %_ptr_Function_v2int = OpTypePointer Function %v2int
-         %29 = OpConstantNull %v2int
-         %30 = OpTypeFunction %v4float
+         %32 = OpConstantNull %v2int
+         %33 = OpTypeFunction %v4float
     %float_1 = OpConstant %float 1
-%textureDimensions_ba1481 = OpFunction %void None %18
-         %21 = OpLabel
-        %res = OpVariable %_ptr_Function_v2int Function %29
-         %25 = OpLoad %11 %arg_0
-         %22 = OpImageQuerySizeLod %v2int %25 %int_0
-               OpStore %res %22
+%textureDimensions_ba1481 = OpFunction %void None %21
+         %24 = OpLabel
+        %res = OpVariable %_ptr_Function_v2int Function %32
+         %28 = OpLoad %11 %arg_0
+         %25 = OpImageQuerySizeLod %v2int %28 %int_0
+               OpStore %res %25
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %30
-         %32 = OpLabel
-         %33 = OpFunctionCall %void %textureDimensions_ba1481
+%vertex_main_inner = OpFunction %v4float None %33
+         %35 = OpLabel
+         %36 = OpFunctionCall %void %textureDimensions_ba1481
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %18
-         %35 = OpLabel
-         %36 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %36
+%vertex_main = OpFunction %void None %21
+         %38 = OpLabel
+         %39 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %39
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %18
-         %39 = OpLabel
-         %40 = OpFunctionCall %void %textureDimensions_ba1481
-               OpReturn
-               OpFunctionEnd
-%compute_main = OpFunction %void None %18
+%fragment_main = OpFunction %void None %21
          %42 = OpLabel
          %43 = OpFunctionCall %void %textureDimensions_ba1481
                OpReturn
                OpFunctionEnd
+%compute_main = OpFunction %void None %21
+         %45 = OpLabel
+         %46 = OpFunctionCall %void %textureDimensions_ba1481
+               OpReturn
+               OpFunctionEnd
diff --git a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.hlsl b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.hlsl
index f1d67e8..d481026 100644
--- a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.hlsl
+++ b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.hlsl
@@ -1,14 +1,34 @@
+struct GammaTransferParams {
+  float G;
+  float A;
+  float B;
+  float C;
+  float D;
+  float E;
+  float F;
+  uint padding;
+};
 struct ExternalTextureParams {
   uint numPlanes;
   float3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  float3x3 gamutConversionMatrix;
 };
 
 Texture2D<float4> ext_tex_plane_1 : register(t1, space1);
 cbuffer cbuffer_ext_tex_params : register(b2, space1) {
-  uint4 ext_tex_params[4];
+  uint4 ext_tex_params[11];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
 
+float3 gammaCorrection(float3 v, GammaTransferParams params) {
+  const bool3 cond = (abs(v) < float3((params.D).xxx));
+  const float3 t = (sign(v) * ((params.C * abs(v)) + params.F));
+  const float3 f = (sign(v) * (pow(((params.A * abs(v)) + params.B), float3((params.G).xxx)) + params.E));
+  return (cond ? t : f);
+}
+
 float4 textureLoadExternal(Texture2D<float4> plane0, Texture2D<float4> plane1, int2 coord, ExternalTextureParams params) {
   float3 color = float3(0.0f, 0.0f, 0.0f);
   if ((params.numPlanes == 1u)) {
@@ -16,20 +36,43 @@
   } else {
     color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(coord, 0)).r, plane1.Load(int3(coord, 0)).rg, 1.0f));
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = mul(color, params.gamutConversionMatrix);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return float4(color, 1.0f);
 }
 
-float3x4 tint_symbol_3(uint4 buffer[4], uint offset) {
+float3x4 tint_symbol_3(uint4 buffer[11], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
   return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
 }
 
-ExternalTextureParams tint_symbol_1(uint4 buffer[4], uint offset) {
+GammaTransferParams tint_symbol_5(uint4 buffer[11], uint offset) {
   const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const ExternalTextureParams tint_symbol_5 = {buffer[scalar_offset_3 / 4][scalar_offset_3 % 4], tint_symbol_3(buffer, (offset + 16u))};
-  return tint_symbol_5;
+  const uint scalar_offset_4 = ((offset + 4u)) / 4;
+  const uint scalar_offset_5 = ((offset + 8u)) / 4;
+  const uint scalar_offset_6 = ((offset + 12u)) / 4;
+  const uint scalar_offset_7 = ((offset + 16u)) / 4;
+  const uint scalar_offset_8 = ((offset + 20u)) / 4;
+  const uint scalar_offset_9 = ((offset + 24u)) / 4;
+  const uint scalar_offset_10 = ((offset + 28u)) / 4;
+  const GammaTransferParams tint_symbol_9 = {asfloat(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), asfloat(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), asfloat(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4]), asfloat(buffer[scalar_offset_6 / 4][scalar_offset_6 % 4]), asfloat(buffer[scalar_offset_7 / 4][scalar_offset_7 % 4]), asfloat(buffer[scalar_offset_8 / 4][scalar_offset_8 % 4]), asfloat(buffer[scalar_offset_9 / 4][scalar_offset_9 % 4]), buffer[scalar_offset_10 / 4][scalar_offset_10 % 4]};
+  return tint_symbol_9;
+}
+
+float3x3 tint_symbol_7(uint4 buffer[11], uint offset) {
+  const uint scalar_offset_11 = ((offset + 0u)) / 4;
+  const uint scalar_offset_12 = ((offset + 16u)) / 4;
+  const uint scalar_offset_13 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_11 / 4].xyz), asfloat(buffer[scalar_offset_12 / 4].xyz), asfloat(buffer[scalar_offset_13 / 4].xyz));
+}
+
+ExternalTextureParams tint_symbol_1(uint4 buffer[11], uint offset) {
+  const uint scalar_offset_14 = ((offset + 0u)) / 4;
+  const ExternalTextureParams tint_symbol_10 = {buffer[scalar_offset_14 / 4][scalar_offset_14 % 4], tint_symbol_3(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 64u)), tint_symbol_5(buffer, (offset + 96u)), tint_symbol_7(buffer, (offset + 128u))};
+  return tint_symbol_10;
 }
 
 void textureLoad_8acf41() {
diff --git a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.msl b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.msl
index 2cf34bc..d7ae796 100644
--- a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.msl
+++ b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.msl
@@ -1,12 +1,33 @@
 #include <metal_stdlib>
 
 using namespace metal;
+struct GammaTransferParams {
+  /* 0x0000 */ float G;
+  /* 0x0004 */ float A;
+  /* 0x0008 */ float B;
+  /* 0x000c */ float C;
+  /* 0x0010 */ float D;
+  /* 0x0014 */ float E;
+  /* 0x0018 */ float F;
+  /* 0x001c */ uint padding;
+};
+
 struct ExternalTextureParams {
   /* 0x0000 */ uint numPlanes;
   /* 0x0004 */ int8_t tint_pad[12];
   /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
+  /* 0x0040 */ GammaTransferParams gammaDecodeParams;
+  /* 0x0060 */ GammaTransferParams gammaEncodeParams;
+  /* 0x0080 */ float3x3 gamutConversionMatrix;
 };
 
+float3 gammaCorrection(float3 v, GammaTransferParams params) {
+  bool3 const cond = (fabs(v) < float3(params.D));
+  float3 const t = (sign(v) * ((params.C * fabs(v)) + params.F));
+  float3 const f = (sign(v) * (pow(((params.A * fabs(v)) + params.B), float3(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 float4 textureLoadExternal(texture2d<float, access::sample> plane0, texture2d<float, access::sample> plane1, int2 coord, ExternalTextureParams params) {
   float3 color = 0.0f;
   if ((params.numPlanes == 1u)) {
@@ -14,6 +35,9 @@
   } else {
     color = (float4(plane0.read(uint2(coord), 0)[0], float4(plane1.read(uint2(coord), 0)).rg, 1.0f) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return float4(color, 1.0f);
 }
 
diff --git a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm
index 8e9330c..950b973 100644
--- a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm
@@ -1,9 +1,10 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 81
+; Bound: 129
 ; Schema: 0
                OpCapability Shader
+         %27 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint Vertex %vertex_main "vertex_main" %value %vertex_point_size
                OpEntryPoint Fragment %fragment_main "fragment_main"
@@ -16,13 +17,28 @@
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
                OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
+               OpMemberName %ExternalTextureParams 2 "gammaDecodeParams"
+               OpName %GammaTransferParams "GammaTransferParams"
+               OpMemberName %GammaTransferParams 0 "G"
+               OpMemberName %GammaTransferParams 1 "A"
+               OpMemberName %GammaTransferParams 2 "B"
+               OpMemberName %GammaTransferParams 3 "C"
+               OpMemberName %GammaTransferParams 4 "D"
+               OpMemberName %GammaTransferParams 5 "E"
+               OpMemberName %GammaTransferParams 6 "F"
+               OpMemberName %GammaTransferParams 7 "padding"
+               OpMemberName %ExternalTextureParams 3 "gammaEncodeParams"
+               OpMemberName %ExternalTextureParams 4 "gamutConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
+               OpName %gammaCorrection "gammaCorrection"
+               OpName %v "v"
+               OpName %params "params"
                OpName %textureLoadExternal "textureLoadExternal"
                OpName %plane0 "plane0"
                OpName %plane1 "plane1"
                OpName %coord "coord"
-               OpName %params "params"
+               OpName %params_0 "params"
                OpName %color "color"
                OpName %textureLoad_8acf41 "textureLoad_8acf41"
                OpName %res "res"
@@ -39,6 +55,19 @@
                OpMemberDecorate %ExternalTextureParams 1 Offset 16
                OpMemberDecorate %ExternalTextureParams 1 ColMajor
                OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
+               OpMemberDecorate %ExternalTextureParams 2 Offset 64
+               OpMemberDecorate %GammaTransferParams 0 Offset 0
+               OpMemberDecorate %GammaTransferParams 1 Offset 4
+               OpMemberDecorate %GammaTransferParams 2 Offset 8
+               OpMemberDecorate %GammaTransferParams 3 Offset 12
+               OpMemberDecorate %GammaTransferParams 4 Offset 16
+               OpMemberDecorate %GammaTransferParams 5 Offset 20
+               OpMemberDecorate %GammaTransferParams 6 Offset 24
+               OpMemberDecorate %GammaTransferParams 7 Offset 28
+               OpMemberDecorate %ExternalTextureParams 3 Offset 96
+               OpMemberDecorate %ExternalTextureParams 4 Offset 128
+               OpMemberDecorate %ExternalTextureParams 4 ColMajor
+               OpMemberDecorate %ExternalTextureParams 4 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 2
@@ -57,91 +86,143 @@
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
 %mat3v4float = OpTypeMatrix %v4float 3
-%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
+%GammaTransferParams = OpTypeStruct %float %float %float %float %float %float %float %uint
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float %GammaTransferParams %GammaTransferParams %mat3v3float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
+         %21 = OpTypeFunction %v3float %v3float %GammaTransferParams
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %41 = OpConstantNull %v3float
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
-         %18 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
-    %v3float = OpTypeVector %float 3
-%_ptr_Function_v3float = OpTypePointer Function %v3float
-         %30 = OpConstantNull %v3float
+         %61 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
      %uint_1 = OpConstant %uint 1
-       %bool = OpTypeBool
       %int_0 = OpConstant %int 0
     %v2float = OpTypeVector %float 2
     %float_1 = OpConstant %float 1
        %void = OpTypeVoid
-         %57 = OpTypeFunction %void
-         %64 = OpConstantNull %v2int
+        %105 = OpTypeFunction %void
+        %112 = OpConstantNull %v2int
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %68 = OpTypeFunction %v4float
-%textureLoadExternal = OpFunction %v4float None %18
+        %116 = OpTypeFunction %v4float
+%gammaCorrection = OpFunction %v3float None %21
+          %v = OpFunctionParameter %v3float
+     %params = OpFunctionParameter %GammaTransferParams
+         %25 = OpLabel
+         %39 = OpVariable %_ptr_Function_v3float Function %41
+         %51 = OpVariable %_ptr_Function_v3float Function %41
+         %57 = OpVariable %_ptr_Function_v3float Function %41
+         %26 = OpExtInst %v3float %27 FAbs %v
+         %28 = OpCompositeExtract %float %params 4
+         %29 = OpCompositeConstruct %v3float %28 %28 %28
+         %30 = OpFOrdLessThan %v3bool %26 %29
+         %33 = OpExtInst %v3float %27 FSign %v
+         %34 = OpCompositeExtract %float %params 3
+         %35 = OpExtInst %v3float %27 FAbs %v
+         %36 = OpVectorTimesScalar %v3float %35 %34
+         %37 = OpCompositeExtract %float %params 6
+         %42 = OpCompositeConstruct %v3float %37 %37 %37
+         %38 = OpFAdd %v3float %36 %42
+         %43 = OpFMul %v3float %33 %38
+         %44 = OpExtInst %v3float %27 FSign %v
+         %46 = OpCompositeExtract %float %params 1
+         %47 = OpExtInst %v3float %27 FAbs %v
+         %48 = OpVectorTimesScalar %v3float %47 %46
+         %49 = OpCompositeExtract %float %params 2
+         %52 = OpCompositeConstruct %v3float %49 %49 %49
+         %50 = OpFAdd %v3float %48 %52
+         %53 = OpCompositeExtract %float %params 0
+         %54 = OpCompositeConstruct %v3float %53 %53 %53
+         %45 = OpExtInst %v3float %27 Pow %50 %54
+         %55 = OpCompositeExtract %float %params 5
+         %58 = OpCompositeConstruct %v3float %55 %55 %55
+         %56 = OpFAdd %v3float %45 %58
+         %59 = OpFMul %v3float %44 %56
+         %60 = OpSelect %v3float %30 %43 %59
+               OpReturnValue %60
+               OpFunctionEnd
+%textureLoadExternal = OpFunction %v4float None %61
      %plane0 = OpFunctionParameter %11
      %plane1 = OpFunctionParameter %11
       %coord = OpFunctionParameter %v2int
-     %params = OpFunctionParameter %ExternalTextureParams
-         %26 = OpLabel
-      %color = OpVariable %_ptr_Function_v3float Function %30
-         %31 = OpCompositeExtract %uint %params 0
-         %33 = OpIEqual %bool %31 %uint_1
-               OpSelectionMerge %35 None
-               OpBranchConditional %33 %36 %37
-         %36 = OpLabel
-         %38 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-         %40 = OpVectorShuffle %v3float %38 %38 0 1 2
-               OpStore %color %40
-               OpBranch %35
-         %37 = OpLabel
-         %41 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-         %42 = OpCompositeExtract %float %41 0
-         %43 = OpImageFetch %v4float %plane1 %coord Lod %int_0
-         %45 = OpVectorShuffle %v2float %43 %43 0 1
-         %46 = OpCompositeExtract %float %45 0
-         %47 = OpCompositeExtract %float %45 1
-         %49 = OpCompositeConstruct %v4float %42 %46 %47 %float_1
-         %50 = OpCompositeExtract %mat3v4float %params 1
-         %51 = OpVectorTimesMatrix %v3float %49 %50
-               OpStore %color %51
-               OpBranch %35
-         %35 = OpLabel
-         %52 = OpLoad %v3float %color
-         %53 = OpCompositeExtract %float %52 0
-         %54 = OpCompositeExtract %float %52 1
-         %55 = OpCompositeExtract %float %52 2
-         %56 = OpCompositeConstruct %v4float %53 %54 %55 %float_1
-               OpReturnValue %56
+   %params_0 = OpFunctionParameter %ExternalTextureParams
+         %69 = OpLabel
+      %color = OpVariable %_ptr_Function_v3float Function %41
+         %71 = OpCompositeExtract %uint %params_0 0
+         %73 = OpIEqual %bool %71 %uint_1
+               OpSelectionMerge %74 None
+               OpBranchConditional %73 %75 %76
+         %75 = OpLabel
+         %77 = OpImageFetch %v4float %plane0 %coord Lod %int_0
+         %79 = OpVectorShuffle %v3float %77 %77 0 1 2
+               OpStore %color %79
+               OpBranch %74
+         %76 = OpLabel
+         %80 = OpImageFetch %v4float %plane0 %coord Lod %int_0
+         %81 = OpCompositeExtract %float %80 0
+         %82 = OpImageFetch %v4float %plane1 %coord Lod %int_0
+         %84 = OpVectorShuffle %v2float %82 %82 0 1
+         %85 = OpCompositeExtract %float %84 0
+         %86 = OpCompositeExtract %float %84 1
+         %88 = OpCompositeConstruct %v4float %81 %85 %86 %float_1
+         %89 = OpCompositeExtract %mat3v4float %params_0 1
+         %90 = OpVectorTimesMatrix %v3float %88 %89
+               OpStore %color %90
+               OpBranch %74
+         %74 = OpLabel
+         %92 = OpLoad %v3float %color
+         %93 = OpCompositeExtract %GammaTransferParams %params_0 2
+         %91 = OpFunctionCall %v3float %gammaCorrection %92 %93
+               OpStore %color %91
+         %94 = OpCompositeExtract %mat3v3float %params_0 4
+         %95 = OpLoad %v3float %color
+         %96 = OpMatrixTimesVector %v3float %94 %95
+               OpStore %color %96
+         %98 = OpLoad %v3float %color
+         %99 = OpCompositeExtract %GammaTransferParams %params_0 3
+         %97 = OpFunctionCall %v3float %gammaCorrection %98 %99
+               OpStore %color %97
+        %100 = OpLoad %v3float %color
+        %101 = OpCompositeExtract %float %100 0
+        %102 = OpCompositeExtract %float %100 1
+        %103 = OpCompositeExtract %float %100 2
+        %104 = OpCompositeConstruct %v4float %101 %102 %103 %float_1
+               OpReturnValue %104
                OpFunctionEnd
-%textureLoad_8acf41 = OpFunction %void None %57
-         %60 = OpLabel
+%textureLoad_8acf41 = OpFunction %void None %105
+        %108 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function %5
-         %62 = OpLoad %11 %arg_0
-         %63 = OpLoad %11 %ext_tex_plane_1
-         %65 = OpLoad %ExternalTextureParams %ext_tex_params
-         %61 = OpFunctionCall %v4float %textureLoadExternal %62 %63 %64 %65
-               OpStore %res %61
+        %110 = OpLoad %11 %arg_0
+        %111 = OpLoad %11 %ext_tex_plane_1
+        %113 = OpLoad %ExternalTextureParams %ext_tex_params
+        %109 = OpFunctionCall %v4float %textureLoadExternal %110 %111 %112 %113
+               OpStore %res %109
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %68
-         %70 = OpLabel
-         %71 = OpFunctionCall %void %textureLoad_8acf41
+%vertex_main_inner = OpFunction %v4float None %116
+        %118 = OpLabel
+        %119 = OpFunctionCall %void %textureLoad_8acf41
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %57
-         %73 = OpLabel
-         %74 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %74
+%vertex_main = OpFunction %void None %105
+        %121 = OpLabel
+        %122 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %122
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %57
-         %76 = OpLabel
-         %77 = OpFunctionCall %void %textureLoad_8acf41
+%fragment_main = OpFunction %void None %105
+        %124 = OpLabel
+        %125 = OpFunctionCall %void %textureLoad_8acf41
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %57
-         %79 = OpLabel
-         %80 = OpFunctionCall %void %textureLoad_8acf41
+%compute_main = OpFunction %void None %105
+        %127 = OpLabel
+        %128 = OpFunctionCall %void %textureLoad_8acf41
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.hlsl b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.hlsl
index dce01cb..d673a4f 100644
--- a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.hlsl
+++ b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.hlsl
@@ -1,15 +1,35 @@
+struct GammaTransferParams {
+  float G;
+  float A;
+  float B;
+  float C;
+  float D;
+  float E;
+  float F;
+  uint padding;
+};
 struct ExternalTextureParams {
   uint numPlanes;
   float3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  float3x3 gamutConversionMatrix;
 };
 
 Texture2D<float4> ext_tex_plane_1 : register(t2, space1);
 cbuffer cbuffer_ext_tex_params : register(b3, space1) {
-  uint4 ext_tex_params[4];
+  uint4 ext_tex_params[11];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
 SamplerState arg_1 : register(s1, space1);
 
+float3 gammaCorrection(float3 v, GammaTransferParams params) {
+  const bool3 cond = (abs(v) < float3((params.D).xxx));
+  const float3 t = (sign(v) * ((params.C * abs(v)) + params.F));
+  const float3 f = (sign(v) * (pow(((params.A * abs(v)) + params.B), float3((params.G).xxx)) + params.E));
+  return (cond ? t : f);
+}
+
 float4 textureSampleExternal(Texture2D<float4> plane0, Texture2D<float4> plane1, SamplerState smp, float2 coord, ExternalTextureParams params) {
   float3 color = float3(0.0f, 0.0f, 0.0f);
   if ((params.numPlanes == 1u)) {
@@ -17,20 +37,43 @@
   } else {
     color = mul(params.yuvToRgbConversionMatrix, float4(plane0.SampleLevel(smp, coord, 0.0f).r, plane1.SampleLevel(smp, coord, 0.0f).rg, 1.0f));
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = mul(color, params.gamutConversionMatrix);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return float4(color, 1.0f);
 }
 
-float3x4 tint_symbol_3(uint4 buffer[4], uint offset) {
+float3x4 tint_symbol_3(uint4 buffer[11], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
   return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
 }
 
-ExternalTextureParams tint_symbol_1(uint4 buffer[4], uint offset) {
+GammaTransferParams tint_symbol_5(uint4 buffer[11], uint offset) {
   const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const ExternalTextureParams tint_symbol_5 = {buffer[scalar_offset_3 / 4][scalar_offset_3 % 4], tint_symbol_3(buffer, (offset + 16u))};
-  return tint_symbol_5;
+  const uint scalar_offset_4 = ((offset + 4u)) / 4;
+  const uint scalar_offset_5 = ((offset + 8u)) / 4;
+  const uint scalar_offset_6 = ((offset + 12u)) / 4;
+  const uint scalar_offset_7 = ((offset + 16u)) / 4;
+  const uint scalar_offset_8 = ((offset + 20u)) / 4;
+  const uint scalar_offset_9 = ((offset + 24u)) / 4;
+  const uint scalar_offset_10 = ((offset + 28u)) / 4;
+  const GammaTransferParams tint_symbol_9 = {asfloat(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), asfloat(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), asfloat(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4]), asfloat(buffer[scalar_offset_6 / 4][scalar_offset_6 % 4]), asfloat(buffer[scalar_offset_7 / 4][scalar_offset_7 % 4]), asfloat(buffer[scalar_offset_8 / 4][scalar_offset_8 % 4]), asfloat(buffer[scalar_offset_9 / 4][scalar_offset_9 % 4]), buffer[scalar_offset_10 / 4][scalar_offset_10 % 4]};
+  return tint_symbol_9;
+}
+
+float3x3 tint_symbol_7(uint4 buffer[11], uint offset) {
+  const uint scalar_offset_11 = ((offset + 0u)) / 4;
+  const uint scalar_offset_12 = ((offset + 16u)) / 4;
+  const uint scalar_offset_13 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_11 / 4].xyz), asfloat(buffer[scalar_offset_12 / 4].xyz), asfloat(buffer[scalar_offset_13 / 4].xyz));
+}
+
+ExternalTextureParams tint_symbol_1(uint4 buffer[11], uint offset) {
+  const uint scalar_offset_14 = ((offset + 0u)) / 4;
+  const ExternalTextureParams tint_symbol_10 = {buffer[scalar_offset_14 / 4][scalar_offset_14 % 4], tint_symbol_3(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 64u)), tint_symbol_5(buffer, (offset + 96u)), tint_symbol_7(buffer, (offset + 128u))};
+  return tint_symbol_10;
 }
 
 void textureSampleLevel_979816() {
diff --git a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.msl b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.msl
index 2a297df..abe1ccc 100644
--- a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.msl
+++ b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.msl
@@ -1,12 +1,33 @@
 #include <metal_stdlib>
 
 using namespace metal;
+struct GammaTransferParams {
+  /* 0x0000 */ float G;
+  /* 0x0004 */ float A;
+  /* 0x0008 */ float B;
+  /* 0x000c */ float C;
+  /* 0x0010 */ float D;
+  /* 0x0014 */ float E;
+  /* 0x0018 */ float F;
+  /* 0x001c */ uint padding;
+};
+
 struct ExternalTextureParams {
   /* 0x0000 */ uint numPlanes;
   /* 0x0004 */ int8_t tint_pad[12];
   /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
+  /* 0x0040 */ GammaTransferParams gammaDecodeParams;
+  /* 0x0060 */ GammaTransferParams gammaEncodeParams;
+  /* 0x0080 */ float3x3 gamutConversionMatrix;
 };
 
+float3 gammaCorrection(float3 v, GammaTransferParams params) {
+  bool3 const cond = (fabs(v) < float3(params.D));
+  float3 const t = (sign(v) * ((params.C * fabs(v)) + params.F));
+  float3 const f = (sign(v) * (pow(((params.A * fabs(v)) + params.B), float3(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 float4 textureSampleExternal(texture2d<float, access::sample> plane0, texture2d<float, access::sample> plane1, sampler smp, float2 coord, ExternalTextureParams params) {
   float3 color = 0.0f;
   if ((params.numPlanes == 1u)) {
@@ -14,6 +35,9 @@
   } else {
     color = (float4(plane0.sample(smp, coord, level(0.0f))[0], float4(plane1.sample(smp, coord, level(0.0f))).rg, 1.0f) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return float4(color, 1.0f);
 }
 
diff --git a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm
index ae6490c..ebf6441 100644
--- a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm
@@ -1,9 +1,10 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 88
+; Bound: 136
 ; Schema: 0
                OpCapability Shader
+         %30 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint Vertex %vertex_main "vertex_main" %value %vertex_point_size
                OpEntryPoint Fragment %fragment_main "fragment_main"
@@ -16,15 +17,30 @@
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
                OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
+               OpMemberName %ExternalTextureParams 2 "gammaDecodeParams"
+               OpName %GammaTransferParams "GammaTransferParams"
+               OpMemberName %GammaTransferParams 0 "G"
+               OpMemberName %GammaTransferParams 1 "A"
+               OpMemberName %GammaTransferParams 2 "B"
+               OpMemberName %GammaTransferParams 3 "C"
+               OpMemberName %GammaTransferParams 4 "D"
+               OpMemberName %GammaTransferParams 5 "E"
+               OpMemberName %GammaTransferParams 6 "F"
+               OpMemberName %GammaTransferParams 7 "padding"
+               OpMemberName %ExternalTextureParams 3 "gammaEncodeParams"
+               OpMemberName %ExternalTextureParams 4 "gamutConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
+               OpName %gammaCorrection "gammaCorrection"
+               OpName %v "v"
+               OpName %params "params"
                OpName %textureSampleExternal "textureSampleExternal"
                OpName %plane0 "plane0"
                OpName %plane1 "plane1"
                OpName %smp "smp"
                OpName %coord "coord"
-               OpName %params "params"
+               OpName %params_0 "params"
                OpName %color "color"
                OpName %textureSampleLevel_979816 "textureSampleLevel_979816"
                OpName %res "res"
@@ -41,6 +57,19 @@
                OpMemberDecorate %ExternalTextureParams 1 Offset 16
                OpMemberDecorate %ExternalTextureParams 1 ColMajor
                OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
+               OpMemberDecorate %ExternalTextureParams 2 Offset 64
+               OpMemberDecorate %GammaTransferParams 0 Offset 0
+               OpMemberDecorate %GammaTransferParams 1 Offset 4
+               OpMemberDecorate %GammaTransferParams 2 Offset 8
+               OpMemberDecorate %GammaTransferParams 3 Offset 12
+               OpMemberDecorate %GammaTransferParams 4 Offset 16
+               OpMemberDecorate %GammaTransferParams 5 Offset 20
+               OpMemberDecorate %GammaTransferParams 6 Offset 24
+               OpMemberDecorate %GammaTransferParams 7 Offset 28
+               OpMemberDecorate %ExternalTextureParams 3 Offset 96
+               OpMemberDecorate %ExternalTextureParams 4 Offset 128
+               OpMemberDecorate %ExternalTextureParams 4 ColMajor
+               OpMemberDecorate %ExternalTextureParams 4 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 3
@@ -61,98 +90,150 @@
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
 %mat3v4float = OpTypeMatrix %v4float 3
-%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
+%GammaTransferParams = OpTypeStruct %float %float %float %float %float %float %float %uint
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float %GammaTransferParams %GammaTransferParams %mat3v3float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
-         %20 = OpTypeSampler
-%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
-      %arg_1 = OpVariable %_ptr_UniformConstant_20 UniformConstant
-    %v2float = OpTypeVector %float 2
-         %21 = OpTypeFunction %v4float %11 %11 %20 %v2float %ExternalTextureParams
-    %v3float = OpTypeVector %float 3
-%_ptr_Function_v3float = OpTypePointer Function %v3float
-         %33 = OpConstantNull %v3float
-     %uint_1 = OpConstant %uint 1
+         %23 = OpTypeSampler
+%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
+      %arg_1 = OpVariable %_ptr_UniformConstant_23 UniformConstant
+         %24 = OpTypeFunction %v3float %v3float %GammaTransferParams
        %bool = OpTypeBool
-         %42 = OpTypeSampledImage %11
+     %v3bool = OpTypeVector %bool 3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %44 = OpConstantNull %v3float
+    %v2float = OpTypeVector %float 2
+         %64 = OpTypeFunction %v4float %11 %11 %23 %v2float %ExternalTextureParams
+     %uint_1 = OpConstant %uint 1
+         %81 = OpTypeSampledImage %11
     %float_0 = OpConstant %float 0
     %float_1 = OpConstant %float 1
        %void = OpTypeVoid
-         %63 = OpTypeFunction %void
-         %71 = OpConstantNull %v2float
+        %111 = OpTypeFunction %void
+        %119 = OpConstantNull %v2float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %75 = OpTypeFunction %v4float
-%textureSampleExternal = OpFunction %v4float None %21
+        %123 = OpTypeFunction %v4float
+%gammaCorrection = OpFunction %v3float None %24
+          %v = OpFunctionParameter %v3float
+     %params = OpFunctionParameter %GammaTransferParams
+         %28 = OpLabel
+         %42 = OpVariable %_ptr_Function_v3float Function %44
+         %54 = OpVariable %_ptr_Function_v3float Function %44
+         %60 = OpVariable %_ptr_Function_v3float Function %44
+         %29 = OpExtInst %v3float %30 FAbs %v
+         %31 = OpCompositeExtract %float %params 4
+         %32 = OpCompositeConstruct %v3float %31 %31 %31
+         %33 = OpFOrdLessThan %v3bool %29 %32
+         %36 = OpExtInst %v3float %30 FSign %v
+         %37 = OpCompositeExtract %float %params 3
+         %38 = OpExtInst %v3float %30 FAbs %v
+         %39 = OpVectorTimesScalar %v3float %38 %37
+         %40 = OpCompositeExtract %float %params 6
+         %45 = OpCompositeConstruct %v3float %40 %40 %40
+         %41 = OpFAdd %v3float %39 %45
+         %46 = OpFMul %v3float %36 %41
+         %47 = OpExtInst %v3float %30 FSign %v
+         %49 = OpCompositeExtract %float %params 1
+         %50 = OpExtInst %v3float %30 FAbs %v
+         %51 = OpVectorTimesScalar %v3float %50 %49
+         %52 = OpCompositeExtract %float %params 2
+         %55 = OpCompositeConstruct %v3float %52 %52 %52
+         %53 = OpFAdd %v3float %51 %55
+         %56 = OpCompositeExtract %float %params 0
+         %57 = OpCompositeConstruct %v3float %56 %56 %56
+         %48 = OpExtInst %v3float %30 Pow %53 %57
+         %58 = OpCompositeExtract %float %params 5
+         %61 = OpCompositeConstruct %v3float %58 %58 %58
+         %59 = OpFAdd %v3float %48 %61
+         %62 = OpFMul %v3float %47 %59
+         %63 = OpSelect %v3float %33 %46 %62
+               OpReturnValue %63
+               OpFunctionEnd
+%textureSampleExternal = OpFunction %v4float None %64
      %plane0 = OpFunctionParameter %11
      %plane1 = OpFunctionParameter %11
-        %smp = OpFunctionParameter %20
+        %smp = OpFunctionParameter %23
       %coord = OpFunctionParameter %v2float
-     %params = OpFunctionParameter %ExternalTextureParams
-         %29 = OpLabel
-      %color = OpVariable %_ptr_Function_v3float Function %33
-         %34 = OpCompositeExtract %uint %params 0
-         %36 = OpIEqual %bool %34 %uint_1
-               OpSelectionMerge %38 None
-               OpBranchConditional %36 %39 %40
-         %39 = OpLabel
-         %43 = OpSampledImage %42 %plane0 %smp
-         %41 = OpImageSampleExplicitLod %v4float %43 %coord Lod %float_0
-         %45 = OpVectorShuffle %v3float %41 %41 0 1 2
-               OpStore %color %45
-               OpBranch %38
-         %40 = OpLabel
-         %47 = OpSampledImage %42 %plane0 %smp
-         %46 = OpImageSampleExplicitLod %v4float %47 %coord Lod %float_0
-         %48 = OpCompositeExtract %float %46 0
-         %50 = OpSampledImage %42 %plane1 %smp
-         %49 = OpImageSampleExplicitLod %v4float %50 %coord Lod %float_0
-         %51 = OpVectorShuffle %v2float %49 %49 0 1
-         %52 = OpCompositeExtract %float %51 0
-         %53 = OpCompositeExtract %float %51 1
-         %55 = OpCompositeConstruct %v4float %48 %52 %53 %float_1
-         %56 = OpCompositeExtract %mat3v4float %params 1
-         %57 = OpVectorTimesMatrix %v3float %55 %56
-               OpStore %color %57
-               OpBranch %38
-         %38 = OpLabel
-         %58 = OpLoad %v3float %color
-         %59 = OpCompositeExtract %float %58 0
-         %60 = OpCompositeExtract %float %58 1
-         %61 = OpCompositeExtract %float %58 2
-         %62 = OpCompositeConstruct %v4float %59 %60 %61 %float_1
-               OpReturnValue %62
+   %params_0 = OpFunctionParameter %ExternalTextureParams
+         %72 = OpLabel
+      %color = OpVariable %_ptr_Function_v3float Function %44
+         %74 = OpCompositeExtract %uint %params_0 0
+         %76 = OpIEqual %bool %74 %uint_1
+               OpSelectionMerge %77 None
+               OpBranchConditional %76 %78 %79
+         %78 = OpLabel
+         %82 = OpSampledImage %81 %plane0 %smp
+         %80 = OpImageSampleExplicitLod %v4float %82 %coord Lod %float_0
+         %84 = OpVectorShuffle %v3float %80 %80 0 1 2
+               OpStore %color %84
+               OpBranch %77
+         %79 = OpLabel
+         %86 = OpSampledImage %81 %plane0 %smp
+         %85 = OpImageSampleExplicitLod %v4float %86 %coord Lod %float_0
+         %87 = OpCompositeExtract %float %85 0
+         %89 = OpSampledImage %81 %plane1 %smp
+         %88 = OpImageSampleExplicitLod %v4float %89 %coord Lod %float_0
+         %90 = OpVectorShuffle %v2float %88 %88 0 1
+         %91 = OpCompositeExtract %float %90 0
+         %92 = OpCompositeExtract %float %90 1
+         %94 = OpCompositeConstruct %v4float %87 %91 %92 %float_1
+         %95 = OpCompositeExtract %mat3v4float %params_0 1
+         %96 = OpVectorTimesMatrix %v3float %94 %95
+               OpStore %color %96
+               OpBranch %77
+         %77 = OpLabel
+         %98 = OpLoad %v3float %color
+         %99 = OpCompositeExtract %GammaTransferParams %params_0 2
+         %97 = OpFunctionCall %v3float %gammaCorrection %98 %99
+               OpStore %color %97
+        %100 = OpCompositeExtract %mat3v3float %params_0 4
+        %101 = OpLoad %v3float %color
+        %102 = OpMatrixTimesVector %v3float %100 %101
+               OpStore %color %102
+        %104 = OpLoad %v3float %color
+        %105 = OpCompositeExtract %GammaTransferParams %params_0 3
+        %103 = OpFunctionCall %v3float %gammaCorrection %104 %105
+               OpStore %color %103
+        %106 = OpLoad %v3float %color
+        %107 = OpCompositeExtract %float %106 0
+        %108 = OpCompositeExtract %float %106 1
+        %109 = OpCompositeExtract %float %106 2
+        %110 = OpCompositeConstruct %v4float %107 %108 %109 %float_1
+               OpReturnValue %110
                OpFunctionEnd
-%textureSampleLevel_979816 = OpFunction %void None %63
-         %66 = OpLabel
+%textureSampleLevel_979816 = OpFunction %void None %111
+        %114 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function %5
-         %68 = OpLoad %11 %arg_0
-         %69 = OpLoad %11 %ext_tex_plane_1
-         %70 = OpLoad %20 %arg_1
-         %72 = OpLoad %ExternalTextureParams %ext_tex_params
-         %67 = OpFunctionCall %v4float %textureSampleExternal %68 %69 %70 %71 %72
-               OpStore %res %67
+        %116 = OpLoad %11 %arg_0
+        %117 = OpLoad %11 %ext_tex_plane_1
+        %118 = OpLoad %23 %arg_1
+        %120 = OpLoad %ExternalTextureParams %ext_tex_params
+        %115 = OpFunctionCall %v4float %textureSampleExternal %116 %117 %118 %119 %120
+               OpStore %res %115
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %75
-         %77 = OpLabel
-         %78 = OpFunctionCall %void %textureSampleLevel_979816
+%vertex_main_inner = OpFunction %v4float None %123
+        %125 = OpLabel
+        %126 = OpFunctionCall %void %textureSampleLevel_979816
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %63
-         %80 = OpLabel
-         %81 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %81
+%vertex_main = OpFunction %void None %111
+        %128 = OpLabel
+        %129 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %129
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %63
-         %83 = OpLabel
-         %84 = OpFunctionCall %void %textureSampleLevel_979816
+%fragment_main = OpFunction %void None %111
+        %131 = OpLabel
+        %132 = OpFunctionCall %void %textureSampleLevel_979816
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %63
-         %86 = OpLabel
-         %87 = OpFunctionCall %void %textureSampleLevel_979816
+%compute_main = OpFunction %void None %111
+        %134 = OpLabel
+        %135 = OpFunctionCall %void %textureSampleLevel_979816
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.hlsl b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.hlsl
index e821392..2fb9dfe 100644
--- a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.hlsl
+++ b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.hlsl
@@ -1,14 +1,34 @@
+struct GammaTransferParams {
+  float G;
+  float A;
+  float B;
+  float C;
+  float D;
+  float E;
+  float F;
+  uint padding;
+};
 struct ExternalTextureParams {
   uint numPlanes;
   float3x4 yuvToRgbConversionMatrix;
+  GammaTransferParams gammaDecodeParams;
+  GammaTransferParams gammaEncodeParams;
+  float3x3 gamutConversionMatrix;
 };
 
 Texture2D<float4> ext_tex_plane_1 : register(t1, space1);
 cbuffer cbuffer_ext_tex_params : register(b2, space1) {
-  uint4 ext_tex_params[4];
+  uint4 ext_tex_params[11];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
 
+float3 gammaCorrection(float3 v, GammaTransferParams params) {
+  const bool3 cond = (abs(v) < float3((params.D).xxx));
+  const float3 t = (sign(v) * ((params.C * abs(v)) + params.F));
+  const float3 f = (sign(v) * (pow(((params.A * abs(v)) + params.B), float3((params.G).xxx)) + params.E));
+  return (cond ? t : f);
+}
+
 float4 textureLoadExternal(Texture2D<float4> plane0, Texture2D<float4> plane1, int2 coord, ExternalTextureParams params) {
   float3 color = float3(0.0f, 0.0f, 0.0f);
   if ((params.numPlanes == 1u)) {
@@ -16,6 +36,9 @@
   } else {
     color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(coord, 0)).r, plane1.Load(int3(coord, 0)).rg, 1.0f));
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = mul(color, params.gamutConversionMatrix);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return float4(color, 1.0f);
 }
 
@@ -23,17 +46,37 @@
   return textureLoadExternal(tint_symbol, ext_tex_plane_1_1, coords, ext_tex_params_1);
 }
 
-float3x4 tint_symbol_4(uint4 buffer[4], uint offset) {
+float3x4 tint_symbol_4(uint4 buffer[11], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
   const uint scalar_offset_1 = ((offset + 16u)) / 4;
   const uint scalar_offset_2 = ((offset + 32u)) / 4;
   return float3x4(asfloat(buffer[scalar_offset / 4]), asfloat(buffer[scalar_offset_1 / 4]), asfloat(buffer[scalar_offset_2 / 4]));
 }
 
-ExternalTextureParams tint_symbol_2(uint4 buffer[4], uint offset) {
+GammaTransferParams tint_symbol_6(uint4 buffer[11], uint offset) {
   const uint scalar_offset_3 = ((offset + 0u)) / 4;
-  const ExternalTextureParams tint_symbol_6 = {buffer[scalar_offset_3 / 4][scalar_offset_3 % 4], tint_symbol_4(buffer, (offset + 16u))};
-  return tint_symbol_6;
+  const uint scalar_offset_4 = ((offset + 4u)) / 4;
+  const uint scalar_offset_5 = ((offset + 8u)) / 4;
+  const uint scalar_offset_6 = ((offset + 12u)) / 4;
+  const uint scalar_offset_7 = ((offset + 16u)) / 4;
+  const uint scalar_offset_8 = ((offset + 20u)) / 4;
+  const uint scalar_offset_9 = ((offset + 24u)) / 4;
+  const uint scalar_offset_10 = ((offset + 28u)) / 4;
+  const GammaTransferParams tint_symbol_10 = {asfloat(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), asfloat(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4]), asfloat(buffer[scalar_offset_5 / 4][scalar_offset_5 % 4]), asfloat(buffer[scalar_offset_6 / 4][scalar_offset_6 % 4]), asfloat(buffer[scalar_offset_7 / 4][scalar_offset_7 % 4]), asfloat(buffer[scalar_offset_8 / 4][scalar_offset_8 % 4]), asfloat(buffer[scalar_offset_9 / 4][scalar_offset_9 % 4]), buffer[scalar_offset_10 / 4][scalar_offset_10 % 4]};
+  return tint_symbol_10;
+}
+
+float3x3 tint_symbol_8(uint4 buffer[11], uint offset) {
+  const uint scalar_offset_11 = ((offset + 0u)) / 4;
+  const uint scalar_offset_12 = ((offset + 16u)) / 4;
+  const uint scalar_offset_13 = ((offset + 32u)) / 4;
+  return float3x3(asfloat(buffer[scalar_offset_11 / 4].xyz), asfloat(buffer[scalar_offset_12 / 4].xyz), asfloat(buffer[scalar_offset_13 / 4].xyz));
+}
+
+ExternalTextureParams tint_symbol_2(uint4 buffer[11], uint offset) {
+  const uint scalar_offset_14 = ((offset + 0u)) / 4;
+  const ExternalTextureParams tint_symbol_11 = {buffer[scalar_offset_14 / 4][scalar_offset_14 % 4], tint_symbol_4(buffer, (offset + 16u)), tint_symbol_6(buffer, (offset + 64u)), tint_symbol_6(buffer, (offset + 96u)), tint_symbol_8(buffer, (offset + 128u))};
+  return tint_symbol_11;
 }
 
 void doTextureLoad() {
diff --git a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.msl b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.msl
index bc167c9..c1e9dd6 100644
--- a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.msl
+++ b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.msl
@@ -1,12 +1,33 @@
 #include <metal_stdlib>
 
 using namespace metal;
+struct GammaTransferParams {
+  /* 0x0000 */ float G;
+  /* 0x0004 */ float A;
+  /* 0x0008 */ float B;
+  /* 0x000c */ float C;
+  /* 0x0010 */ float D;
+  /* 0x0014 */ float E;
+  /* 0x0018 */ float F;
+  /* 0x001c */ uint padding;
+};
+
 struct ExternalTextureParams {
   /* 0x0000 */ uint numPlanes;
   /* 0x0004 */ int8_t tint_pad[12];
   /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
+  /* 0x0040 */ GammaTransferParams gammaDecodeParams;
+  /* 0x0060 */ GammaTransferParams gammaEncodeParams;
+  /* 0x0080 */ float3x3 gamutConversionMatrix;
 };
 
+float3 gammaCorrection(float3 v, GammaTransferParams params) {
+  bool3 const cond = (fabs(v) < float3(params.D));
+  float3 const t = (sign(v) * ((params.C * fabs(v)) + params.F));
+  float3 const f = (sign(v) * (pow(((params.A * fabs(v)) + params.B), float3(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 float4 textureLoadExternal(texture2d<float, access::sample> plane0, texture2d<float, access::sample> plane1, int2 coord, ExternalTextureParams params) {
   float3 color = 0.0f;
   if ((params.numPlanes == 1u)) {
@@ -14,6 +35,9 @@
   } else {
     color = (float4(plane0.read(uint2(coord), 0)[0], float4(plane1.read(uint2(coord), 0)).rg, 1.0f) * params.yuvToRgbConversionMatrix);
   }
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
   return float4(color, 1.0f);
 }
 
diff --git a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.spvasm b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.spvasm
index 9fbc846..b7d51af 100644
--- a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.spvasm
+++ b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.spvasm
@@ -1,9 +1,10 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 89
+; Bound: 137
 ; Schema: 0
                OpCapability Shader
+         %27 = OpExtInstImport "GLSL.std.450"
                OpMemoryModel Logical GLSL450
                OpEntryPoint Vertex %vertex_main "vertex_main" %value %vertex_point_size
                OpEntryPoint Fragment %fragment_main "fragment_main"
@@ -16,13 +17,28 @@
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
                OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
+               OpMemberName %ExternalTextureParams 2 "gammaDecodeParams"
+               OpName %GammaTransferParams "GammaTransferParams"
+               OpMemberName %GammaTransferParams 0 "G"
+               OpMemberName %GammaTransferParams 1 "A"
+               OpMemberName %GammaTransferParams 2 "B"
+               OpMemberName %GammaTransferParams 3 "C"
+               OpMemberName %GammaTransferParams 4 "D"
+               OpMemberName %GammaTransferParams 5 "E"
+               OpMemberName %GammaTransferParams 6 "F"
+               OpMemberName %GammaTransferParams 7 "padding"
+               OpMemberName %ExternalTextureParams 3 "gammaEncodeParams"
+               OpMemberName %ExternalTextureParams 4 "gamutConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
+               OpName %gammaCorrection "gammaCorrection"
+               OpName %v "v"
+               OpName %params "params"
                OpName %textureLoadExternal "textureLoadExternal"
                OpName %plane0 "plane0"
                OpName %plane1 "plane1"
                OpName %coord "coord"
-               OpName %params "params"
+               OpName %params_0 "params"
                OpName %color "color"
                OpName %textureLoad2d "textureLoad2d"
                OpName %texture "texture"
@@ -44,6 +60,19 @@
                OpMemberDecorate %ExternalTextureParams 1 Offset 16
                OpMemberDecorate %ExternalTextureParams 1 ColMajor
                OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
+               OpMemberDecorate %ExternalTextureParams 2 Offset 64
+               OpMemberDecorate %GammaTransferParams 0 Offset 0
+               OpMemberDecorate %GammaTransferParams 1 Offset 4
+               OpMemberDecorate %GammaTransferParams 2 Offset 8
+               OpMemberDecorate %GammaTransferParams 3 Offset 12
+               OpMemberDecorate %GammaTransferParams 4 Offset 16
+               OpMemberDecorate %GammaTransferParams 5 Offset 20
+               OpMemberDecorate %GammaTransferParams 6 Offset 24
+               OpMemberDecorate %GammaTransferParams 7 Offset 28
+               OpMemberDecorate %ExternalTextureParams 3 Offset 96
+               OpMemberDecorate %ExternalTextureParams 4 Offset 128
+               OpMemberDecorate %ExternalTextureParams 4 ColMajor
+               OpMemberDecorate %ExternalTextureParams 4 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 2
@@ -62,101 +91,153 @@
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
 %mat3v4float = OpTypeMatrix %v4float 3
-%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
+%GammaTransferParams = OpTypeStruct %float %float %float %float %float %float %float %uint
+    %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float %GammaTransferParams %GammaTransferParams %mat3v3float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
+         %21 = OpTypeFunction %v3float %v3float %GammaTransferParams
+       %bool = OpTypeBool
+     %v3bool = OpTypeVector %bool 3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %41 = OpConstantNull %v3float
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
-         %18 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
-    %v3float = OpTypeVector %float 3
-%_ptr_Function_v3float = OpTypePointer Function %v3float
-         %30 = OpConstantNull %v3float
+         %61 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
      %uint_1 = OpConstant %uint 1
-       %bool = OpTypeBool
       %int_0 = OpConstant %int 0
     %v2float = OpTypeVector %float 2
     %float_1 = OpConstant %float 1
-         %57 = OpTypeFunction %v4float %11 %11 %ExternalTextureParams %v2int
+        %105 = OpTypeFunction %v4float %11 %11 %ExternalTextureParams %v2int
        %void = OpTypeVoid
-         %65 = OpTypeFunction %void
-         %73 = OpConstantNull %v2int
+        %113 = OpTypeFunction %void
+        %121 = OpConstantNull %v2int
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %76 = OpTypeFunction %v4float
-%textureLoadExternal = OpFunction %v4float None %18
+        %124 = OpTypeFunction %v4float
+%gammaCorrection = OpFunction %v3float None %21
+          %v = OpFunctionParameter %v3float
+     %params = OpFunctionParameter %GammaTransferParams
+         %25 = OpLabel
+         %39 = OpVariable %_ptr_Function_v3float Function %41
+         %51 = OpVariable %_ptr_Function_v3float Function %41
+         %57 = OpVariable %_ptr_Function_v3float Function %41
+         %26 = OpExtInst %v3float %27 FAbs %v
+         %28 = OpCompositeExtract %float %params 4
+         %29 = OpCompositeConstruct %v3float %28 %28 %28
+         %30 = OpFOrdLessThan %v3bool %26 %29
+         %33 = OpExtInst %v3float %27 FSign %v
+         %34 = OpCompositeExtract %float %params 3
+         %35 = OpExtInst %v3float %27 FAbs %v
+         %36 = OpVectorTimesScalar %v3float %35 %34
+         %37 = OpCompositeExtract %float %params 6
+         %42 = OpCompositeConstruct %v3float %37 %37 %37
+         %38 = OpFAdd %v3float %36 %42
+         %43 = OpFMul %v3float %33 %38
+         %44 = OpExtInst %v3float %27 FSign %v
+         %46 = OpCompositeExtract %float %params 1
+         %47 = OpExtInst %v3float %27 FAbs %v
+         %48 = OpVectorTimesScalar %v3float %47 %46
+         %49 = OpCompositeExtract %float %params 2
+         %52 = OpCompositeConstruct %v3float %49 %49 %49
+         %50 = OpFAdd %v3float %48 %52
+         %53 = OpCompositeExtract %float %params 0
+         %54 = OpCompositeConstruct %v3float %53 %53 %53
+         %45 = OpExtInst %v3float %27 Pow %50 %54
+         %55 = OpCompositeExtract %float %params 5
+         %58 = OpCompositeConstruct %v3float %55 %55 %55
+         %56 = OpFAdd %v3float %45 %58
+         %59 = OpFMul %v3float %44 %56
+         %60 = OpSelect %v3float %30 %43 %59
+               OpReturnValue %60
+               OpFunctionEnd
+%textureLoadExternal = OpFunction %v4float None %61
      %plane0 = OpFunctionParameter %11
      %plane1 = OpFunctionParameter %11
       %coord = OpFunctionParameter %v2int
-     %params = OpFunctionParameter %ExternalTextureParams
-         %26 = OpLabel
-      %color = OpVariable %_ptr_Function_v3float Function %30
-         %31 = OpCompositeExtract %uint %params 0
-         %33 = OpIEqual %bool %31 %uint_1
-               OpSelectionMerge %35 None
-               OpBranchConditional %33 %36 %37
-         %36 = OpLabel
-         %38 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-         %40 = OpVectorShuffle %v3float %38 %38 0 1 2
-               OpStore %color %40
-               OpBranch %35
-         %37 = OpLabel
-         %41 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-         %42 = OpCompositeExtract %float %41 0
-         %43 = OpImageFetch %v4float %plane1 %coord Lod %int_0
-         %45 = OpVectorShuffle %v2float %43 %43 0 1
-         %46 = OpCompositeExtract %float %45 0
-         %47 = OpCompositeExtract %float %45 1
-         %49 = OpCompositeConstruct %v4float %42 %46 %47 %float_1
-         %50 = OpCompositeExtract %mat3v4float %params 1
-         %51 = OpVectorTimesMatrix %v3float %49 %50
-               OpStore %color %51
-               OpBranch %35
-         %35 = OpLabel
-         %52 = OpLoad %v3float %color
-         %53 = OpCompositeExtract %float %52 0
-         %54 = OpCompositeExtract %float %52 1
-         %55 = OpCompositeExtract %float %52 2
-         %56 = OpCompositeConstruct %v4float %53 %54 %55 %float_1
-               OpReturnValue %56
+   %params_0 = OpFunctionParameter %ExternalTextureParams
+         %69 = OpLabel
+      %color = OpVariable %_ptr_Function_v3float Function %41
+         %71 = OpCompositeExtract %uint %params_0 0
+         %73 = OpIEqual %bool %71 %uint_1
+               OpSelectionMerge %74 None
+               OpBranchConditional %73 %75 %76
+         %75 = OpLabel
+         %77 = OpImageFetch %v4float %plane0 %coord Lod %int_0
+         %79 = OpVectorShuffle %v3float %77 %77 0 1 2
+               OpStore %color %79
+               OpBranch %74
+         %76 = OpLabel
+         %80 = OpImageFetch %v4float %plane0 %coord Lod %int_0
+         %81 = OpCompositeExtract %float %80 0
+         %82 = OpImageFetch %v4float %plane1 %coord Lod %int_0
+         %84 = OpVectorShuffle %v2float %82 %82 0 1
+         %85 = OpCompositeExtract %float %84 0
+         %86 = OpCompositeExtract %float %84 1
+         %88 = OpCompositeConstruct %v4float %81 %85 %86 %float_1
+         %89 = OpCompositeExtract %mat3v4float %params_0 1
+         %90 = OpVectorTimesMatrix %v3float %88 %89
+               OpStore %color %90
+               OpBranch %74
+         %74 = OpLabel
+         %92 = OpLoad %v3float %color
+         %93 = OpCompositeExtract %GammaTransferParams %params_0 2
+         %91 = OpFunctionCall %v3float %gammaCorrection %92 %93
+               OpStore %color %91
+         %94 = OpCompositeExtract %mat3v3float %params_0 4
+         %95 = OpLoad %v3float %color
+         %96 = OpMatrixTimesVector %v3float %94 %95
+               OpStore %color %96
+         %98 = OpLoad %v3float %color
+         %99 = OpCompositeExtract %GammaTransferParams %params_0 3
+         %97 = OpFunctionCall %v3float %gammaCorrection %98 %99
+               OpStore %color %97
+        %100 = OpLoad %v3float %color
+        %101 = OpCompositeExtract %float %100 0
+        %102 = OpCompositeExtract %float %100 1
+        %103 = OpCompositeExtract %float %100 2
+        %104 = OpCompositeConstruct %v4float %101 %102 %103 %float_1
+               OpReturnValue %104
                OpFunctionEnd
-%textureLoad2d = OpFunction %v4float None %57
+%textureLoad2d = OpFunction %v4float None %105
     %texture = OpFunctionParameter %11
 %ext_tex_plane_1_1 = OpFunctionParameter %11
 %ext_tex_params_1 = OpFunctionParameter %ExternalTextureParams
      %coords = OpFunctionParameter %v2int
-         %63 = OpLabel
-         %64 = OpFunctionCall %v4float %textureLoadExternal %texture %ext_tex_plane_1_1 %coords %ext_tex_params_1
-               OpReturnValue %64
+        %111 = OpLabel
+        %112 = OpFunctionCall %v4float %textureLoadExternal %texture %ext_tex_plane_1_1 %coords %ext_tex_params_1
+               OpReturnValue %112
                OpFunctionEnd
-%doTextureLoad = OpFunction %void None %65
-         %68 = OpLabel
+%doTextureLoad = OpFunction %void None %113
+        %116 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function %5
-         %70 = OpLoad %11 %arg_0
-         %71 = OpLoad %11 %ext_tex_plane_1
-         %72 = OpLoad %ExternalTextureParams %ext_tex_params
-         %69 = OpFunctionCall %v4float %textureLoad2d %70 %71 %72 %73
-               OpStore %res %69
+        %118 = OpLoad %11 %arg_0
+        %119 = OpLoad %11 %ext_tex_plane_1
+        %120 = OpLoad %ExternalTextureParams %ext_tex_params
+        %117 = OpFunctionCall %v4float %textureLoad2d %118 %119 %120 %121
+               OpStore %res %117
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %76
-         %78 = OpLabel
-         %79 = OpFunctionCall %void %doTextureLoad
+%vertex_main_inner = OpFunction %v4float None %124
+        %126 = OpLabel
+        %127 = OpFunctionCall %void %doTextureLoad
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %65
-         %81 = OpLabel
-         %82 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %82
+%vertex_main = OpFunction %void None %113
+        %129 = OpLabel
+        %130 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %130
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %65
-         %84 = OpLabel
-         %85 = OpFunctionCall %void %doTextureLoad
+%fragment_main = OpFunction %void None %113
+        %132 = OpLabel
+        %133 = OpFunctionCall %void %doTextureLoad
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %65
-         %87 = OpLabel
-         %88 = OpFunctionCall %void %doTextureLoad
+%compute_main = OpFunction %void None %113
+        %135 = OpLabel
+        %136 = OpFunctionCall %void %doTextureLoad
                OpReturn
                OpFunctionEnd