Change External Texture YUV-to-RGB Conversion to Use Matrix

Changes Dawn and Tint to use a 3x3 matrix for external texture
YUV-to-RGB conversions. This will allow us to use standard matrices
as they exist in SkYuvMath.

Bugs: dawn::1082
Change-Id: I8e0c7c3dc1c085d8f336da956aea9496913b70fa
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/86847
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Brandon1 Jones <brandon1.jones@intel.com>
diff --git a/src/dawn/native/ExternalTexture.cpp b/src/dawn/native/ExternalTexture.cpp
index a610004..7b3ae85 100644
--- a/src/dawn/native/ExternalTexture.cpp
+++ b/src/dawn/native/ExternalTexture.cpp
@@ -144,26 +144,20 @@
 
         DAWN_TRY_ASSIGN(mParamsBuffer, device->CreateBuffer(&bufferDesc));
 
-        // Dawn & Tint's YUV to RGB conversion implementation was inspired by the conversions found
-        // in libYUV. If this implementation needs expanded to support more colorspaces, this file
-        // is an excellent reference: chromium/src/third_party/libyuv/source/row_common.cc.
-        //
-        // The conversion from YUV to RGB looks like this:
-        // r = Y * 1.164          + V * vr
-        // g = Y * 1.164 - U * ug - V * vg
-        // b = Y * 1.164 + U * ub
-        //
-        // By changing the values of vr, vg, ub, and ug we can change the destination color space.
+        // Dawn & Tint's YUV-to-RGB conversion implementation is a simple 3x4 matrix multiplication
+        // using a standard conversion matrix. These matrices can be found in
+        // chromium/src/third_party/skia/src/core/SkYUVMath.cpp
         ExternalTextureParams params;
         params.numPlanes = descriptor->plane1 == nullptr ? 1 : 2;
 
         switch (descriptor->colorSpace) {
             case wgpu::PredefinedColorSpace::Srgb:
-                // Numbers derived from ITU-R recommendation for limited range BT.709
-                params.vr = 1.793;
-                params.vg = 0.392;
-                params.ub = 0.813;
-                params.ug = 2.017;
+                // 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:
                 break;
diff --git a/src/dawn/native/ExternalTexture.h b/src/dawn/native/ExternalTexture.h
index 694ab73..e752ca5 100644
--- a/src/dawn/native/ExternalTexture.h
+++ b/src/dawn/native/ExternalTexture.h
@@ -28,10 +28,8 @@
 
     struct ExternalTextureParams {
         uint32_t numPlanes;
-        float vr;
-        float vg;
-        float ub;
-        float ug;
+        std::array<uint32_t, 3> padding;
+        std::array<float, 12> yuvToRgbConversion;
     };
 
     MaybeError ValidateExternalTextureDescriptor(const DeviceBase* device,
diff --git a/src/dawn/tests/end2end/ExternalTextureTests.cpp b/src/dawn/tests/end2end/ExternalTextureTests.cpp
index 5843764..80cf6ce 100644
--- a/src/dawn/tests/end2end/ExternalTextureTests.cpp
+++ b/src/dawn/tests/end2end/ExternalTextureTests.cpp
@@ -191,10 +191,10 @@
         RGBA8 rgba;
     };
 
-    std::array<ConversionExpectation, 4> expectations = {{{0.0f, 0.5f, 0.5f, RGBA8::kBlack},
-                                                          {0.298f, 0.329f, 1.0f, RGBA8::kRed},
-                                                          {0.584f, -0.168f, -0.823f, RGBA8::kGreen},
-                                                          {0.113f, 1.0f, 0.419f, RGBA8::kBlue}}};
+    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}}};
 
     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 00466ac..37d1fa0 100644
--- a/src/tint/transform/multiplanar_external_texture.cc
+++ b/src/tint/transform/multiplanar_external_texture.cc
@@ -239,9 +239,8 @@
   /// Creates the ExternalTextureParams struct.
   void createExtTexParamsStruct() {
     ast::StructMemberList member_list = {
-        b.Member("numPlanes", b.ty.u32()), b.Member("vr", b.ty.f32()),
-        b.Member("ug", b.ty.f32()), b.Member("vg", b.ty.f32()),
-        b.Member("ub", b.ty.f32())};
+        b.Member("numPlanes", b.ty.u32()),
+        b.Member("yuvToRgbConversionMatrix", b.ty.mat3x4(b.ty.f32()))};
 
     params_struct_sym = b.Symbols().New("ExternalTextureParams");
 
@@ -280,40 +279,26 @@
     }
 
     return {
-        // if (params.numPlanes == 1u) {
-        //    return singlePlaneCall
-        // }
+        // var color: vec3<f32>;
+        b.Decl(b.Var("color", b.ty.vec3(b.ty.f32()))),
+        // if ((params.numPlanes == 1u))
         b.If(b.create<ast::BinaryExpression>(
                  ast::BinaryOp::kEqual, b.MemberAccessor("params", "numPlanes"),
                  b.Expr(1u)),
-             b.Block(b.Return(single_plane_call))),
-        // let y = plane0Call.r - 0.0625;
-        b.Decl(b.Const("y", nullptr,
-                       b.Sub(b.MemberAccessor(plane_0_call, "r"), 0.0625f))),
-        // let uv = plane1Call.rg - 0.5;
-        b.Decl(b.Const("uv", nullptr,
-                       b.Sub(b.MemberAccessor(plane_1_call, "rg"), 0.5f))),
-        // let u = uv.x;
-        b.Decl(b.Const("u", nullptr, b.MemberAccessor("uv", "x"))),
-        // let v = uv.y;
-        b.Decl(b.Const("v", nullptr, b.MemberAccessor("uv", "y"))),
-        // let r = 1.164 * y + params.vr * v;
-        b.Decl(b.Const("r", nullptr,
-                       b.Add(b.Mul(1.164f, "y"),
-                             b.Mul(b.MemberAccessor("params", "vr"), "v")))),
-        // let g = 1.164 * y - params.ug * u - params.vg * v;
-        b.Decl(
-            b.Const("g", nullptr,
-                    b.Sub(b.Sub(b.Mul(1.164f, "y"),
-                                b.Mul(b.MemberAccessor("params", "ug"), "u")),
-                          b.Mul(b.MemberAccessor("params", "vg"), "v")))),
-        // let b = 1.164 * y + params.ub * u;
-        b.Decl(b.Const("b", nullptr,
-                       b.Add(b.Mul(1.164f, "y"),
-                             b.Mul(b.MemberAccessor("params", "ub"), "u")))),
-        // return vec4<f32>(r, g, b, 1.0);
-        b.Return(b.vec4<f32>("r", "g", "b", 1.0f)),
-    };
+             b.Block(
+                 // color = textureLoad(plane0, coord, 0).rgb;
+                 b.Assign("color", b.MemberAccessor(single_plane_call, "rgb"))),
+             b.Else(b.Block(
+                 // color = vec4<f32>(plane_0_call.r, plane_1_call.rg, 1.0) *
+                 //         params.yuvToRgbConversionMatrix;
+                 b.Assign("color",
+                          b.Mul(b.vec4<f32>(
+                                    b.MemberAccessor(plane_0_call, "r"),
+                                    b.MemberAccessor(plane_1_call, "rg"), 1.0f),
+                                b.MemberAccessor(
+                                    "params", "yuvToRgbConversionMatrix")))))),
+        // return vec4<f32>(color, 1.0f);
+        b.Return(b.vec4<f32>("color", 1.0f))};
   }
 
   /// Creates the textureSampleExternal function if needed and returns a call
diff --git a/src/tint/transform/multiplanar_external_texture_test.cc b/src/tint/transform/multiplanar_external_texture_test.cc
index b0a79d6..df3b837 100644
--- a/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/transform/multiplanar_external_texture_test.cc
@@ -108,10 +108,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -151,10 +148,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -193,10 +187,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -208,17 +199,13 @@
 @group(0) @binding(1) var ext_tex : texture_2d<f32>;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -249,10 +236,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -260,17 +244,13 @@
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -304,10 +284,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -317,17 +294,13 @@
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
 
 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)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -357,10 +330,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -368,17 +338,13 @@
 @group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
 
 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)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -412,10 +378,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -427,31 +390,23 @@
 @group(0) @binding(1) var ext_tex : texture_2d<f32>;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 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)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -483,10 +438,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -494,31 +446,23 @@
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 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)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0).r, textureLoad(plane1, coord, 0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -556,10 +500,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(4) var ext_tex_plane_1 : texture_2d<f32>;
@@ -589,17 +530,13 @@
 @group(1) @binding(0) var ext_tex_3 : texture_2d<f32>;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -640,10 +577,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -651,17 +585,13 @@
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -707,10 +637,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -723,17 +650,13 @@
 }
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -773,10 +696,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -784,17 +704,13 @@
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(s : sampler, t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams) {
@@ -841,10 +757,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -856,17 +769,13 @@
 @group(0) @binding(6) var<uniform> ext_tex_params_1 : ExternalTextureParams;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
@@ -919,10 +828,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -939,17 +845,13 @@
 }
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
@@ -997,10 +899,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1008,17 +907,13 @@
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -1072,10 +967,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1083,17 +975,13 @@
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -1135,10 +1023,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 fn f(ext_tex : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams) -> vec2<i32> {
@@ -1174,10 +1059,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1187,17 +1069,13 @@
 type ET = texture_external;
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -1243,10 +1121,7 @@
   auto* expect = R"(
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1259,17 +1134,13 @@
 }
 
 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)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
diff --git a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl
index b351a33..3583595 100644
--- a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.glsl
@@ -2,18 +2,12 @@
 
 struct ExternalTextureParams {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  mat3x4 yuvToRgbConversionMatrix;
 };
 
 layout(binding = 2) uniform ExternalTextureParams_1 {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  mat3x4 yuvToRgbConversionMatrix;
 } ext_tex_params;
 
 uniform highp sampler2D arg_0_1;
@@ -38,18 +32,12 @@
 
 struct ExternalTextureParams {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  mat3x4 yuvToRgbConversionMatrix;
 };
 
 layout(binding = 2) uniform ExternalTextureParams_1 {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  mat3x4 yuvToRgbConversionMatrix;
 } ext_tex_params;
 
 uniform highp sampler2D arg_0_1;
@@ -69,18 +57,12 @@
 
 struct ExternalTextureParams {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  mat3x4 yuvToRgbConversionMatrix;
 };
 
 layout(binding = 2) uniform ExternalTextureParams_1 {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  mat3x4 yuvToRgbConversionMatrix;
 } 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 4697e5b..78d6e70 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[2];
+  uint4 ext_tex_params[4];
 };
 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 1faa96a..6a4127b 100644
--- a/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.msl
+++ b/test/tint/builtins/gen/textureDimensions/ba1481.wgsl.expected.msl
@@ -3,10 +3,7 @@
 using namespace metal;
 struct ExternalTextureParams {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  float3x4 yuvToRgbConversionMatrix;
 };
 
 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 461515f..9ff8d5a 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: 43
+; Bound: 44
 ; Schema: 0
                OpCapability Shader
                OpCapability ImageQuery
@@ -16,10 +16,7 @@
                OpName %ext_tex_plane_1 "ext_tex_plane_1"
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
-               OpMemberName %ExternalTextureParams 1 "vr"
-               OpMemberName %ExternalTextureParams 2 "ug"
-               OpMemberName %ExternalTextureParams 3 "vg"
-               OpMemberName %ExternalTextureParams 4 "ub"
+               OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
                OpName %textureDimensions_ba1481 "textureDimensions_ba1481"
@@ -34,10 +31,9 @@
                OpDecorate %ext_tex_plane_1 Binding 1
                OpDecorate %ExternalTextureParams Block
                OpMemberDecorate %ExternalTextureParams 0 Offset 0
-               OpMemberDecorate %ExternalTextureParams 1 Offset 4
-               OpMemberDecorate %ExternalTextureParams 2 Offset 8
-               OpMemberDecorate %ExternalTextureParams 3 Offset 12
-               OpMemberDecorate %ExternalTextureParams 4 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 ColMajor
+               OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 2
@@ -55,46 +51,47 @@
 %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
-%ExternalTextureParams = OpTypeStruct %uint %float %float %float %float
+%mat3v4float = OpTypeMatrix %v4float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %void = OpTypeVoid
-         %17 = OpTypeFunction %void
+         %18 = OpTypeFunction %void
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
       %int_0 = OpConstant %int 0
 %_ptr_Function_v2int = OpTypePointer Function %v2int
-         %28 = OpConstantNull %v2int
-         %29 = OpTypeFunction %v4float
+         %29 = OpConstantNull %v2int
+         %30 = OpTypeFunction %v4float
     %float_1 = OpConstant %float 1
-%textureDimensions_ba1481 = OpFunction %void None %17
-         %20 = OpLabel
-        %res = OpVariable %_ptr_Function_v2int Function %28
-         %24 = OpLoad %11 %arg_0
-         %21 = OpImageQuerySizeLod %v2int %24 %int_0
-               OpStore %res %21
+%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
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %29
-         %31 = OpLabel
-         %32 = OpFunctionCall %void %textureDimensions_ba1481
+%vertex_main_inner = OpFunction %v4float None %30
+         %32 = OpLabel
+         %33 = OpFunctionCall %void %textureDimensions_ba1481
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %17
-         %34 = OpLabel
-         %35 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %35
+%vertex_main = OpFunction %void None %18
+         %35 = OpLabel
+         %36 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %36
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %17
-         %38 = OpLabel
-         %39 = OpFunctionCall %void %textureDimensions_ba1481
+%fragment_main = OpFunction %void None %18
+         %39 = OpLabel
+         %40 = OpFunctionCall %void %textureDimensions_ba1481
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %17
-         %41 = OpLabel
-         %42 = OpFunctionCall %void %textureDimensions_ba1481
+%compute_main = OpFunction %void None %18
+         %42 = OpLabel
+         %43 = 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 a14b74b..f1d67e8 100644
--- a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.hlsl
+++ b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.hlsl
@@ -1,39 +1,35 @@
 struct ExternalTextureParams {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  float3x4 yuvToRgbConversionMatrix;
 };
 
 Texture2D<float4> ext_tex_plane_1 : register(t1, space1);
 cbuffer cbuffer_ext_tex_params : register(b2, space1) {
-  uint4 ext_tex_params[2];
+  uint4 ext_tex_params[4];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
 
 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)) {
-    return plane0.Load(int3(coord, 0));
+    color = plane0.Load(int3(coord, 0)).rgb;
+  } else {
+    color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(coord, 0)).r, plane1.Load(int3(coord, 0)).rg, 1.0f));
   }
-  const float y = (plane0.Load(int3(coord, 0)).r - 0.0625f);
-  const float2 uv = (plane1.Load(int3(coord, 0)).rg - 0.5f);
-  const float u = uv.x;
-  const float v = uv.y;
-  const float r = ((1.164000034f * y) + (params.vr * v));
-  const float g = (((1.164000034f * y) - (params.ug * u)) - (params.vg * v));
-  const float b = ((1.164000034f * y) + (params.ub * u));
-  return float4(r, g, b, 1.0f);
+  return float4(color, 1.0f);
 }
 
-ExternalTextureParams tint_symbol_1(uint4 buffer[2], uint offset) {
+float3x4 tint_symbol_3(uint4 buffer[4], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  const uint scalar_offset_2 = ((offset + 8u)) / 4;
-  const uint scalar_offset_3 = ((offset + 12u)) / 4;
-  const uint scalar_offset_4 = ((offset + 16u)) / 4;
-  const ExternalTextureParams tint_symbol_4 = {buffer[scalar_offset / 4][scalar_offset % 4], asfloat(buffer[scalar_offset_1 / 4][scalar_offset_1 % 4]), asfloat(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), asfloat(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), asfloat(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_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) {
+  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;
 }
 
 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 d91b328..2cf34bc 100644
--- a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.msl
+++ b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.msl
@@ -3,24 +3,18 @@
 using namespace metal;
 struct ExternalTextureParams {
   /* 0x0000 */ uint numPlanes;
-  /* 0x0004 */ float vr;
-  /* 0x0008 */ float ug;
-  /* 0x000c */ float vg;
-  /* 0x0010 */ float ub;
+  /* 0x0004 */ int8_t tint_pad[12];
+  /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
 };
 
 float4 textureLoadExternal(texture2d<float, access::sample> plane0, texture2d<float, access::sample> plane1, int2 coord, ExternalTextureParams params) {
+  float3 color = 0.0f;
   if ((params.numPlanes == 1u)) {
-    return plane0.read(uint2(coord), 0);
+    color = float4(plane0.read(uint2(coord), 0)).rgb;
+  } else {
+    color = (float4(plane0.read(uint2(coord), 0)[0], float4(plane1.read(uint2(coord), 0)).rg, 1.0f) * params.yuvToRgbConversionMatrix);
   }
-  float const y = (plane0.read(uint2(coord), 0)[0] - 0.0625f);
-  float2 const uv = (float4(plane1.read(uint2(coord), 0)).rg - 0.5f);
-  float const u = uv[0];
-  float const v = uv[1];
-  float const r = ((1.164000034f * y) + (params.vr * v));
-  float const g = (((1.164000034f * y) - (params.ug * u)) - (params.vg * v));
-  float const b = ((1.164000034f * y) + (params.ub * u));
-  return float4(r, g, b, 1.0f);
+  return float4(color, 1.0f);
 }
 
 void textureLoad_8acf41(texture2d<float, access::sample> tint_symbol_1, texture2d<float, access::sample> tint_symbol_2, const constant ExternalTextureParams* const tint_symbol_3) {
diff --git a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm
index 4ac3e99..8e9330c 100644
--- a/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/textureLoad/8acf41.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 91
+; Bound: 81
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -15,10 +15,7 @@
                OpName %ext_tex_plane_1 "ext_tex_plane_1"
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
-               OpMemberName %ExternalTextureParams 1 "vr"
-               OpMemberName %ExternalTextureParams 2 "ug"
-               OpMemberName %ExternalTextureParams 3 "vg"
-               OpMemberName %ExternalTextureParams 4 "ub"
+               OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
                OpName %textureLoadExternal "textureLoadExternal"
@@ -26,6 +23,7 @@
                OpName %plane1 "plane1"
                OpName %coord "coord"
                OpName %params "params"
+               OpName %color "color"
                OpName %textureLoad_8acf41 "textureLoad_8acf41"
                OpName %res "res"
                OpName %vertex_main_inner "vertex_main_inner"
@@ -38,10 +36,9 @@
                OpDecorate %ext_tex_plane_1 Binding 1
                OpDecorate %ExternalTextureParams Block
                OpMemberDecorate %ExternalTextureParams 0 Offset 0
-               OpMemberDecorate %ExternalTextureParams 1 Offset 4
-               OpMemberDecorate %ExternalTextureParams 2 Offset 8
-               OpMemberDecorate %ExternalTextureParams 3 Offset 12
-               OpMemberDecorate %ExternalTextureParams 4 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 ColMajor
+               OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 2
@@ -59,99 +56,92 @@
 %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
-%ExternalTextureParams = OpTypeStruct %uint %float %float %float %float
+%mat3v4float = OpTypeMatrix %v4float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
-         %17 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
+         %18 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
+    %v3float = OpTypeVector %float 3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %30 = OpConstantNull %v3float
      %uint_1 = OpConstant %uint 1
        %bool = OpTypeBool
       %int_0 = OpConstant %int 0
-%float_0_0625 = OpConstant %float 0.0625
     %v2float = OpTypeVector %float 2
-  %float_0_5 = OpConstant %float 0.5
-%_ptr_Function_v2float = OpTypePointer Function %v2float
-         %45 = OpConstantNull %v2float
-%float_1_16400003 = OpConstant %float 1.16400003
     %float_1 = OpConstant %float 1
        %void = OpTypeVoid
-         %67 = OpTypeFunction %void
-         %74 = OpConstantNull %v2int
+         %57 = OpTypeFunction %void
+         %64 = OpConstantNull %v2int
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %78 = OpTypeFunction %v4float
-%textureLoadExternal = OpFunction %v4float None %17
+         %68 = OpTypeFunction %v4float
+%textureLoadExternal = OpFunction %v4float None %18
      %plane0 = OpFunctionParameter %11
      %plane1 = OpFunctionParameter %11
       %coord = OpFunctionParameter %v2int
      %params = OpFunctionParameter %ExternalTextureParams
-         %25 = OpLabel
-         %43 = OpVariable %_ptr_Function_v2float Function %45
-         %26 = OpCompositeExtract %uint %params 0
-         %28 = OpIEqual %bool %26 %uint_1
-               OpSelectionMerge %30 None
-               OpBranchConditional %28 %31 %30
-         %31 = OpLabel
-         %32 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-               OpReturnValue %32
-         %30 = OpLabel
-         %34 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-         %35 = OpCompositeExtract %float %34 0
-         %37 = OpFSub %float %35 %float_0_0625
-         %38 = OpImageFetch %v4float %plane1 %coord Lod %int_0
-         %40 = OpVectorShuffle %v2float %38 %38 0 1
-         %46 = OpCompositeConstruct %v2float %float_0_5 %float_0_5
-         %42 = OpFSub %v2float %40 %46
-         %47 = OpCompositeExtract %float %42 0
-         %48 = OpCompositeExtract %float %42 1
-         %50 = OpFMul %float %float_1_16400003 %37
-         %51 = OpCompositeExtract %float %params 1
-         %52 = OpFMul %float %51 %48
-         %53 = OpFAdd %float %50 %52
-         %54 = OpFMul %float %float_1_16400003 %37
-         %55 = OpCompositeExtract %float %params 2
-         %56 = OpFMul %float %55 %47
-         %57 = OpFSub %float %54 %56
-         %58 = OpCompositeExtract %float %params 3
-         %59 = OpFMul %float %58 %48
-         %60 = OpFSub %float %57 %59
-         %61 = OpFMul %float %float_1_16400003 %37
-         %62 = OpCompositeExtract %float %params 4
-         %63 = OpFMul %float %62 %47
-         %64 = OpFAdd %float %61 %63
-         %66 = OpCompositeConstruct %v4float %53 %60 %64 %float_1
-               OpReturnValue %66
+         %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
                OpFunctionEnd
-%textureLoad_8acf41 = OpFunction %void None %67
-         %70 = OpLabel
+%textureLoad_8acf41 = OpFunction %void None %57
+         %60 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function %5
-         %72 = OpLoad %11 %arg_0
-         %73 = OpLoad %11 %ext_tex_plane_1
-         %75 = OpLoad %ExternalTextureParams %ext_tex_params
-         %71 = OpFunctionCall %v4float %textureLoadExternal %72 %73 %74 %75
-               OpStore %res %71
+         %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
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %78
-         %80 = OpLabel
-         %81 = OpFunctionCall %void %textureLoad_8acf41
+%vertex_main_inner = OpFunction %v4float None %68
+         %70 = OpLabel
+         %71 = OpFunctionCall %void %textureLoad_8acf41
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %67
-         %83 = OpLabel
-         %84 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %84
+%vertex_main = OpFunction %void None %57
+         %73 = OpLabel
+         %74 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %74
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %67
-         %86 = OpLabel
-         %87 = OpFunctionCall %void %textureLoad_8acf41
+%fragment_main = OpFunction %void None %57
+         %76 = OpLabel
+         %77 = OpFunctionCall %void %textureLoad_8acf41
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %67
-         %89 = OpLabel
-         %90 = OpFunctionCall %void %textureLoad_8acf41
+%compute_main = OpFunction %void None %57
+         %79 = OpLabel
+         %80 = 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 4fe76bc..dce01cb 100644
--- a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.hlsl
+++ b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.hlsl
@@ -1,40 +1,36 @@
 struct ExternalTextureParams {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  float3x4 yuvToRgbConversionMatrix;
 };
 
 Texture2D<float4> ext_tex_plane_1 : register(t2, space1);
 cbuffer cbuffer_ext_tex_params : register(b3, space1) {
-  uint4 ext_tex_params[2];
+  uint4 ext_tex_params[4];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
 SamplerState arg_1 : register(s1, space1);
 
 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)) {
-    return plane0.SampleLevel(smp, coord, 0.0f);
+    color = plane0.SampleLevel(smp, coord, 0.0f).rgb;
+  } else {
+    color = mul(params.yuvToRgbConversionMatrix, float4(plane0.SampleLevel(smp, coord, 0.0f).r, plane1.SampleLevel(smp, coord, 0.0f).rg, 1.0f));
   }
-  const float y = (plane0.SampleLevel(smp, coord, 0.0f).r - 0.0625f);
-  const float2 uv = (plane1.SampleLevel(smp, coord, 0.0f).rg - 0.5f);
-  const float u = uv.x;
-  const float v = uv.y;
-  const float r = ((1.164000034f * y) + (params.vr * v));
-  const float g = (((1.164000034f * y) - (params.ug * u)) - (params.vg * v));
-  const float b = ((1.164000034f * y) + (params.ub * u));
-  return float4(r, g, b, 1.0f);
+  return float4(color, 1.0f);
 }
 
-ExternalTextureParams tint_symbol_1(uint4 buffer[2], uint offset) {
+float3x4 tint_symbol_3(uint4 buffer[4], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  const uint scalar_offset_2 = ((offset + 8u)) / 4;
-  const uint scalar_offset_3 = ((offset + 12u)) / 4;
-  const uint scalar_offset_4 = ((offset + 16u)) / 4;
-  const ExternalTextureParams tint_symbol_4 = {buffer[scalar_offset / 4][scalar_offset % 4], asfloat(buffer[scalar_offset_1 / 4][scalar_offset_1 % 4]), asfloat(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), asfloat(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), asfloat(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_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) {
+  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;
 }
 
 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 9b4be13..2a297df 100644
--- a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.msl
+++ b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.msl
@@ -3,24 +3,18 @@
 using namespace metal;
 struct ExternalTextureParams {
   /* 0x0000 */ uint numPlanes;
-  /* 0x0004 */ float vr;
-  /* 0x0008 */ float ug;
-  /* 0x000c */ float vg;
-  /* 0x0010 */ float ub;
+  /* 0x0004 */ int8_t tint_pad[12];
+  /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
 };
 
 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)) {
-    return plane0.sample(smp, coord, level(0.0f));
+    color = float4(plane0.sample(smp, coord, level(0.0f))).rgb;
+  } else {
+    color = (float4(plane0.sample(smp, coord, level(0.0f))[0], float4(plane1.sample(smp, coord, level(0.0f))).rg, 1.0f) * params.yuvToRgbConversionMatrix);
   }
-  float const y = (plane0.sample(smp, coord, level(0.0f))[0] - 0.0625f);
-  float2 const uv = (float4(plane1.sample(smp, coord, level(0.0f))).rg - 0.5f);
-  float const u = uv[0];
-  float const v = uv[1];
-  float const r = ((1.164000034f * y) + (params.vr * v));
-  float const g = (((1.164000034f * y) - (params.ug * u)) - (params.vg * v));
-  float const b = ((1.164000034f * y) + (params.ub * u));
-  return float4(r, g, b, 1.0f);
+  return float4(color, 1.0f);
 }
 
 void textureSampleLevel_979816(texture2d<float, access::sample> tint_symbol_1, texture2d<float, access::sample> tint_symbol_2, sampler tint_symbol_3, const constant ExternalTextureParams* const tint_symbol_4) {
diff --git a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm
index 62347b9..ae6490c 100644
--- a/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/textureSampleLevel/979816.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 97
+; Bound: 88
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -15,10 +15,7 @@
                OpName %ext_tex_plane_1 "ext_tex_plane_1"
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
-               OpMemberName %ExternalTextureParams 1 "vr"
-               OpMemberName %ExternalTextureParams 2 "ug"
-               OpMemberName %ExternalTextureParams 3 "vg"
-               OpMemberName %ExternalTextureParams 4 "ub"
+               OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
                OpName %arg_1 "arg_1"
@@ -28,6 +25,7 @@
                OpName %smp "smp"
                OpName %coord "coord"
                OpName %params "params"
+               OpName %color "color"
                OpName %textureSampleLevel_979816 "textureSampleLevel_979816"
                OpName %res "res"
                OpName %vertex_main_inner "vertex_main_inner"
@@ -40,10 +38,9 @@
                OpDecorate %ext_tex_plane_1 Binding 2
                OpDecorate %ExternalTextureParams Block
                OpMemberDecorate %ExternalTextureParams 0 Offset 0
-               OpMemberDecorate %ExternalTextureParams 1 Offset 4
-               OpMemberDecorate %ExternalTextureParams 2 Offset 8
-               OpMemberDecorate %ExternalTextureParams 3 Offset 12
-               OpMemberDecorate %ExternalTextureParams 4 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 ColMajor
+               OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 3
@@ -63,105 +60,99 @@
 %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
-%ExternalTextureParams = OpTypeStruct %uint %float %float %float %float
+%mat3v4float = OpTypeMatrix %v4float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
-         %19 = OpTypeSampler
-%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
-      %arg_1 = OpVariable %_ptr_UniformConstant_19 UniformConstant
+         %20 = OpTypeSampler
+%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
+      %arg_1 = OpVariable %_ptr_UniformConstant_20 UniformConstant
     %v2float = OpTypeVector %float 2
-         %20 = OpTypeFunction %v4float %11 %11 %19 %v2float %ExternalTextureParams
+         %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
        %bool = OpTypeBool
-         %36 = OpTypeSampledImage %11
+         %42 = OpTypeSampledImage %11
     %float_0 = OpConstant %float 0
-%float_0_0625 = OpConstant %float 0.0625
-  %float_0_5 = OpConstant %float 0.5
-%_ptr_Function_v2float = OpTypePointer Function %v2float
-         %51 = OpConstantNull %v2float
-%float_1_16400003 = OpConstant %float 1.16400003
     %float_1 = OpConstant %float 1
        %void = OpTypeVoid
-         %73 = OpTypeFunction %void
+         %63 = OpTypeFunction %void
+         %71 = OpConstantNull %v2float
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %84 = OpTypeFunction %v4float
-%textureSampleExternal = OpFunction %v4float None %20
+         %75 = OpTypeFunction %v4float
+%textureSampleExternal = OpFunction %v4float None %21
      %plane0 = OpFunctionParameter %11
      %plane1 = OpFunctionParameter %11
-        %smp = OpFunctionParameter %19
+        %smp = OpFunctionParameter %20
       %coord = OpFunctionParameter %v2float
      %params = OpFunctionParameter %ExternalTextureParams
-         %28 = OpLabel
-         %49 = OpVariable %_ptr_Function_v2float Function %51
-         %29 = OpCompositeExtract %uint %params 0
-         %31 = OpIEqual %bool %29 %uint_1
-               OpSelectionMerge %33 None
-               OpBranchConditional %31 %34 %33
-         %34 = OpLabel
-         %37 = OpSampledImage %36 %plane0 %smp
-         %35 = OpImageSampleExplicitLod %v4float %37 %coord Lod %float_0
-               OpReturnValue %35
-         %33 = OpLabel
-         %40 = OpSampledImage %36 %plane0 %smp
-         %39 = OpImageSampleExplicitLod %v4float %40 %coord Lod %float_0
-         %41 = OpCompositeExtract %float %39 0
-         %43 = OpFSub %float %41 %float_0_0625
-         %45 = OpSampledImage %36 %plane1 %smp
-         %44 = OpImageSampleExplicitLod %v4float %45 %coord Lod %float_0
-         %46 = OpVectorShuffle %v2float %44 %44 0 1
-         %52 = OpCompositeConstruct %v2float %float_0_5 %float_0_5
-         %48 = OpFSub %v2float %46 %52
-         %53 = OpCompositeExtract %float %48 0
-         %54 = OpCompositeExtract %float %48 1
-         %56 = OpFMul %float %float_1_16400003 %43
-         %57 = OpCompositeExtract %float %params 1
-         %58 = OpFMul %float %57 %54
-         %59 = OpFAdd %float %56 %58
-         %60 = OpFMul %float %float_1_16400003 %43
-         %61 = OpCompositeExtract %float %params 2
-         %62 = OpFMul %float %61 %53
-         %63 = OpFSub %float %60 %62
-         %64 = OpCompositeExtract %float %params 3
-         %65 = OpFMul %float %64 %54
-         %66 = OpFSub %float %63 %65
-         %67 = OpFMul %float %float_1_16400003 %43
-         %68 = OpCompositeExtract %float %params 4
-         %69 = OpFMul %float %68 %53
-         %70 = OpFAdd %float %67 %69
-         %72 = OpCompositeConstruct %v4float %59 %66 %70 %float_1
-               OpReturnValue %72
+         %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
                OpFunctionEnd
-%textureSampleLevel_979816 = OpFunction %void None %73
-         %76 = OpLabel
+%textureSampleLevel_979816 = OpFunction %void None %63
+         %66 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function %5
-         %78 = OpLoad %11 %arg_0
-         %79 = OpLoad %11 %ext_tex_plane_1
-         %80 = OpLoad %19 %arg_1
-         %81 = OpLoad %ExternalTextureParams %ext_tex_params
-         %77 = OpFunctionCall %v4float %textureSampleExternal %78 %79 %80 %51 %81
-               OpStore %res %77
+         %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
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %84
-         %86 = OpLabel
-         %87 = OpFunctionCall %void %textureSampleLevel_979816
+%vertex_main_inner = OpFunction %v4float None %75
+         %77 = OpLabel
+         %78 = OpFunctionCall %void %textureSampleLevel_979816
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %73
-         %89 = OpLabel
-         %90 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %90
+%vertex_main = OpFunction %void None %63
+         %80 = OpLabel
+         %81 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %81
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %73
-         %92 = OpLabel
-         %93 = OpFunctionCall %void %textureSampleLevel_979816
+%fragment_main = OpFunction %void None %63
+         %83 = OpLabel
+         %84 = OpFunctionCall %void %textureSampleLevel_979816
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %73
-         %95 = OpLabel
-         %96 = OpFunctionCall %void %textureSampleLevel_979816
+%compute_main = OpFunction %void None %63
+         %86 = OpLabel
+         %87 = 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 e7f6715..e821392 100644
--- a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.hlsl
+++ b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.hlsl
@@ -1,43 +1,39 @@
 struct ExternalTextureParams {
   uint numPlanes;
-  float vr;
-  float ug;
-  float vg;
-  float ub;
+  float3x4 yuvToRgbConversionMatrix;
 };
 
 Texture2D<float4> ext_tex_plane_1 : register(t1, space1);
 cbuffer cbuffer_ext_tex_params : register(b2, space1) {
-  uint4 ext_tex_params[2];
+  uint4 ext_tex_params[4];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
 
 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)) {
-    return plane0.Load(int3(coord, 0));
+    color = plane0.Load(int3(coord, 0)).rgb;
+  } else {
+    color = mul(params.yuvToRgbConversionMatrix, float4(plane0.Load(int3(coord, 0)).r, plane1.Load(int3(coord, 0)).rg, 1.0f));
   }
-  const float y = (plane0.Load(int3(coord, 0)).r - 0.0625f);
-  const float2 uv = (plane1.Load(int3(coord, 0)).rg - 0.5f);
-  const float u = uv.x;
-  const float v = uv.y;
-  const float r = ((1.164000034f * y) + (params.vr * v));
-  const float g = (((1.164000034f * y) - (params.ug * u)) - (params.vg * v));
-  const float b = ((1.164000034f * y) + (params.ub * u));
-  return float4(r, g, b, 1.0f);
+  return float4(color, 1.0f);
 }
 
 float4 textureLoad2d(Texture2D<float4> tint_symbol, Texture2D<float4> ext_tex_plane_1_1, ExternalTextureParams ext_tex_params_1, int2 coords) {
   return textureLoadExternal(tint_symbol, ext_tex_plane_1_1, coords, ext_tex_params_1);
 }
 
-ExternalTextureParams tint_symbol_2(uint4 buffer[2], uint offset) {
+float3x4 tint_symbol_4(uint4 buffer[4], uint offset) {
   const uint scalar_offset = ((offset + 0u)) / 4;
-  const uint scalar_offset_1 = ((offset + 4u)) / 4;
-  const uint scalar_offset_2 = ((offset + 8u)) / 4;
-  const uint scalar_offset_3 = ((offset + 12u)) / 4;
-  const uint scalar_offset_4 = ((offset + 16u)) / 4;
-  const ExternalTextureParams tint_symbol_5 = {buffer[scalar_offset / 4][scalar_offset % 4], asfloat(buffer[scalar_offset_1 / 4][scalar_offset_1 % 4]), asfloat(buffer[scalar_offset_2 / 4][scalar_offset_2 % 4]), asfloat(buffer[scalar_offset_3 / 4][scalar_offset_3 % 4]), asfloat(buffer[scalar_offset_4 / 4][scalar_offset_4 % 4])};
-  return tint_symbol_5;
+  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) {
+  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;
 }
 
 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 4e82e4d..bc167c9 100644
--- a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.msl
+++ b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.msl
@@ -3,24 +3,18 @@
 using namespace metal;
 struct ExternalTextureParams {
   /* 0x0000 */ uint numPlanes;
-  /* 0x0004 */ float vr;
-  /* 0x0008 */ float ug;
-  /* 0x000c */ float vg;
-  /* 0x0010 */ float ub;
+  /* 0x0004 */ int8_t tint_pad[12];
+  /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
 };
 
 float4 textureLoadExternal(texture2d<float, access::sample> plane0, texture2d<float, access::sample> plane1, int2 coord, ExternalTextureParams params) {
+  float3 color = 0.0f;
   if ((params.numPlanes == 1u)) {
-    return plane0.read(uint2(coord), 0);
+    color = float4(plane0.read(uint2(coord), 0)).rgb;
+  } else {
+    color = (float4(plane0.read(uint2(coord), 0)[0], float4(plane1.read(uint2(coord), 0)).rg, 1.0f) * params.yuvToRgbConversionMatrix);
   }
-  float const y = (plane0.read(uint2(coord), 0)[0] - 0.0625f);
-  float2 const uv = (float4(plane1.read(uint2(coord), 0)).rg - 0.5f);
-  float const u = uv[0];
-  float const v = uv[1];
-  float const r = ((1.164000034f * y) + (params.vr * v));
-  float const g = (((1.164000034f * y) - (params.ug * u)) - (params.vg * v));
-  float const b = ((1.164000034f * y) + (params.ub * u));
-  return float4(r, g, b, 1.0f);
+  return float4(color, 1.0f);
 }
 
 float4 textureLoad2d(texture2d<float, access::sample> tint_symbol, texture2d<float, access::sample> ext_tex_plane_1_1, ExternalTextureParams ext_tex_params_1, int2 coords) {
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 cd8297f..9fbc846 100644
--- a/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.spvasm
+++ b/test/tint/builtins/textureLoad/texture_external_param.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 99
+; Bound: 89
 ; Schema: 0
                OpCapability Shader
                OpMemoryModel Logical GLSL450
@@ -15,10 +15,7 @@
                OpName %ext_tex_plane_1 "ext_tex_plane_1"
                OpName %ExternalTextureParams "ExternalTextureParams"
                OpMemberName %ExternalTextureParams 0 "numPlanes"
-               OpMemberName %ExternalTextureParams 1 "vr"
-               OpMemberName %ExternalTextureParams 2 "ug"
-               OpMemberName %ExternalTextureParams 3 "vg"
-               OpMemberName %ExternalTextureParams 4 "ub"
+               OpMemberName %ExternalTextureParams 1 "yuvToRgbConversionMatrix"
                OpName %ext_tex_params "ext_tex_params"
                OpName %arg_0 "arg_0"
                OpName %textureLoadExternal "textureLoadExternal"
@@ -26,6 +23,7 @@
                OpName %plane1 "plane1"
                OpName %coord "coord"
                OpName %params "params"
+               OpName %color "color"
                OpName %textureLoad2d "textureLoad2d"
                OpName %texture "texture"
                OpName %ext_tex_plane_1_1 "ext_tex_plane_1_1"
@@ -43,10 +41,9 @@
                OpDecorate %ext_tex_plane_1 Binding 1
                OpDecorate %ExternalTextureParams Block
                OpMemberDecorate %ExternalTextureParams 0 Offset 0
-               OpMemberDecorate %ExternalTextureParams 1 Offset 4
-               OpMemberDecorate %ExternalTextureParams 2 Offset 8
-               OpMemberDecorate %ExternalTextureParams 3 Offset 12
-               OpMemberDecorate %ExternalTextureParams 4 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 Offset 16
+               OpMemberDecorate %ExternalTextureParams 1 ColMajor
+               OpMemberDecorate %ExternalTextureParams 1 MatrixStride 16
                OpDecorate %ext_tex_params NonWritable
                OpDecorate %ext_tex_params DescriptorSet 1
                OpDecorate %ext_tex_params Binding 2
@@ -64,109 +61,102 @@
 %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
 %ext_tex_plane_1 = OpVariable %_ptr_UniformConstant_11 UniformConstant
        %uint = OpTypeInt 32 0
-%ExternalTextureParams = OpTypeStruct %uint %float %float %float %float
+%mat3v4float = OpTypeMatrix %v4float 3
+%ExternalTextureParams = OpTypeStruct %uint %mat3v4float
 %_ptr_Uniform_ExternalTextureParams = OpTypePointer Uniform %ExternalTextureParams
 %ext_tex_params = OpVariable %_ptr_Uniform_ExternalTextureParams Uniform
       %arg_0 = OpVariable %_ptr_UniformConstant_11 UniformConstant
         %int = OpTypeInt 32 1
       %v2int = OpTypeVector %int 2
-         %17 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
+         %18 = OpTypeFunction %v4float %11 %11 %v2int %ExternalTextureParams
+    %v3float = OpTypeVector %float 3
+%_ptr_Function_v3float = OpTypePointer Function %v3float
+         %30 = OpConstantNull %v3float
      %uint_1 = OpConstant %uint 1
        %bool = OpTypeBool
       %int_0 = OpConstant %int 0
-%float_0_0625 = OpConstant %float 0.0625
     %v2float = OpTypeVector %float 2
-  %float_0_5 = OpConstant %float 0.5
-%_ptr_Function_v2float = OpTypePointer Function %v2float
-         %45 = OpConstantNull %v2float
-%float_1_16400003 = OpConstant %float 1.16400003
     %float_1 = OpConstant %float 1
-         %67 = OpTypeFunction %v4float %11 %11 %ExternalTextureParams %v2int
+         %57 = OpTypeFunction %v4float %11 %11 %ExternalTextureParams %v2int
        %void = OpTypeVoid
-         %75 = OpTypeFunction %void
-         %83 = OpConstantNull %v2int
+         %65 = OpTypeFunction %void
+         %73 = OpConstantNull %v2int
 %_ptr_Function_v4float = OpTypePointer Function %v4float
-         %86 = OpTypeFunction %v4float
-%textureLoadExternal = OpFunction %v4float None %17
+         %76 = OpTypeFunction %v4float
+%textureLoadExternal = OpFunction %v4float None %18
      %plane0 = OpFunctionParameter %11
      %plane1 = OpFunctionParameter %11
       %coord = OpFunctionParameter %v2int
      %params = OpFunctionParameter %ExternalTextureParams
-         %25 = OpLabel
-         %43 = OpVariable %_ptr_Function_v2float Function %45
-         %26 = OpCompositeExtract %uint %params 0
-         %28 = OpIEqual %bool %26 %uint_1
-               OpSelectionMerge %30 None
-               OpBranchConditional %28 %31 %30
-         %31 = OpLabel
-         %32 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-               OpReturnValue %32
-         %30 = OpLabel
-         %34 = OpImageFetch %v4float %plane0 %coord Lod %int_0
-         %35 = OpCompositeExtract %float %34 0
-         %37 = OpFSub %float %35 %float_0_0625
-         %38 = OpImageFetch %v4float %plane1 %coord Lod %int_0
-         %40 = OpVectorShuffle %v2float %38 %38 0 1
-         %46 = OpCompositeConstruct %v2float %float_0_5 %float_0_5
-         %42 = OpFSub %v2float %40 %46
-         %47 = OpCompositeExtract %float %42 0
-         %48 = OpCompositeExtract %float %42 1
-         %50 = OpFMul %float %float_1_16400003 %37
-         %51 = OpCompositeExtract %float %params 1
-         %52 = OpFMul %float %51 %48
-         %53 = OpFAdd %float %50 %52
-         %54 = OpFMul %float %float_1_16400003 %37
-         %55 = OpCompositeExtract %float %params 2
-         %56 = OpFMul %float %55 %47
-         %57 = OpFSub %float %54 %56
-         %58 = OpCompositeExtract %float %params 3
-         %59 = OpFMul %float %58 %48
-         %60 = OpFSub %float %57 %59
-         %61 = OpFMul %float %float_1_16400003 %37
-         %62 = OpCompositeExtract %float %params 4
-         %63 = OpFMul %float %62 %47
-         %64 = OpFAdd %float %61 %63
-         %66 = OpCompositeConstruct %v4float %53 %60 %64 %float_1
-               OpReturnValue %66
+         %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
                OpFunctionEnd
-%textureLoad2d = OpFunction %v4float None %67
+%textureLoad2d = OpFunction %v4float None %57
     %texture = OpFunctionParameter %11
 %ext_tex_plane_1_1 = OpFunctionParameter %11
 %ext_tex_params_1 = OpFunctionParameter %ExternalTextureParams
      %coords = OpFunctionParameter %v2int
-         %73 = OpLabel
-         %74 = OpFunctionCall %v4float %textureLoadExternal %texture %ext_tex_plane_1_1 %coords %ext_tex_params_1
-               OpReturnValue %74
+         %63 = OpLabel
+         %64 = OpFunctionCall %v4float %textureLoadExternal %texture %ext_tex_plane_1_1 %coords %ext_tex_params_1
+               OpReturnValue %64
                OpFunctionEnd
-%doTextureLoad = OpFunction %void None %75
-         %78 = OpLabel
+%doTextureLoad = OpFunction %void None %65
+         %68 = OpLabel
         %res = OpVariable %_ptr_Function_v4float Function %5
-         %80 = OpLoad %11 %arg_0
-         %81 = OpLoad %11 %ext_tex_plane_1
-         %82 = OpLoad %ExternalTextureParams %ext_tex_params
-         %79 = OpFunctionCall %v4float %textureLoad2d %80 %81 %82 %83
-               OpStore %res %79
+         %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
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %86
-         %88 = OpLabel
-         %89 = OpFunctionCall %void %doTextureLoad
+%vertex_main_inner = OpFunction %v4float None %76
+         %78 = OpLabel
+         %79 = OpFunctionCall %void %doTextureLoad
                OpReturnValue %5
                OpFunctionEnd
-%vertex_main = OpFunction %void None %75
-         %91 = OpLabel
-         %92 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %92
+%vertex_main = OpFunction %void None %65
+         %81 = OpLabel
+         %82 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %82
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
-%fragment_main = OpFunction %void None %75
-         %94 = OpLabel
-         %95 = OpFunctionCall %void %doTextureLoad
+%fragment_main = OpFunction %void None %65
+         %84 = OpLabel
+         %85 = OpFunctionCall %void %doTextureLoad
                OpReturn
                OpFunctionEnd
-%compute_main = OpFunction %void None %75
-         %97 = OpLabel
-         %98 = OpFunctionCall %void %doTextureLoad
+%compute_main = OpFunction %void None %65
+         %87 = OpLabel
+         %88 = OpFunctionCall %void %doTextureLoad
                OpReturn
                OpFunctionEnd