Make textureDimensions(texture_external) use the visible size.

Previously it was using the size of plane0, which was incorrect when the
plane was cropped or for some rotations. Adds a test that checks that
the correct size is returned.

Also fixes the computation of the visibleSize in ExternalTexture to
account for the rotation.

Fixed: 341216488
Change-Id: If81ebb83f044795b641e888491f2f8603b38be0a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/188802
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/ExternalTexture.cpp b/src/dawn/native/ExternalTexture.cpp
index 5ebe350..7249bc5 100644
--- a/src/dawn/native/ExternalTexture.cpp
+++ b/src/dawn/native/ExternalTexture.cpp
@@ -304,6 +304,7 @@
         case wgpu::ExternalTextureRotation::Rotate0Degrees:
             break;
         case wgpu::ExternalTextureRotation::Rotate90Degrees:
+            std::swap(loadBounds[0], loadBounds[1]);
             sampleTransform = Mul(mat2x3{0, +1, 0,   // x' = y
                                          -1, 0, 0},  // y' = -x
                                   sampleTransform);
@@ -314,7 +315,7 @@
                                   sampleTransform);
             break;
         case wgpu::ExternalTextureRotation::Rotate270Degrees:
-
+            std::swap(loadBounds[0], loadBounds[1]);
             sampleTransform = Mul(mat2x3{0, -1, 0,   // x' = -y
                                          +1, 0, 0},  // y' = x
                                   sampleTransform);
diff --git a/src/dawn/tests/end2end/ExternalTextureTests.cpp b/src/dawn/tests/end2end/ExternalTextureTests.cpp
index b43c05a..37fcbda 100644
--- a/src/dawn/tests/end2end/ExternalTextureTests.cpp
+++ b/src/dawn/tests/end2end/ExternalTextureTests.cpp
@@ -692,6 +692,115 @@
     }
 }
 
+// Test for a bug found during review where the visibleSize was not correctly rotated during the
+// initialization of the ExternalTexture, which could lead to incorrect textureLoad operations when
+// rotating 90 and 270 degrees.
+TEST_P(ExternalTextureTests, RotateAndOrFlipTextureLoadSinglePlaneNotSquare) {
+    // TODO(crbug.com/dawn/2295): diagnose this failure on Pixel 4 OpenGLES
+    DAWN_SUPPRESS_TEST_IF(IsOpenGLES() && IsAndroid() && IsQualcomm());
+
+    wgpu::Texture sourceTexture =
+        Create2DTexture(device, 2, 16, kFormat,
+                        wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment);
+    RenderQuad(sourceTexture,
+               {kGreen.rgbaFloats, kBlack.rgbaFloats, kRed.rgbaFloats, kBlue.rgbaFloats});
+
+    wgpu::Texture renderTexture = Create2DTexture(
+        device, 2, 2, kFormat, wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
+
+    struct RotationExpectation {
+        wgpu::ExternalTextureRotation rotation;
+        bool mirrored;
+        utils::RGBA8 upperLeftColor;
+        utils::RGBA8 upperRightColor;
+        utils::RGBA8 lowerLeftColor;
+        utils::RGBA8 lowerRightColor;
+    };
+    std::array<RotationExpectation, 8> expectations = {
+        {{wgpu::ExternalTextureRotation::Rotate0Degrees, false, utils::RGBA8::kGreen,
+          utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kBlue},
+         {wgpu::ExternalTextureRotation::Rotate90Degrees, false, utils::RGBA8::kRed,
+          utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlack},
+         {wgpu::ExternalTextureRotation::Rotate180Degrees, false, utils::RGBA8::kBlue,
+          utils::RGBA8::kRed, utils::RGBA8::kBlack, utils::RGBA8::kGreen},
+         {wgpu::ExternalTextureRotation::Rotate270Degrees, false, utils::RGBA8::kBlack,
+          utils::RGBA8::kBlue, utils::RGBA8::kGreen, utils::RGBA8::kRed},
+         {wgpu::ExternalTextureRotation::Rotate0Degrees, true, utils::RGBA8::kBlack,
+          utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kRed},
+         {wgpu::ExternalTextureRotation::Rotate90Degrees, true, utils::RGBA8::kGreen,
+          utils::RGBA8::kRed, utils::RGBA8::kBlack, utils::RGBA8::kBlue},
+         {wgpu::ExternalTextureRotation::Rotate180Degrees, true, utils::RGBA8::kRed,
+          utils::RGBA8::kBlue, utils::RGBA8::kGreen, utils::RGBA8::kBlack},
+         {wgpu::ExternalTextureRotation::Rotate270Degrees, true, utils::RGBA8::kBlue,
+          utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kGreen}}};
+
+    wgpu::ShaderModule loadModule = utils::CreateShaderModule(device, R"(
+        @group(0) @binding(0) var<storage, read_write> dimension : vec2u;
+        @group(0) @binding(1) var t : texture_external;
+
+        @fragment fn main(@builtin(position) FragCoord : vec4f)
+                                 -> @location(0) vec4f {
+            dimension = textureDimensions(t);
+
+            var coords = textureDimensions(t) / 2 + vec2u(FragCoord.xy) - vec2(1, 1);
+            return textureLoad(t, coords);
+        })");
+
+    wgpu::BufferDescriptor dimensionBufferDesc;
+    dimensionBufferDesc.size = 8;
+    dimensionBufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
+    wgpu::Buffer dimensionBuffer = device.CreateBuffer(&dimensionBufferDesc);
+
+    for (const RotationExpectation& exp : expectations) {
+        // Pipeline Creation
+        utils::ComboRenderPipelineDescriptor descriptor;
+        descriptor.vertex.module = vsModule;
+        descriptor.cFragment.module = loadModule;
+        descriptor.cTargets[0].format = kFormat;
+        wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
+
+        // Create an ExternalTextureDescriptor from the texture view
+        wgpu::ExternalTextureDescriptor externalDesc =
+            InitExternalTextureDescriptor(sourceTexture.CreateView());
+        externalDesc.rotation = exp.rotation;
+        externalDesc.mirrored = exp.mirrored;
+        externalDesc.visibleOrigin = {0, 0};
+        externalDesc.visibleSize = {sourceTexture.GetWidth(), sourceTexture.GetHeight()};
+
+        // Import the external texture and make the bindgroup.
+        wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
+        wgpu::BindGroup bindGroup = utils::MakeBindGroup(
+            device, pipeline.GetBindGroupLayout(0), {{1, externalTexture}, {0, dimensionBuffer}});
+
+        // Run the shader, which should sample from the external texture and draw a triangle into
+        // the upper left corner of the render texture.
+        utils::ComboRenderPassDescriptor renderPass({renderTexture.CreateView()});
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+        pass.SetPipeline(pipeline);
+        pass.SetBindGroup(0, bindGroup);
+        pass.Draw(6);
+        pass.End();
+
+        wgpu::CommandBuffer commands = encoder.Finish();
+        queue.Submit(1, &commands);
+
+        EXPECT_PIXEL_RGBA8_EQ(exp.upperLeftColor, renderTexture, 0, 0);
+        EXPECT_PIXEL_RGBA8_EQ(exp.upperRightColor, renderTexture, 1, 0);
+        EXPECT_PIXEL_RGBA8_EQ(exp.lowerLeftColor, renderTexture, 0, 1);
+        EXPECT_PIXEL_RGBA8_EQ(exp.lowerRightColor, renderTexture, 1, 1);
+
+        if (exp.rotation == wgpu::ExternalTextureRotation::Rotate90Degrees ||
+            exp.rotation == wgpu::ExternalTextureRotation::Rotate270Degrees) {
+            EXPECT_BUFFER_U32_EQ(sourceTexture.GetHeight(), dimensionBuffer, 0);
+            EXPECT_BUFFER_U32_EQ(sourceTexture.GetWidth(), dimensionBuffer, 4);
+        } else {
+            EXPECT_BUFFER_U32_EQ(sourceTexture.GetWidth(), dimensionBuffer, 0);
+            EXPECT_BUFFER_U32_EQ(sourceTexture.GetHeight(), dimensionBuffer, 4);
+        }
+    }
+}
+
 // Test draws a green square in the upper left quadrant, a black square in the upper right, a red
 // square in the lower left and a blue square in the lower right. The image is then sampled as an
 // external texture and rotated 0, 90, 180, and 270 degrees with and without the y-axis flipped.
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
index 8637697..4a0de1f 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
@@ -228,8 +228,14 @@
                 },
                 [&](CoreBuiltinCall* call) {
                     if (call->Func() == core::BuiltinFn::kTextureDimensions) {
-                        // Use the first plane for the `textureDimensions()` call.
-                        call->SetOperand(use.operand_index, plane_0);
+                        // Use params.visibleSize + vec2u(1, 1) instead of the textureDimensions.
+                        b.InsertBefore(call, [&] {
+                            auto* visible_size = b.Access<vec2<u32>>(params, 12_u);
+                            auto* vec2u_1_1 = b.Splat<vec2<u32>>(1_u);
+                            auto* dimensions = b.Add<vec2<u32>>(visible_size, vec2u_1_1);
+                            dimensions->SetResults(Vector{call->DetachResult()});
+                        });
+                        call->Destroy();
                     } else if (call->Func() == core::BuiltinFn::kTextureLoad) {
                         // Convert the coordinates to unsigned integers if necessary.
                         auto* coords = call->Args()[1];
@@ -410,11 +416,10 @@
             auto* yuv_to_rgb_conversion_only = b.Access(ty.u32(), params, 1_u);
             auto* yuv_to_rgb_conversion = b.Access(ty.mat3x4<f32>(), params, 2_u);
             auto* load_transform_matrix = b.Access(ty.mat3x2<f32>(), params, 7_u);
-            auto* display_visible_rect_max = b.Access(ty.vec2<u32>(), params, 12_u);
+            auto* visible_size = b.Access(ty.vec2<u32>(), params, 12_u);
             auto* plane1_coord_factor = b.Access(ty.vec2<f32>(), params, 13_u);
 
-            auto* clamped_coords =
-                b.Call(vec2u, core::BuiltinFn::kMin, coords, display_visible_rect_max);
+            auto* clamped_coords = b.Call(vec2u, core::BuiltinFn::kMin, coords, visible_size);
             auto* clamped_coords_f = b.Convert(vec2f, clamped_coords);
             auto* modified_coords =
                 b.Multiply(vec2f, load_transform_matrix, b.Construct(vec3f, clamped_coords_f, 1_f));
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
index 39b06e8..c8dc646 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
@@ -270,7 +270,8 @@
     %5:texture_2d<f32> = load %texture_plane0
     %6:texture_2d<f32> = load %texture_plane1
     %7:tint_ExternalTextureParams = load %texture_params
-    %result:vec2<u32> = textureDimensions %5
+    %8:vec2<u32> = access %7, 12u
+    %result:vec2<u32> = add %8, vec2<u32>(1u)
     ret %result
   }
 }
@@ -1071,99 +1072,100 @@
     %15:texture_2d<f32> = load %texture_plane0
     %16:texture_2d<f32> = load %texture_plane1
     %17:tint_ExternalTextureParams = load %texture_params
-    %18:vec2<u32> = textureDimensions %15
-    %19:texture_2d<f32> = load %texture_plane0
-    %20:texture_2d<f32> = load %texture_plane1
-    %21:tint_ExternalTextureParams = load %texture_params
-    %22:vec4<f32> = call %tint_TextureSampleExternal, %19, %20, %21, %sampler_1, %coords_1
-    %23:texture_2d<f32> = load %texture_plane0
-    %24:texture_2d<f32> = load %texture_plane1
-    %25:tint_ExternalTextureParams = load %texture_params
-    %26:vec4<f32> = call %tint_TextureSampleExternal, %23, %24, %25, %sampler_1, %coords_1
-    %27:texture_2d<f32> = load %texture_plane0
-    %28:texture_2d<f32> = load %texture_plane1
-    %29:tint_ExternalTextureParams = load %texture_params
-    %result_a:vec4<f32> = call %foo, %27, %28, %29, %sampler_1, %coords_1
-    %result_b:vec4<f32> = call %foo, %27, %28, %29, %sampler_1, %coords_1
-    %32:vec4<f32> = add %result_a, %result_b
-    ret %32
+    %18:vec2<u32> = access %17, 12u
+    %19:vec2<u32> = add %18, vec2<u32>(1u)
+    %20:texture_2d<f32> = load %texture_plane0
+    %21:texture_2d<f32> = load %texture_plane1
+    %22:tint_ExternalTextureParams = load %texture_params
+    %23:vec4<f32> = call %tint_TextureSampleExternal, %20, %21, %22, %sampler_1, %coords_1
+    %24:texture_2d<f32> = load %texture_plane0
+    %25:texture_2d<f32> = load %texture_plane1
+    %26:tint_ExternalTextureParams = load %texture_params
+    %27:vec4<f32> = call %tint_TextureSampleExternal, %24, %25, %26, %sampler_1, %coords_1
+    %28:texture_2d<f32> = load %texture_plane0
+    %29:texture_2d<f32> = load %texture_plane1
+    %30:tint_ExternalTextureParams = load %texture_params
+    %result_a:vec4<f32> = call %foo, %28, %29, %30, %sampler_1, %coords_1
+    %result_b:vec4<f32> = call %foo, %28, %29, %30, %sampler_1, %coords_1
+    %33:vec4<f32> = add %result_a, %result_b
+    ret %33
   }
 }
 %tint_TextureSampleExternal = func(%plane_0:texture_2d<f32>, %plane_1:texture_2d<f32>, %params:tint_ExternalTextureParams, %sampler_2:sampler, %coords_2:vec2<f32>):vec4<f32> {  # %sampler_2: 'sampler', %coords_2: 'coords'
   $B4: {
-    %38:u32 = access %params, 1u
-    %39:mat3x4<f32> = access %params, 2u
-    %40:mat3x2<f32> = access %params, 6u
-    %41:vec2<f32> = access %params, 8u
-    %42:vec2<f32> = access %params, 9u
-    %43:vec2<f32> = access %params, 10u
-    %44:vec2<f32> = access %params, 11u
-    %45:vec3<f32> = construct %coords_2, 1.0f
-    %46:vec2<f32> = mul %40, %45
-    %47:vec2<f32> = clamp %46, %41, %42
-    %48:u32 = access %params, 0u
-    %49:bool = eq %48, 1u
-    %50:vec3<f32>, %51:f32 = if %49 [t: $B5, f: $B6] {  # if_1
+    %39:u32 = access %params, 1u
+    %40:mat3x4<f32> = access %params, 2u
+    %41:mat3x2<f32> = access %params, 6u
+    %42:vec2<f32> = access %params, 8u
+    %43:vec2<f32> = access %params, 9u
+    %44:vec2<f32> = access %params, 10u
+    %45:vec2<f32> = access %params, 11u
+    %46:vec3<f32> = construct %coords_2, 1.0f
+    %47:vec2<f32> = mul %41, %46
+    %48:vec2<f32> = clamp %47, %42, %43
+    %49:u32 = access %params, 0u
+    %50:bool = eq %49, 1u
+    %51:vec3<f32>, %52:f32 = if %50 [t: $B5, f: $B6] {  # if_1
       $B5: {  # true
-        %52:vec4<f32> = textureSampleLevel %plane_0, %sampler_2, %47, 0.0f
-        %53:vec3<f32> = swizzle %52, xyz
-        %54:f32 = access %52, 3u
-        exit_if %53, %54  # if_1
+        %53:vec4<f32> = textureSampleLevel %plane_0, %sampler_2, %48, 0.0f
+        %54:vec3<f32> = swizzle %53, xyz
+        %55:f32 = access %53, 3u
+        exit_if %54, %55  # if_1
       }
       $B6: {  # false
-        %55:vec4<f32> = textureSampleLevel %plane_0, %sampler_2, %47, 0.0f
-        %56:f32 = access %55, 0u
-        %57:vec2<f32> = clamp %46, %43, %44
-        %58:vec4<f32> = textureSampleLevel %plane_1, %sampler_2, %57, 0.0f
-        %59:vec2<f32> = swizzle %58, xy
-        %60:vec4<f32> = construct %56, %59, 1.0f
-        %61:vec3<f32> = mul %60, %39
-        exit_if %61, 1.0f  # if_1
+        %56:vec4<f32> = textureSampleLevel %plane_0, %sampler_2, %48, 0.0f
+        %57:f32 = access %56, 0u
+        %58:vec2<f32> = clamp %47, %44, %45
+        %59:vec4<f32> = textureSampleLevel %plane_1, %sampler_2, %58, 0.0f
+        %60:vec2<f32> = swizzle %59, xy
+        %61:vec4<f32> = construct %57, %60, 1.0f
+        %62:vec3<f32> = mul %61, %40
+        exit_if %62, 1.0f  # if_1
       }
     }
-    %62:bool = eq %38, 0u
-    %63:vec3<f32> = if %62 [t: $B7, f: $B8] {  # if_2
+    %63:bool = eq %39, 0u
+    %64:vec3<f32> = if %63 [t: $B7, f: $B8] {  # if_2
       $B7: {  # true
-        %64:tint_GammaTransferParams = access %params, 3u
-        %65:tint_GammaTransferParams = access %params, 4u
-        %66:mat3x3<f32> = access %params, 5u
-        %67:vec3<f32> = call %tint_GammaCorrection, %50, %64
-        %69:vec3<f32> = mul %66, %67
-        %70:vec3<f32> = call %tint_GammaCorrection, %69, %65
-        exit_if %70  # if_2
+        %65:tint_GammaTransferParams = access %params, 3u
+        %66:tint_GammaTransferParams = access %params, 4u
+        %67:mat3x3<f32> = access %params, 5u
+        %68:vec3<f32> = call %tint_GammaCorrection, %51, %65
+        %70:vec3<f32> = mul %67, %68
+        %71:vec3<f32> = call %tint_GammaCorrection, %70, %66
+        exit_if %71  # if_2
       }
       $B8: {  # false
-        exit_if %50  # if_2
+        exit_if %51  # if_2
       }
     }
-    %71:vec4<f32> = construct %63, %51
-    ret %71
+    %72:vec4<f32> = construct %64, %52
+    ret %72
   }
 }
 %tint_GammaCorrection = func(%v:vec3<f32>, %params_1:tint_GammaTransferParams):vec3<f32> {  # %params_1: 'params'
   $B9: {
-    %74:f32 = access %params_1, 0u
-    %75:f32 = access %params_1, 1u
-    %76:f32 = access %params_1, 2u
-    %77:f32 = access %params_1, 3u
-    %78:f32 = access %params_1, 4u
-    %79:f32 = access %params_1, 5u
-    %80:f32 = access %params_1, 6u
-    %81:vec3<f32> = construct %74
-    %82:vec3<f32> = construct %78
-    %83:vec3<f32> = abs %v
-    %84:vec3<f32> = sign %v
-    %85:vec3<bool> = lt %83, %82
-    %86:vec3<f32> = mul %77, %83
-    %87:vec3<f32> = add %86, %80
-    %88:vec3<f32> = mul %84, %87
-    %89:vec3<f32> = mul %75, %83
-    %90:vec3<f32> = add %89, %76
-    %91:vec3<f32> = pow %90, %81
-    %92:vec3<f32> = add %91, %79
-    %93:vec3<f32> = mul %84, %92
-    %94:vec3<f32> = select %93, %88, %85
-    ret %94
+    %75:f32 = access %params_1, 0u
+    %76:f32 = access %params_1, 1u
+    %77:f32 = access %params_1, 2u
+    %78:f32 = access %params_1, 3u
+    %79:f32 = access %params_1, 4u
+    %80:f32 = access %params_1, 5u
+    %81:f32 = access %params_1, 6u
+    %82:vec3<f32> = construct %75
+    %83:vec3<f32> = construct %79
+    %84:vec3<f32> = abs %v
+    %85:vec3<f32> = sign %v
+    %86:vec3<bool> = lt %84, %83
+    %87:vec3<f32> = mul %78, %84
+    %88:vec3<f32> = add %87, %81
+    %89:vec3<f32> = mul %85, %88
+    %90:vec3<f32> = mul %76, %84
+    %91:vec3<f32> = add %90, %77
+    %92:vec3<f32> = pow %91, %82
+    %93:vec3<f32> = add %92, %80
+    %94:vec3<f32> = mul %85, %93
+    %95:vec3<f32> = select %94, %89, %86
+    ret %95
   }
 }
 )";
diff --git a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
index 0b59b7d..c9b1313 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
@@ -221,13 +221,12 @@
 
         // Transform the external texture builtin calls into calls to the external texture
         // functions.
-        ctx.ReplaceAll([&](const CallExpression* expr) -> const CallExpression* {
+        ctx.ReplaceAll([&](const CallExpression* expr) -> const Expression* {
             auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>();
             auto* builtin = call->Target()->As<sem::BuiltinFn>();
 
             if (builtin && !builtin->Parameters().IsEmpty() &&
-                builtin->Parameters()[0]->Type()->Is<core::type::ExternalTexture>() &&
-                builtin->Fn() != wgsl::BuiltinFn::kTextureDimensions) {
+                builtin->Parameters()[0]->Type()->Is<core::type::ExternalTexture>()) {
                 if (auto* var_user =
                         sem.GetVal(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
                     auto it = new_binding_symbols.find(var_user->Variable());
@@ -245,6 +244,8 @@
                             return createTextureLoad(call, syms);
                         case wgsl::BuiltinFn::kTextureSampleBaseClampToEdge:
                             return createTextureSampleBaseClampToEdge(expr, syms);
+                        case wgsl::BuiltinFn::kTextureDimensions:
+                            return createTextureDimensions(call, syms);
                         default:
                             break;
                     }
@@ -553,6 +554,19 @@
         return b.Call(texture_load_external_sym, plane_0_binding_arg, syms.plane_1,
                       ctx.Clone(args[1]->Declaration()), syms.params);
     }
+
+    /// Returns the expression used to replace a textureDimensions call.
+    /// @param call the call expression being transformed
+    /// @param syms the expanded symbols to be used in the new call
+    /// @returns a load of params.visibleSize
+    const Expression* createTextureDimensions(const sem::Call* call, NewBindingSymbols syms) {
+        if (TINT_UNLIKELY(call->Arguments().Length() != 1)) {
+            TINT_ICE() << "expected textureDimensions call with a texture_external to have 1 "
+                          "arguments, found "
+                       << call->Arguments().Length() << " arguments";
+        }
+        return b.Add(b.MemberAccessor(syms.params, "visibleSize"), b.Call<vec2<u32>>(1_a));
+    }
 };
 
 MultiplanarExternalTexture::NewBindingPoints::NewBindingPoints() = default;
diff --git a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture_test.cc b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture_test.cc
index 65c7b41..a16eb09 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture_test.cc
@@ -171,7 +171,7 @@
 @fragment
 fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
   var dim : vec2<u32>;
-  dim = textureDimensions(ext_tex);
+  dim = (ext_tex_params.visibleSize + vec2<u32>(1));
   return vec4<f32>(0.0, 0.0, 0.0, 0.0);
 }
 )";
@@ -318,7 +318,7 @@
 @fragment
 fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
   var dim : vec2<u32>;
-  dim = textureDimensions(ext_tex);
+  dim = (ext_tex_params.visibleSize + vec2<u32>(1));
   return vec4<f32>(0.0, 0.0, 0.0, 0.0);
 }
 
@@ -1791,7 +1791,7 @@
 }
 
 fn f(ext_tex : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams) -> vec2<u32> {
-  return textureDimensions(ext_tex);
+  return (ext_tex_params.visibleSize + vec2<u32>(1));
 }
 )";
 
diff --git a/test/tint/bug/tint/1739.wgsl.expected.glsl b/test/tint/bug/tint/1739.wgsl.expected.glsl
index 1ebb2f4..2140d8a 100644
--- a/test/tint/bug/tint/1739.wgsl.expected.glsl
+++ b/test/tint/bug/tint/1739.wgsl.expected.glsl
@@ -103,9 +103,9 @@
 }
 
 void tint_symbol() {
-  vec4 red = textureLoadExternal(t_1, ext_tex_plane_1_1, clamp(ivec2(10), ivec2(0), ivec2((uvec2(textureSize(t_1, 0)) - uvec2(1u)))), conv_ExternalTextureParams(ext_tex_params.inner));
+  vec4 red = textureLoadExternal(t_1, ext_tex_plane_1_1, clamp(ivec2(10), ivec2(0), ivec2(((ext_tex_params.inner.visibleSize + uvec2(1u)) - uvec2(1u)))), conv_ExternalTextureParams(ext_tex_params.inner));
   imageStore(outImage, clamp(ivec2(0), ivec2(0), ivec2((uvec2(imageSize(outImage)) - uvec2(1u)))), red);
-  vec4 green = textureLoadExternal(t_1, ext_tex_plane_1_1, clamp(ivec2(70, 118), ivec2(0), ivec2((uvec2(textureSize(t_1, 0)) - uvec2(1u)))), conv_ExternalTextureParams(ext_tex_params.inner));
+  vec4 green = textureLoadExternal(t_1, ext_tex_plane_1_1, clamp(ivec2(70, 118), ivec2(0), ivec2(((ext_tex_params.inner.visibleSize + uvec2(1u)) - uvec2(1u)))), conv_ExternalTextureParams(ext_tex_params.inner));
   imageStore(outImage, clamp(ivec2(1, 0), ivec2(0), ivec2((uvec2(imageSize(outImage)) - uvec2(1u)))), green);
   return;
 }
diff --git a/test/tint/bug/tint/1739.wgsl.expected.msl b/test/tint/bug/tint/1739.wgsl.expected.msl
index 115be5c..fec25f8 100644
--- a/test/tint/bug/tint/1739.wgsl.expected.msl
+++ b/test/tint/bug/tint/1739.wgsl.expected.msl
@@ -123,9 +123,9 @@
 }
 
 kernel void tint_symbol(texture2d<float, access::sample> tint_symbol_1 [[texture(1)]], texture2d<float, access::sample> tint_symbol_2 [[texture(2)]], const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_3 [[buffer(3)]], texture2d<float, access::write> tint_symbol_4 [[texture(0)]]) {
-  float4 red = textureLoadExternal(tint_symbol_1, tint_symbol_2, tint_clamp(int2(10), int2(0), int2((uint2(tint_symbol_1.get_width(), tint_symbol_1.get_height()) - uint2(1u)))), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
+  float4 red = textureLoadExternal(tint_symbol_1, tint_symbol_2, tint_clamp(int2(10), int2(0), int2((((*(tint_symbol_3)).visibleSize + uint2(1u)) - uint2(1u)))), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
   tint_symbol_4.write(red, uint2(tint_clamp(int2(0), int2(0), int2((uint2(tint_symbol_4.get_width(), tint_symbol_4.get_height()) - uint2(1u))))));
-  float4 green = textureLoadExternal(tint_symbol_1, tint_symbol_2, tint_clamp(int2(70, 118), int2(0), int2((uint2(tint_symbol_1.get_width(), tint_symbol_1.get_height()) - uint2(1u)))), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
+  float4 green = textureLoadExternal(tint_symbol_1, tint_symbol_2, tint_clamp(int2(70, 118), int2(0), int2((((*(tint_symbol_3)).visibleSize + uint2(1u)) - uint2(1u)))), tint_unpack_vec3_in_composite_1(*(tint_symbol_3)));
   tint_symbol_4.write(green, uint2(tint_clamp(int2(1, 0), int2(0), int2((uint2(tint_symbol_4.get_width(), tint_symbol_4.get_height()) - uint2(1u))))));
   return;
 }
diff --git a/test/tint/bug/tint/1739.wgsl.expected.spvasm b/test/tint/bug/tint/1739.wgsl.expected.spvasm
index baa7ad9..38b33c8 100644
--- a/test/tint/bug/tint/1739.wgsl.expected.spvasm
+++ b/test/tint/bug/tint/1739.wgsl.expected.spvasm
@@ -1,7 +1,7 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 256
+; Bound: 259
 ; Schema: 0
                OpCapability Shader
                OpCapability ImageQuery
@@ -195,15 +195,16 @@
      %int_10 = OpConstant %int 10
         %209 = OpConstantComposite %v2int %int_10 %int_10
         %210 = OpConstantNull %v2int
-      %int_0 = OpConstant %int 0
-        %215 = OpConstantComposite %v2uint %uint_1 %uint_1
      %uint_0 = OpConstant %uint 0
+    %uint_16 = OpConstant %uint 16
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+        %217 = OpConstantComposite %v2uint %uint_1 %uint_1
 %_ptr_Uniform_ExternalTextureParams_std140 = OpTypePointer Uniform %ExternalTextureParams_std140
      %int_70 = OpConstant %int 70
     %int_118 = OpConstant %int 118
-        %237 = OpConstantComposite %v2int %int_70 %int_118
+        %239 = OpConstantComposite %v2int %int_70 %int_118
       %int_1 = OpConstant %int 1
-        %250 = OpConstantComposite %v2int %int_1 %118
+        %253 = OpConstantComposite %v2int %int_1 %118
   %tint_ftou = OpFunction %v2uint None %21
           %v = OpFunctionParameter %v2float
          %24 = OpLabel
@@ -382,43 +383,45 @@
       %green = OpVariable %_ptr_Function_v4float Function %110
         %205 = OpLoad %3 %t
         %206 = OpLoad %3 %ext_tex_plane_1
-        %213 = OpLoad %3 %t
-        %212 = OpImageQuerySizeLod %v2uint %213 %int_0
-        %216 = OpISub %v2uint %212 %215
-        %211 = OpBitcast %v2int %216
+        %215 = OpAccessChain %_ptr_Uniform_v2uint %ext_tex_params %uint_0 %uint_16
+        %216 = OpLoad %v2uint %215
+        %218 = OpIAdd %v2uint %216 %217
+        %219 = OpISub %v2uint %218 %217
+        %211 = OpBitcast %v2int %219
         %207 = OpFunctionCall %v2int %tint_clamp %209 %210 %211
-        %220 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
-        %221 = OpLoad %ExternalTextureParams_std140 %220
-        %217 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %221
-        %204 = OpFunctionCall %v4float %textureLoadExternal %205 %206 %207 %217
+        %222 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
+        %223 = OpLoad %ExternalTextureParams_std140 %222
+        %220 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %223
+        %204 = OpFunctionCall %v4float %textureLoadExternal %205 %206 %207 %220
                OpStore %red %204
-        %224 = OpLoad %20 %outImage
-        %228 = OpLoad %20 %outImage
-        %227 = OpImageQuerySize %v2uint %228
-        %229 = OpISub %v2uint %227 %215
-        %226 = OpBitcast %v2int %229
-        %225 = OpFunctionCall %v2int %tint_clamp %210 %210 %226
-        %230 = OpLoad %v4float %red
-               OpImageWrite %224 %225 %230
-        %232 = OpLoad %3 %t
-        %233 = OpLoad %3 %ext_tex_plane_1
-        %240 = OpLoad %3 %t
-        %239 = OpImageQuerySizeLod %v2uint %240 %int_0
-        %241 = OpISub %v2uint %239 %215
-        %238 = OpBitcast %v2int %241
-        %234 = OpFunctionCall %v2int %tint_clamp %237 %210 %238
-        %243 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
-        %244 = OpLoad %ExternalTextureParams_std140 %243
-        %242 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %244
-        %231 = OpFunctionCall %v4float %textureLoadExternal %232 %233 %234 %242
-               OpStore %green %231
-        %247 = OpLoad %20 %outImage
-        %253 = OpLoad %20 %outImage
-        %252 = OpImageQuerySize %v2uint %253
-        %254 = OpISub %v2uint %252 %215
-        %251 = OpBitcast %v2int %254
-        %248 = OpFunctionCall %v2int %tint_clamp %250 %210 %251
-        %255 = OpLoad %v4float %green
-               OpImageWrite %247 %248 %255
+        %226 = OpLoad %20 %outImage
+        %230 = OpLoad %20 %outImage
+        %229 = OpImageQuerySize %v2uint %230
+        %231 = OpISub %v2uint %229 %217
+        %228 = OpBitcast %v2int %231
+        %227 = OpFunctionCall %v2int %tint_clamp %210 %210 %228
+        %232 = OpLoad %v4float %red
+               OpImageWrite %226 %227 %232
+        %234 = OpLoad %3 %t
+        %235 = OpLoad %3 %ext_tex_plane_1
+        %241 = OpAccessChain %_ptr_Uniform_v2uint %ext_tex_params %uint_0 %uint_16
+        %242 = OpLoad %v2uint %241
+        %243 = OpIAdd %v2uint %242 %217
+        %244 = OpISub %v2uint %243 %217
+        %240 = OpBitcast %v2int %244
+        %236 = OpFunctionCall %v2int %tint_clamp %239 %210 %240
+        %246 = OpAccessChain %_ptr_Uniform_ExternalTextureParams_std140 %ext_tex_params %uint_0
+        %247 = OpLoad %ExternalTextureParams_std140 %246
+        %245 = OpFunctionCall %ExternalTextureParams %conv_ExternalTextureParams %247
+        %233 = OpFunctionCall %v4float %textureLoadExternal %234 %235 %236 %245
+               OpStore %green %233
+        %250 = OpLoad %20 %outImage
+        %256 = OpLoad %20 %outImage
+        %255 = OpImageQuerySize %v2uint %256
+        %257 = OpISub %v2uint %255 %217
+        %254 = OpBitcast %v2int %257
+        %251 = OpFunctionCall %v2int %tint_clamp %253 %210 %254
+        %258 = OpLoad %v4float %green
+               OpImageWrite %250 %251 %258
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/bug/tint/2076.wgsl.expected.ir.glsl b/test/tint/bug/tint/2076.wgsl.expected.ir.glsl
index 1bc2599..31b48a0 100644
--- a/test/tint/bug/tint/2076.wgsl.expected.ir.glsl
+++ b/test/tint/bug/tint/2076.wgsl.expected.ir.glsl
@@ -24,13 +24,13 @@
   GammaTransferParams gammaDecodeParams;
   GammaTransferParams gammaEncodeParams;
   mat3 gamutConversionMatrix;
-  mat3x2 coordTransformationMatrix;
-  mat3x2 loadTransformationMatrix;
+  mat3x2 sampleTransform;
+  mat3x2 loadTransform;
   vec2 samplePlane0RectMin;
   vec2 samplePlane0RectMax;
   vec2 samplePlane1RectMin;
   vec2 samplePlane1RectMax;
-  uvec2 displayVisibleRectMax;
+  uvec2 visibleSize;
   vec2 plane1CoordFactor;
 };
 
@@ -43,17 +43,17 @@
   GammaTransferParams gammaDecodeParams;
   GammaTransferParams gammaEncodeParams;
   mat3 gamutConversionMatrix;
-  vec2 coordTransformationMatrix_0;
-  vec2 coordTransformationMatrix_1;
-  vec2 coordTransformationMatrix_2;
-  vec2 loadTransformationMatrix_0;
-  vec2 loadTransformationMatrix_1;
-  vec2 loadTransformationMatrix_2;
+  vec2 sampleTransform_0;
+  vec2 sampleTransform_1;
+  vec2 sampleTransform_2;
+  vec2 loadTransform_0;
+  vec2 loadTransform_1;
+  vec2 loadTransform_2;
   vec2 samplePlane0RectMin;
   vec2 samplePlane0RectMax;
   vec2 samplePlane1RectMin;
   vec2 samplePlane1RectMax;
-  uvec2 displayVisibleRectMax;
+  uvec2 visibleSize;
   vec2 plane1CoordFactor;
 };
 
diff --git a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl
index c731548..b45ca2b 100644
--- a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl
@@ -3,12 +3,11 @@
   uint4 ext_tex_params[17];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
+
 RWByteAddressBuffer prevent_dce : register(u0, space2);
 
 void textureDimensions_cdc6c9() {
-  uint2 tint_tmp;
-  arg_0.GetDimensions(tint_tmp.x, tint_tmp.y);
-  uint2 res = tint_tmp;
+  uint2 res = (ext_tex_params[16].xy + (1u).xx);
   prevent_dce.Store2(0u, asuint(res));
 }
 
diff --git a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl
index c731548..b45ca2b 100644
--- a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl
@@ -3,12 +3,11 @@
   uint4 ext_tex_params[17];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
+
 RWByteAddressBuffer prevent_dce : register(u0, space2);
 
 void textureDimensions_cdc6c9() {
-  uint2 tint_tmp;
-  arg_0.GetDimensions(tint_tmp.x, tint_tmp.y);
-  uint2 res = tint_tmp;
+  uint2 res = (ext_tex_params[16].xy + (1u).xx);
   prevent_dce.Store2(0u, asuint(res));
 }
 
diff --git a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.glsl b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.glsl
index f4d92ca..95c24ec 100644
--- a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.glsl
@@ -57,13 +57,12 @@
   ExternalTextureParams_std140 inner;
 } ext_tex_params;
 
-uniform highp sampler2D arg_0_1;
 layout(binding = 0, std430) buffer prevent_dce_block_ssbo {
   uvec2 inner;
 } prevent_dce;
 
 void textureDimensions_cdc6c9() {
-  uvec2 res = uvec2(textureSize(arg_0_1, 0));
+  uvec2 res = (ext_tex_params.inner.visibleSize + uvec2(1u));
   prevent_dce.inner = res;
 }
 
@@ -141,13 +140,12 @@
   ExternalTextureParams_std140 inner;
 } ext_tex_params;
 
-uniform highp sampler2D arg_0_1;
 layout(binding = 0, std430) buffer prevent_dce_block_ssbo {
   uvec2 inner;
 } prevent_dce;
 
 void textureDimensions_cdc6c9() {
-  uvec2 res = uvec2(textureSize(arg_0_1, 0));
+  uvec2 res = (ext_tex_params.inner.visibleSize + uvec2(1u));
   prevent_dce.inner = res;
 }
 
@@ -218,13 +216,12 @@
   ExternalTextureParams_std140 inner;
 } ext_tex_params;
 
-uniform highp sampler2D arg_0_1;
 layout(binding = 0, std430) buffer prevent_dce_block_ssbo {
   uvec2 inner;
 } prevent_dce;
 
 void textureDimensions_cdc6c9() {
-  uvec2 res = uvec2(textureSize(arg_0_1, 0));
+  uvec2 res = (ext_tex_params.inner.visibleSize + uvec2(1u));
   prevent_dce.inner = res;
 }
 
diff --git a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.msl b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.msl
index 559bfb4..85ac3a3 100644
--- a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.msl
+++ b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.msl
@@ -15,35 +15,37 @@
 };
 
 struct tint_packed_vec3_f32_array_element {
-  packed_float3 elements;
+  /* 0x0000 */ packed_float3 elements;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
 };
 
 struct GammaTransferParams {
-  float G;
-  float A;
-  float B;
-  float C;
-  float D;
-  float E;
-  float F;
-  uint padding;
+  /* 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_tint_packed_vec3 {
-  uint numPlanes;
-  uint doYuvToRgbConversionOnly;
-  float3x4 yuvToRgbConversionMatrix;
-  GammaTransferParams gammaDecodeParams;
-  GammaTransferParams gammaEncodeParams;
-  tint_array<tint_packed_vec3_f32_array_element, 3> gamutConversionMatrix;
-  float3x2 sampleTransform;
-  float3x2 loadTransform;
-  float2 samplePlane0RectMin;
-  float2 samplePlane0RectMax;
-  float2 samplePlane1RectMin;
-  float2 samplePlane1RectMax;
-  uint2 visibleSize;
-  float2 plane1CoordFactor;
+  /* 0x0000 */ uint numPlanes;
+  /* 0x0004 */ uint doYuvToRgbConversionOnly;
+  /* 0x0008 */ tint_array<int8_t, 8> tint_pad_1;
+  /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
+  /* 0x0040 */ GammaTransferParams gammaDecodeParams;
+  /* 0x0060 */ GammaTransferParams gammaEncodeParams;
+  /* 0x0080 */ tint_array<tint_packed_vec3_f32_array_element, 3> gamutConversionMatrix;
+  /* 0x00b0 */ float3x2 sampleTransform;
+  /* 0x00c8 */ float3x2 loadTransform;
+  /* 0x00e0 */ float2 samplePlane0RectMin;
+  /* 0x00e8 */ float2 samplePlane0RectMax;
+  /* 0x00f0 */ float2 samplePlane1RectMin;
+  /* 0x00f8 */ float2 samplePlane1RectMax;
+  /* 0x0100 */ uint2 visibleSize;
+  /* 0x0108 */ float2 plane1CoordFactor;
 };
 
 struct ExternalTextureParams {
@@ -63,8 +65,8 @@
   float2 plane1CoordFactor;
 };
 
-void textureDimensions_cdc6c9(texture2d<float, access::sample> tint_symbol_1, device uint2* const tint_symbol_2) {
-  uint2 res = uint2(tint_symbol_1.get_width(), tint_symbol_1.get_height());
+void textureDimensions_cdc6c9(const constant ExternalTextureParams_tint_packed_vec3* const tint_symbol_1, device uint2* const tint_symbol_2) {
+  uint2 res = ((*(tint_symbol_1)).visibleSize + uint2(1u));
   *(tint_symbol_2) = res;
 }
 
@@ -72,24 +74,24 @@
   float4 value [[position]];
 };
 
-float4 vertex_main_inner(texture2d<float, access::sample> tint_symbol_3, device uint2* const tint_symbol_4) {
+float4 vertex_main_inner(const constant ExternalTextureParams_tint_packed_vec3* const tint_symbol_3, device uint2* const tint_symbol_4) {
   textureDimensions_cdc6c9(tint_symbol_3, tint_symbol_4);
   return float4(0.0f);
 }
 
-vertex tint_symbol vertex_main(texture2d<float, access::sample> tint_symbol_5 [[texture(0)]], device uint2* tint_symbol_6 [[buffer(0)]]) {
+vertex tint_symbol vertex_main(const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_5 [[buffer(2)]], device uint2* tint_symbol_6 [[buffer(0)]]) {
   float4 const inner_result = vertex_main_inner(tint_symbol_5, tint_symbol_6);
   tint_symbol wrapper_result = {};
   wrapper_result.value = inner_result;
   return wrapper_result;
 }
 
-fragment void fragment_main(texture2d<float, access::sample> tint_symbol_7 [[texture(0)]], device uint2* tint_symbol_8 [[buffer(0)]]) {
+fragment void fragment_main(const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_7 [[buffer(2)]], device uint2* tint_symbol_8 [[buffer(0)]]) {
   textureDimensions_cdc6c9(tint_symbol_7, tint_symbol_8);
   return;
 }
 
-kernel void compute_main(texture2d<float, access::sample> tint_symbol_9 [[texture(0)]], device uint2* tint_symbol_10 [[buffer(0)]]) {
+kernel void compute_main(const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_9 [[buffer(2)]], device uint2* tint_symbol_10 [[buffer(0)]]) {
   textureDimensions_cdc6c9(tint_symbol_9, tint_symbol_10);
   return;
 }
diff --git a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.spvasm b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.spvasm
index 9152ae6..3dc25d5 100644
--- a/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/literal/textureDimensions/cdc6c9.wgsl.expected.spvasm
@@ -1,10 +1,9 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 56
+; Bound: 59
 ; Schema: 0
                OpCapability Shader
-               OpCapability ImageQuery
                OpMemoryModel Logical GLSL450
                OpEntryPoint Vertex %vertex_main "vertex_main" %value %vertex_point_size
                OpEntryPoint Fragment %fragment_main "fragment_main"
@@ -128,44 +127,47 @@
 %prevent_dce = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
        %void = OpTypeVoid
          %27 = OpTypeFunction %void
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
-%_ptr_Function_v2uint = OpTypePointer Function %v2uint
-         %37 = OpConstantNull %v2uint
      %uint_0 = OpConstant %uint 0
+    %uint_16 = OpConstant %uint 16
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+     %uint_1 = OpConstant %uint 1
+         %37 = OpConstantComposite %v2uint %uint_1 %uint_1
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+         %41 = OpConstantNull %v2uint
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
-         %42 = OpTypeFunction %v4float
+         %45 = OpTypeFunction %v4float
     %float_1 = OpConstant %float 1
 %textureDimensions_cdc6c9 = OpFunction %void None %27
          %30 = OpLabel
-        %res = OpVariable %_ptr_Function_v2uint Function %37
-         %32 = OpLoad %11 %arg_0
-         %31 = OpImageQuerySizeLod %v2uint %32 %int_0
-               OpStore %res %31
-         %40 = OpAccessChain %_ptr_StorageBuffer_v2uint %prevent_dce %uint_0
-         %41 = OpLoad %v2uint %res
-               OpStore %40 %41
+        %res = OpVariable %_ptr_Function_v2uint Function %41
+         %34 = OpAccessChain %_ptr_Uniform_v2uint %ext_tex_params %uint_0 %uint_16
+         %35 = OpLoad %v2uint %34
+         %38 = OpIAdd %v2uint %35 %37
+               OpStore %res %38
+         %43 = OpAccessChain %_ptr_StorageBuffer_v2uint %prevent_dce %uint_0
+         %44 = OpLoad %v2uint %res
+               OpStore %43 %44
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %42
-         %44 = OpLabel
-         %45 = OpFunctionCall %void %textureDimensions_cdc6c9
+%vertex_main_inner = OpFunction %v4float None %45
+         %47 = OpLabel
+         %48 = OpFunctionCall %void %textureDimensions_cdc6c9
                OpReturnValue %5
                OpFunctionEnd
 %vertex_main = OpFunction %void None %27
-         %47 = OpLabel
-         %48 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %48
+         %50 = OpLabel
+         %51 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %51
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
 %fragment_main = OpFunction %void None %27
-         %51 = OpLabel
-         %52 = OpFunctionCall %void %textureDimensions_cdc6c9
+         %54 = OpLabel
+         %55 = OpFunctionCall %void %textureDimensions_cdc6c9
                OpReturn
                OpFunctionEnd
 %compute_main = OpFunction %void None %27
-         %54 = OpLabel
-         %55 = OpFunctionCall %void %textureDimensions_cdc6c9
+         %57 = OpLabel
+         %58 = OpFunctionCall %void %textureDimensions_cdc6c9
                OpReturn
                OpFunctionEnd
diff --git a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl
index c731548..b45ca2b 100644
--- a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.dxc.hlsl
@@ -3,12 +3,11 @@
   uint4 ext_tex_params[17];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
+
 RWByteAddressBuffer prevent_dce : register(u0, space2);
 
 void textureDimensions_cdc6c9() {
-  uint2 tint_tmp;
-  arg_0.GetDimensions(tint_tmp.x, tint_tmp.y);
-  uint2 res = tint_tmp;
+  uint2 res = (ext_tex_params[16].xy + (1u).xx);
   prevent_dce.Store2(0u, asuint(res));
 }
 
diff --git a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl
index c731548..b45ca2b 100644
--- a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.fxc.hlsl
@@ -3,12 +3,11 @@
   uint4 ext_tex_params[17];
 };
 Texture2D<float4> arg_0 : register(t0, space1);
+
 RWByteAddressBuffer prevent_dce : register(u0, space2);
 
 void textureDimensions_cdc6c9() {
-  uint2 tint_tmp;
-  arg_0.GetDimensions(tint_tmp.x, tint_tmp.y);
-  uint2 res = tint_tmp;
+  uint2 res = (ext_tex_params[16].xy + (1u).xx);
   prevent_dce.Store2(0u, asuint(res));
 }
 
diff --git a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.glsl b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.glsl
index f4d92ca..95c24ec 100644
--- a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.glsl
@@ -57,13 +57,12 @@
   ExternalTextureParams_std140 inner;
 } ext_tex_params;
 
-uniform highp sampler2D arg_0_1;
 layout(binding = 0, std430) buffer prevent_dce_block_ssbo {
   uvec2 inner;
 } prevent_dce;
 
 void textureDimensions_cdc6c9() {
-  uvec2 res = uvec2(textureSize(arg_0_1, 0));
+  uvec2 res = (ext_tex_params.inner.visibleSize + uvec2(1u));
   prevent_dce.inner = res;
 }
 
@@ -141,13 +140,12 @@
   ExternalTextureParams_std140 inner;
 } ext_tex_params;
 
-uniform highp sampler2D arg_0_1;
 layout(binding = 0, std430) buffer prevent_dce_block_ssbo {
   uvec2 inner;
 } prevent_dce;
 
 void textureDimensions_cdc6c9() {
-  uvec2 res = uvec2(textureSize(arg_0_1, 0));
+  uvec2 res = (ext_tex_params.inner.visibleSize + uvec2(1u));
   prevent_dce.inner = res;
 }
 
@@ -218,13 +216,12 @@
   ExternalTextureParams_std140 inner;
 } ext_tex_params;
 
-uniform highp sampler2D arg_0_1;
 layout(binding = 0, std430) buffer prevent_dce_block_ssbo {
   uvec2 inner;
 } prevent_dce;
 
 void textureDimensions_cdc6c9() {
-  uvec2 res = uvec2(textureSize(arg_0_1, 0));
+  uvec2 res = (ext_tex_params.inner.visibleSize + uvec2(1u));
   prevent_dce.inner = res;
 }
 
diff --git a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.msl b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.msl
index 559bfb4..85ac3a3 100644
--- a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.msl
@@ -15,35 +15,37 @@
 };
 
 struct tint_packed_vec3_f32_array_element {
-  packed_float3 elements;
+  /* 0x0000 */ packed_float3 elements;
+  /* 0x000c */ tint_array<int8_t, 4> tint_pad;
 };
 
 struct GammaTransferParams {
-  float G;
-  float A;
-  float B;
-  float C;
-  float D;
-  float E;
-  float F;
-  uint padding;
+  /* 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_tint_packed_vec3 {
-  uint numPlanes;
-  uint doYuvToRgbConversionOnly;
-  float3x4 yuvToRgbConversionMatrix;
-  GammaTransferParams gammaDecodeParams;
-  GammaTransferParams gammaEncodeParams;
-  tint_array<tint_packed_vec3_f32_array_element, 3> gamutConversionMatrix;
-  float3x2 sampleTransform;
-  float3x2 loadTransform;
-  float2 samplePlane0RectMin;
-  float2 samplePlane0RectMax;
-  float2 samplePlane1RectMin;
-  float2 samplePlane1RectMax;
-  uint2 visibleSize;
-  float2 plane1CoordFactor;
+  /* 0x0000 */ uint numPlanes;
+  /* 0x0004 */ uint doYuvToRgbConversionOnly;
+  /* 0x0008 */ tint_array<int8_t, 8> tint_pad_1;
+  /* 0x0010 */ float3x4 yuvToRgbConversionMatrix;
+  /* 0x0040 */ GammaTransferParams gammaDecodeParams;
+  /* 0x0060 */ GammaTransferParams gammaEncodeParams;
+  /* 0x0080 */ tint_array<tint_packed_vec3_f32_array_element, 3> gamutConversionMatrix;
+  /* 0x00b0 */ float3x2 sampleTransform;
+  /* 0x00c8 */ float3x2 loadTransform;
+  /* 0x00e0 */ float2 samplePlane0RectMin;
+  /* 0x00e8 */ float2 samplePlane0RectMax;
+  /* 0x00f0 */ float2 samplePlane1RectMin;
+  /* 0x00f8 */ float2 samplePlane1RectMax;
+  /* 0x0100 */ uint2 visibleSize;
+  /* 0x0108 */ float2 plane1CoordFactor;
 };
 
 struct ExternalTextureParams {
@@ -63,8 +65,8 @@
   float2 plane1CoordFactor;
 };
 
-void textureDimensions_cdc6c9(texture2d<float, access::sample> tint_symbol_1, device uint2* const tint_symbol_2) {
-  uint2 res = uint2(tint_symbol_1.get_width(), tint_symbol_1.get_height());
+void textureDimensions_cdc6c9(const constant ExternalTextureParams_tint_packed_vec3* const tint_symbol_1, device uint2* const tint_symbol_2) {
+  uint2 res = ((*(tint_symbol_1)).visibleSize + uint2(1u));
   *(tint_symbol_2) = res;
 }
 
@@ -72,24 +74,24 @@
   float4 value [[position]];
 };
 
-float4 vertex_main_inner(texture2d<float, access::sample> tint_symbol_3, device uint2* const tint_symbol_4) {
+float4 vertex_main_inner(const constant ExternalTextureParams_tint_packed_vec3* const tint_symbol_3, device uint2* const tint_symbol_4) {
   textureDimensions_cdc6c9(tint_symbol_3, tint_symbol_4);
   return float4(0.0f);
 }
 
-vertex tint_symbol vertex_main(texture2d<float, access::sample> tint_symbol_5 [[texture(0)]], device uint2* tint_symbol_6 [[buffer(0)]]) {
+vertex tint_symbol vertex_main(const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_5 [[buffer(2)]], device uint2* tint_symbol_6 [[buffer(0)]]) {
   float4 const inner_result = vertex_main_inner(tint_symbol_5, tint_symbol_6);
   tint_symbol wrapper_result = {};
   wrapper_result.value = inner_result;
   return wrapper_result;
 }
 
-fragment void fragment_main(texture2d<float, access::sample> tint_symbol_7 [[texture(0)]], device uint2* tint_symbol_8 [[buffer(0)]]) {
+fragment void fragment_main(const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_7 [[buffer(2)]], device uint2* tint_symbol_8 [[buffer(0)]]) {
   textureDimensions_cdc6c9(tint_symbol_7, tint_symbol_8);
   return;
 }
 
-kernel void compute_main(texture2d<float, access::sample> tint_symbol_9 [[texture(0)]], device uint2* tint_symbol_10 [[buffer(0)]]) {
+kernel void compute_main(const constant ExternalTextureParams_tint_packed_vec3* tint_symbol_9 [[buffer(2)]], device uint2* tint_symbol_10 [[buffer(0)]]) {
   textureDimensions_cdc6c9(tint_symbol_9, tint_symbol_10);
   return;
 }
diff --git a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.spvasm b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.spvasm
index 9152ae6..3dc25d5 100644
--- a/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.spvasm
+++ b/test/tint/builtins/gen/var/textureDimensions/cdc6c9.wgsl.expected.spvasm
@@ -1,10 +1,9 @@
 ; SPIR-V
 ; Version: 1.3
 ; Generator: Google Tint Compiler; 0
-; Bound: 56
+; Bound: 59
 ; Schema: 0
                OpCapability Shader
-               OpCapability ImageQuery
                OpMemoryModel Logical GLSL450
                OpEntryPoint Vertex %vertex_main "vertex_main" %value %vertex_point_size
                OpEntryPoint Fragment %fragment_main "fragment_main"
@@ -128,44 +127,47 @@
 %prevent_dce = OpVariable %_ptr_StorageBuffer_prevent_dce_block StorageBuffer
        %void = OpTypeVoid
          %27 = OpTypeFunction %void
-        %int = OpTypeInt 32 1
-      %int_0 = OpConstant %int 0
-%_ptr_Function_v2uint = OpTypePointer Function %v2uint
-         %37 = OpConstantNull %v2uint
      %uint_0 = OpConstant %uint 0
+    %uint_16 = OpConstant %uint 16
+%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint
+     %uint_1 = OpConstant %uint 1
+         %37 = OpConstantComposite %v2uint %uint_1 %uint_1
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+         %41 = OpConstantNull %v2uint
 %_ptr_StorageBuffer_v2uint = OpTypePointer StorageBuffer %v2uint
-         %42 = OpTypeFunction %v4float
+         %45 = OpTypeFunction %v4float
     %float_1 = OpConstant %float 1
 %textureDimensions_cdc6c9 = OpFunction %void None %27
          %30 = OpLabel
-        %res = OpVariable %_ptr_Function_v2uint Function %37
-         %32 = OpLoad %11 %arg_0
-         %31 = OpImageQuerySizeLod %v2uint %32 %int_0
-               OpStore %res %31
-         %40 = OpAccessChain %_ptr_StorageBuffer_v2uint %prevent_dce %uint_0
-         %41 = OpLoad %v2uint %res
-               OpStore %40 %41
+        %res = OpVariable %_ptr_Function_v2uint Function %41
+         %34 = OpAccessChain %_ptr_Uniform_v2uint %ext_tex_params %uint_0 %uint_16
+         %35 = OpLoad %v2uint %34
+         %38 = OpIAdd %v2uint %35 %37
+               OpStore %res %38
+         %43 = OpAccessChain %_ptr_StorageBuffer_v2uint %prevent_dce %uint_0
+         %44 = OpLoad %v2uint %res
+               OpStore %43 %44
                OpReturn
                OpFunctionEnd
-%vertex_main_inner = OpFunction %v4float None %42
-         %44 = OpLabel
-         %45 = OpFunctionCall %void %textureDimensions_cdc6c9
+%vertex_main_inner = OpFunction %v4float None %45
+         %47 = OpLabel
+         %48 = OpFunctionCall %void %textureDimensions_cdc6c9
                OpReturnValue %5
                OpFunctionEnd
 %vertex_main = OpFunction %void None %27
-         %47 = OpLabel
-         %48 = OpFunctionCall %v4float %vertex_main_inner
-               OpStore %value %48
+         %50 = OpLabel
+         %51 = OpFunctionCall %v4float %vertex_main_inner
+               OpStore %value %51
                OpStore %vertex_point_size %float_1
                OpReturn
                OpFunctionEnd
 %fragment_main = OpFunction %void None %27
-         %51 = OpLabel
-         %52 = OpFunctionCall %void %textureDimensions_cdc6c9
+         %54 = OpLabel
+         %55 = OpFunctionCall %void %textureDimensions_cdc6c9
                OpReturn
                OpFunctionEnd
 %compute_main = OpFunction %void None %27
-         %54 = OpLabel
-         %55 = OpFunctionCall %void %textureDimensions_cdc6c9
+         %57 = OpLabel
+         %58 = OpFunctionCall %void %textureDimensions_cdc6c9
                OpReturn
                OpFunctionEnd