Implement textureDimensions()

SPIR-V reader TODO.

Bug: tint:140
Bug: tint:437
Change-Id: Ia3a6cb0b36142142d3dc8662281e1860c609c82b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/36980
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/intrinsic.cc b/src/ast/intrinsic.cc
index 8057e80..c4ce9c1 100644
--- a/src/ast/intrinsic.cc
+++ b/src/ast/intrinsic.cc
@@ -262,13 +262,18 @@
 }
 
 bool IsTextureIntrinsic(Intrinsic i) {
-  return i == Intrinsic::kTextureLoad || i == Intrinsic::kTextureSample ||
+  return i == Intrinsic::kTextureDimensions || i == Intrinsic::kTextureLoad ||
+         i == Intrinsic::kTextureSample ||
          i == Intrinsic::kTextureSampleLevel ||
          i == Intrinsic::kTextureSampleBias ||
          i == Intrinsic::kTextureSampleCompare ||
          i == Intrinsic::kTextureSampleGrad || i == Intrinsic::kTextureStore;
 }
 
+bool IsImageQueryIntrinsic(Intrinsic i) {
+  return i == ast::Intrinsic::kTextureDimensions;
+}
+
 }  // namespace intrinsic
 }  // namespace ast
 }  // namespace tint
diff --git a/src/ast/intrinsic.h b/src/ast/intrinsic.h
index 3207f80..568c9ee 100644
--- a/src/ast/intrinsic.h
+++ b/src/ast/intrinsic.h
@@ -84,6 +84,7 @@
   kStep,
   kTan,
   kTanh,
+  kTextureDimensions,
   kTextureLoad,
   kTextureSample,
   kTextureSampleBias,
@@ -187,6 +188,11 @@
 /// @returns true if the given `i` is a texture operation intrinsic
 bool IsTextureIntrinsic(Intrinsic i);
 
+/// Determines if the given `i` is a image query intrinsic
+/// @param i the intrinsic
+/// @returns true if the given `i` is a image query intrinsic
+bool IsImageQueryIntrinsic(Intrinsic i);
+
 }  // namespace intrinsic
 }  // namespace ast
 }  // namespace tint
diff --git a/src/ast/intrinsic_texture_helper_test.cc b/src/ast/intrinsic_texture_helper_test.cc
index d0cad38..ae705f1 100644
--- a/src/ast/intrinsic_texture_helper_test.cc
+++ b/src/ast/intrinsic_texture_helper_test.cc
@@ -187,6 +187,344 @@
 std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
   return {
       {
+          ValidTextureOverload::kDimensions1d,
+          "textureDimensions(t : texture_1d<f32>) -> i32",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k1d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensions1dArray,
+          "textureDimensions(t : texture_1d_array<f32>) -> i32",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensions2d,
+          "textureDimensions(t : texture_2d<f32>) -> vec2<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensions2dLevel,
+          "textureDimensions(t     : texture_2d<f32>,\n"
+          "                  level : i32) -> vec2<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensions2dArray,
+          "textureDimensions(t : texture_2d_array<f32>) -> vec2<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensions2dArrayLevel,
+          "textureDimensions(t     : texture_2d_array<f32>,\n"
+          "                  level : i32) -> vec2<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensions3d,
+          "textureDimensions(t : texture_3d<f32>) -> vec3<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensions3dLevel,
+          "textureDimensions(t     : texture_3d<f32>,\n"
+          "                  level : i32) -> vec3<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensionsCube,
+          "textureDimensions(t : texture_cube<f32>) -> vec3<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsCubeLevel,
+          "textureDimensions(t     : texture_cube<f32>,\n"
+          "                  level : i32) -> vec3<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensionsCubeArray,
+          "textureDimensions(t : texture_cube_array<f32>) -> vec3<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsCubeArrayLevel,
+          "textureDimensions(t     : texture_cube_array<f32>,\n"
+          "                  level : i32) -> vec3<i32>",
+          TextureKind::kRegular,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensionsMultisampled_2d,
+          "textureDimensions(t : texture_multisampled_2d<f32>)-> vec2<i32>",
+          TextureKind::kMultisampled,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsMultisampled_2dArray,
+          "textureDimensions(t : texture_multisampled_2d_array<f32>)-> "
+          "vec2<i32>",
+          TextureKind::kMultisampled,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepth2d,
+          "textureDimensions(t : texture_depth_2d) -> vec2<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepth2dLevel,
+          "textureDimensions(t     : texture_depth_2d,\n"
+          "                  level : i32) -> vec2<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepth2dArray,
+          "textureDimensions(t : texture_depth_2d_array) -> vec2<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepth2dArrayLevel,
+          "textureDimensions(t     : texture_depth_2d_array,\n"
+          "                  level : i32) -> vec2<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepthCube,
+          "textureDimensions(t : texture_depth_cube) -> vec3<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepthCubeLevel,
+          "textureDimensions(t     : texture_depth_cube,\n"
+          "                  level : i32) -> vec3<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCube,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepthCubeArray,
+          "textureDimensions(t : texture_depth_cube_array) -> vec3<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsDepthCubeArrayLevel,
+          "textureDimensions(t     : texture_depth_cube_array,\n"
+          "                  level : i32) -> vec3<i32>",
+          TextureKind::kDepth,
+          type::SamplerKind::kSampler,
+          type::TextureDimension::kCubeArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture", 1); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageRO1d,
+          "textureDimensions(t : texture_storage_ro_1d<rgba32float>) -> i32",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k1d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageRO1dArray,
+          "textureDimensions(t : texture_storage_ro_1d_array<rgba32float>) -> "
+          "i32",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageRO2d,
+          "textureDimensions(t : texture_storage_ro_2d<rgba32float>) -> "
+          "vec2<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageRO2dArray,
+          "textureDimensions(t : texture_storage_ro_2d_array<rgba32float>) -> "
+          "vec2<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageRO3d,
+          "textureDimensions(t : texture_storage_ro_3d<rgba32float>) -> "
+          "vec3<i32>",
+          ast::AccessControl::kReadOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageWO1d,
+          "textureDimensions(t : texture_storage_wo_1d<rgba32float>) -> i32",
+          ast::AccessControl::kWriteOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k1d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageWO1dArray,
+          "textureDimensions(t : texture_storage_wo_1d_array<rgba32float>) -> "
+          "i32",
+          ast::AccessControl::kWriteOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k1dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageWO2d,
+          "textureDimensions(t : texture_storage_wo_2d<rgba32float>) -> "
+          "vec2<i32>",
+          ast::AccessControl::kWriteOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k2d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageWO2dArray,
+          "textureDimensions(t : texture_storage_wo_2d_array<rgba32float>) -> "
+          "vec2<i32>",
+          ast::AccessControl::kWriteOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k2dArray,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
+          ValidTextureOverload::kDimensionsStorageWO3d,
+          "textureDimensions(t : texture_storage_wo_3d<rgba32float>) -> "
+          "vec3<i32>",
+          ast::AccessControl::kWriteOnly,
+          ast::type::ImageFormat::kRgba32Float,
+          type::TextureDimension::k3d,
+          TextureDataType::kF32,
+          "textureDimensions",
+          [](Builder* b) { return b->ExprList("texture"); },
+      },
+      {
           ValidTextureOverload::kSample1dF32,
           "textureSample(t      : texture_1d<f32>,\n"
           "              s      : sampler,\n"
diff --git a/src/ast/intrinsic_texture_helper_test.h b/src/ast/intrinsic_texture_helper_test.h
index 557518e..fd2d17e 100644
--- a/src/ast/intrinsic_texture_helper_test.h
+++ b/src/ast/intrinsic_texture_helper_test.h
@@ -36,6 +36,38 @@
 
 /// Non-exhaustive list of valid texture overloads
 enum class ValidTextureOverload {
+  kDimensions1d,
+  kDimensions1dArray,
+  kDimensions2d,
+  kDimensions2dLevel,
+  kDimensions2dArray,
+  kDimensions2dArrayLevel,
+  kDimensions3d,
+  kDimensions3dLevel,
+  kDimensionsCube,
+  kDimensionsCubeLevel,
+  kDimensionsCubeArray,
+  kDimensionsCubeArrayLevel,
+  kDimensionsMultisampled_2d,
+  kDimensionsMultisampled_2dArray,
+  kDimensionsDepth2d,
+  kDimensionsDepth2dLevel,
+  kDimensionsDepth2dArray,
+  kDimensionsDepth2dArrayLevel,
+  kDimensionsDepthCube,
+  kDimensionsDepthCubeLevel,
+  kDimensionsDepthCubeArray,
+  kDimensionsDepthCubeArrayLevel,
+  kDimensionsStorageRO1d,
+  kDimensionsStorageRO1dArray,
+  kDimensionsStorageRO2d,
+  kDimensionsStorageRO2dArray,
+  kDimensionsStorageRO3d,
+  kDimensionsStorageWO1d,
+  kDimensionsStorageWO1dArray,
+  kDimensionsStorageWO2d,
+  kDimensionsStorageWO2dArray,
+  kDimensionsStorageWO3d,
   kSample1dF32,
   kSample1dArrayF32,
   kSample2dF32,
diff --git a/src/ast/type/texture_type.cc b/src/ast/type/texture_type.cc
index e97b4be..2914fb6 100644
--- a/src/ast/type/texture_type.cc
+++ b/src/ast/type/texture_type.cc
@@ -56,6 +56,22 @@
   return out;
 }
 
+bool IsTextureArray(TextureDimension dim) {
+  switch (dim) {
+    case TextureDimension::k1dArray:
+    case TextureDimension::k2dArray:
+    case TextureDimension::kCubeArray:
+      return true;
+    case TextureDimension::k2d:
+    case TextureDimension::kNone:
+    case TextureDimension::k1d:
+    case TextureDimension::k3d:
+    case TextureDimension::kCube:
+      return false;
+  }
+  return false;
+}
+
 Texture::Texture(TextureDimension dim) : dim_(dim) {}
 
 Texture::Texture(Texture&&) = default;
diff --git a/src/ast/type/texture_type.h b/src/ast/type/texture_type.h
index 88af3fa..d44f5e2 100644
--- a/src/ast/type/texture_type.h
+++ b/src/ast/type/texture_type.h
@@ -42,6 +42,10 @@
 };
 std::ostream& operator<<(std::ostream& out, TextureDimension dim);
 
+/// @param dim the TextureDimension to query
+/// @return true if the given TextureDimension is an array texture
+bool IsTextureArray(TextureDimension dim);
+
 /// A texture type.
 class Texture : public Castable<Texture, Type> {
  public:
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 0feed92..72551bd 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -556,18 +556,15 @@
                                       ->UnwrapPtrIfNeeded()
                                       ->As<ast::type::Texture>();
 
-    bool is_array = false;
+    bool is_array = ast::type::IsTextureArray(texture->dim());
     bool is_multisampled = texture->Is<ast::type::MultisampledTexture>();
-    switch (texture->dim()) {
-      case ast::type::TextureDimension::k1dArray:
-      case ast::type::TextureDimension::k2dArray:
-      case ast::type::TextureDimension::kCubeArray:
-        is_array = true;
-        break;
-      default:
-        break;
-    }
     switch (ident->intrinsic()) {
+      case ast::Intrinsic::kTextureDimensions:
+        param.idx.texture = param.count++;
+        if (expr->params().size() > param.count) {
+          param.idx.level = param.count++;
+        }
+        break;
       case ast::Intrinsic::kTextureLoad:
         param.idx.texture = param.count++;
         param.idx.coords = param.count++;
@@ -671,7 +668,27 @@
 
     // Set the function return type
     ast::type::Type* return_type = nullptr;
-    if (ident->intrinsic() == ast::Intrinsic::kTextureStore) {
+    if (ident->intrinsic() == ast::Intrinsic::kTextureDimensions) {
+      auto* i32 = mod_->create<ast::type::I32>();
+      switch (texture->dim()) {
+        default:
+          set_error(expr->source(), "invalid texture dimensions");
+          break;
+        case ast::type::TextureDimension::k1d:
+        case ast::type::TextureDimension::k1dArray:
+          return_type = i32;
+          break;
+        case ast::type::TextureDimension::k2d:
+        case ast::type::TextureDimension::k2dArray:
+          return_type = mod_->create<ast::type::Vector>(i32, 2);
+          break;
+        case ast::type::TextureDimension::k3d:
+        case ast::type::TextureDimension::kCube:
+        case ast::type::TextureDimension::kCubeArray:
+          return_type = mod_->create<ast::type::Vector>(i32, 3);
+          break;
+      }
+    } else if (ident->intrinsic() == ast::Intrinsic::kTextureStore) {
       return_type = mod_->create<ast::type::Void>();
     } else {
       if (texture->Is<ast::type::DepthTexture>()) {
@@ -1025,6 +1042,8 @@
     ident->set_intrinsic(ast::Intrinsic::kTan);
   } else if (name == "tanh") {
     ident->set_intrinsic(ast::Intrinsic::kTanh);
+  } else if (name == "textureDimensions") {
+    ident->set_intrinsic(ast::Intrinsic::kTextureDimensions);
   } else if (name == "textureLoad") {
     ident->set_intrinsic(ast::Intrinsic::kTextureLoad);
   } else if (name == "textureStore") {
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 21006f5..46545c4 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -1812,6 +1812,7 @@
         IntrinsicData{"step", ast::Intrinsic::kStep},
         IntrinsicData{"tan", ast::Intrinsic::kTan},
         IntrinsicData{"tanh", ast::Intrinsic::kTanh},
+        IntrinsicData{"textureDimensions", ast::Intrinsic::kTextureDimensions},
         IntrinsicData{"textureLoad", ast::Intrinsic::kTextureLoad},
         IntrinsicData{"textureSample", ast::Intrinsic::kTextureSample},
         IntrinsicData{"textureSampleBias", ast::Intrinsic::kTextureSampleBias},
@@ -2953,6 +2954,40 @@
     ast::intrinsic::test::ValidTextureOverload overload) {
   using ValidTextureOverload = ast::intrinsic::test::ValidTextureOverload;
   switch (overload) {
+    case ValidTextureOverload::kDimensions1d:
+    case ValidTextureOverload::kDimensions1dArray:
+    case ValidTextureOverload::kDimensions2d:
+    case ValidTextureOverload::kDimensions2dArray:
+    case ValidTextureOverload::kDimensions3d:
+    case ValidTextureOverload::kDimensionsCube:
+    case ValidTextureOverload::kDimensionsCubeArray:
+    case ValidTextureOverload::kDimensionsMultisampled_2d:
+    case ValidTextureOverload::kDimensionsMultisampled_2dArray:
+    case ValidTextureOverload::kDimensionsDepth2d:
+    case ValidTextureOverload::kDimensionsDepth2dArray:
+    case ValidTextureOverload::kDimensionsDepthCube:
+    case ValidTextureOverload::kDimensionsDepthCubeArray:
+    case ValidTextureOverload::kDimensionsStorageRO1d:
+    case ValidTextureOverload::kDimensionsStorageRO1dArray:
+    case ValidTextureOverload::kDimensionsStorageRO2d:
+    case ValidTextureOverload::kDimensionsStorageRO2dArray:
+    case ValidTextureOverload::kDimensionsStorageRO3d:
+    case ValidTextureOverload::kDimensionsStorageWO1d:
+    case ValidTextureOverload::kDimensionsStorageWO1dArray:
+    case ValidTextureOverload::kDimensionsStorageWO2d:
+    case ValidTextureOverload::kDimensionsStorageWO2dArray:
+    case ValidTextureOverload::kDimensionsStorageWO3d:
+      return R"(textureDimensions(texture))";
+    case ValidTextureOverload::kDimensions2dLevel:
+    case ValidTextureOverload::kDimensions2dArrayLevel:
+    case ValidTextureOverload::kDimensions3dLevel:
+    case ValidTextureOverload::kDimensionsCubeLevel:
+    case ValidTextureOverload::kDimensionsCubeArrayLevel:
+    case ValidTextureOverload::kDimensionsDepth2dLevel:
+    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+    case ValidTextureOverload::kDimensionsDepthCubeLevel:
+    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+      return R"(textureDimensions(texture, level))";
     case ValidTextureOverload::kSample1dF32:
       return R"(textureSample(texture, sampler, coords))";
     case ValidTextureOverload::kSample1dArrayF32:
@@ -3176,7 +3211,27 @@
   ASSERT_TRUE(td()->Determine()) << td()->error();
   ASSERT_TRUE(td()->DetermineResultType(call)) << td()->error();
 
-  if (std::string(param.function) == "textureStore") {
+  if (std::string(param.function) == "textureDimensions") {
+    switch (param.texture_dimension) {
+      default:
+        FAIL() << "invalid texture dimensions: " << param.texture_dimension;
+      case ast::type::TextureDimension::k1d:
+      case ast::type::TextureDimension::k1dArray:
+        EXPECT_EQ(call->result_type()->type_name(), ty.i32->type_name());
+        break;
+      case ast::type::TextureDimension::k2d:
+      case ast::type::TextureDimension::k2dArray:
+        EXPECT_EQ(call->result_type()->type_name(),
+                  ty.vec2<i32>()->type_name());
+        break;
+      case ast::type::TextureDimension::k3d:
+      case ast::type::TextureDimension::kCube:
+      case ast::type::TextureDimension::kCubeArray:
+        EXPECT_EQ(call->result_type()->type_name(),
+                  ty.vec3<i32>()->type_name());
+        break;
+    }
+  } else if (std::string(param.function) == "textureStore") {
     EXPECT_EQ(call->result_type(), ty.void_);
   } else {
     switch (param.texture_kind) {
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 796d3ec..af842ae 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -736,6 +736,39 @@
   auto* texture = params[pidx.texture];
   auto* texture_type = texture->result_type()->UnwrapPtrIfNeeded();
 
+  if (ident->intrinsic() == ast::Intrinsic::kTextureDimensions) {
+    // Declare a variable to hold the texture dimensions
+    auto dims = namer_->GenerateName(kTempNamePrefix);
+    EmitType(pre, expr->result_type(), Symbol());
+    pre << " " << dims << ";" << std::endl;
+
+    // Now call GetDimensions() on the texture object, populating the dims
+    // variable.
+    std::stringstream tex_out;
+    if (!EmitExpression(pre, tex_out, texture)) {
+      return false;
+    }
+    pre << tex_out.str() << ".GetDimensions(";
+    if (pidx.level != kNotUsed) {
+      pre << pidx.level << ", ";
+    }
+    if (auto* vec = expr->result_type()->As<ast::type::Vector>()) {
+      for (uint32_t i = 0; i < vec->size(); i++) {
+        if (i > 0) {
+          pre << ", ";
+        }
+        pre << dims << "[" << i << "]";
+      }
+    } else {
+      pre << dims;
+    }
+    pre << ");";
+
+    // The result of the textureDimensions() call is now the temporary variable.
+    out << dims;
+    return true;
+  }
+
   if (!EmitExpression(pre, out, texture))
     return false;
 
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h
index 0013033..8f8a37b 100644
--- a/src/writer/hlsl/generator_impl.h
+++ b/src/writer/hlsl/generator_impl.h
@@ -350,10 +350,6 @@
   /// @returns the index string, or blank if unable to generate
   std::string generate_storage_buffer_index_expression(std::ostream& pre,
                                                        ast::Expression* expr);
-  /// Generates a name for the prefix
-  /// @param prefix the prefix of the name to generate
-  /// @returns the name
-  std::string generate_name(const std::string& prefix);
   /// Generates an intrinsic name from the given name
   /// @param intrinsic the intrinsic to convert to a name
   /// @returns the intrinsic name or blank on error
diff --git a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
index 6629410..84d5924 100644
--- a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
+++ b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
@@ -29,10 +29,77 @@
 namespace hlsl {
 namespace {
 
-std::string expected_texture_overload(
+struct ExpectedResult {
+  ExpectedResult(const char* o) : out(o) {}  // NOLINT
+  ExpectedResult(const char* p, const char* o) : pre(p), out(o) {}
+
+  std::string pre;
+  std::string out;
+};
+
+ExpectedResult expected_texture_overload(
     ast::intrinsic::test::ValidTextureOverload overload) {
   using ValidTextureOverload = ast::intrinsic::test::ValidTextureOverload;
   switch (overload) {
+    case ValidTextureOverload::kDimensions1d:
+    case ValidTextureOverload::kDimensions1dArray:
+    case ValidTextureOverload::kDimensionsStorageRO1d:
+    case ValidTextureOverload::kDimensionsStorageRO1dArray:
+    case ValidTextureOverload::kDimensionsStorageWO1d:
+    case ValidTextureOverload::kDimensionsStorageWO1dArray:
+      return {
+          "int _tint_tmp;\n"
+          "test_texture.GetDimensions(_tint_tmp);",
+          "_tint_tmp",
+      };
+    case ValidTextureOverload::kDimensions2d:
+    case ValidTextureOverload::kDimensions2dArray:
+    case ValidTextureOverload::kDimensionsMultisampled_2d:
+    case ValidTextureOverload::kDimensionsMultisampled_2dArray:
+    case ValidTextureOverload::kDimensionsDepth2d:
+    case ValidTextureOverload::kDimensionsDepth2dArray:
+    case ValidTextureOverload::kDimensionsStorageRO2d:
+    case ValidTextureOverload::kDimensionsStorageRO2dArray:
+    case ValidTextureOverload::kDimensionsStorageWO2d:
+    case ValidTextureOverload::kDimensionsStorageWO2dArray:
+      return {
+          "int2 _tint_tmp;\n"
+          "test_texture.GetDimensions(_tint_tmp[0], _tint_tmp[1]);",
+          "_tint_tmp",
+      };
+    case ValidTextureOverload::kDimensions3d:
+    case ValidTextureOverload::kDimensionsCube:
+    case ValidTextureOverload::kDimensionsCubeArray:
+    case ValidTextureOverload::kDimensionsDepthCube:
+    case ValidTextureOverload::kDimensionsDepthCubeArray:
+    case ValidTextureOverload::kDimensionsStorageRO3d:
+    case ValidTextureOverload::kDimensionsStorageWO3d:
+      return {
+          "int3 _tint_tmp;\n"
+          "test_texture.GetDimensions(_tint_tmp[0], _tint_tmp[1], "
+          "_tint_tmp[2]);",
+          "_tint_tmp",
+      };
+    case ValidTextureOverload::kDimensions2dLevel:
+    case ValidTextureOverload::kDimensions2dArrayLevel:
+    case ValidTextureOverload::kDimensionsDepth2dLevel:
+    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+      return {
+          "int2 _tint_tmp;\n"
+          "test_texture.GetDimensions(1, _tint_tmp[0], _tint_tmp[1]);",
+          "_tint_tmp",
+      };
+    case ValidTextureOverload::kDimensions3dLevel:
+    case ValidTextureOverload::kDimensionsCubeLevel:
+    case ValidTextureOverload::kDimensionsCubeArrayLevel:
+    case ValidTextureOverload::kDimensionsDepthCubeLevel:
+    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+      return {
+          "int3 _tint_tmp;\n"
+          "test_texture.GetDimensions(1, _tint_tmp[0], _tint_tmp[1], "
+          "_tint_tmp[2]);",
+          "_tint_tmp",
+      };
     case ValidTextureOverload::kSample1dF32:
       return R"(test_texture.Sample(test_sampler, 1.0f))";
     case ValidTextureOverload::kSample1dArrayF32:
@@ -282,10 +349,10 @@
 
   ASSERT_TRUE(gen.EmitExpression(pre, out, call)) << gen.error();
 
-  EXPECT_TRUE(pre_result().empty());
-
   auto expected = expected_texture_overload(param.overload);
-  EXPECT_EQ(result(), expected);
+
+  EXPECT_EQ(expected.pre, pre_result());
+  EXPECT_EQ(expected.out, result());
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 6d91cfa..e21221e 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -652,6 +652,49 @@
   auto& pidx = signature->params.idx;
   auto const kNotUsed = ast::intrinsic::TextureSignature::Parameters::kNotUsed;
 
+  if (ident->intrinsic() == ast::Intrinsic::kTextureDimensions) {
+    auto get_dim = [&](const char* name) {
+      if (!EmitExpression(params[pidx.texture])) {
+        return false;
+      }
+      out_ << ".get_" << name << "(";
+      if (pidx.level != kNotUsed) {
+        out_ << pidx.level;
+      }
+      out_ << ")";
+      return true;
+    };
+
+    size_t dims = 1;
+    if (auto* vec = expr->result_type()->As<ast::type::Vector>()) {
+      dims = vec->size();
+    }
+    switch (dims) {
+      case 1:
+        get_dim("width");
+        break;
+      case 2:
+        EmitType(expr->result_type(), Symbol());
+        out_ << "(";
+        get_dim("width");
+        out_ << ", ";
+        get_dim("height");
+        out_ << ")";
+        break;
+      case 3:
+        EmitType(expr->result_type(), Symbol());
+        out_ << "(";
+        get_dim("width");
+        out_ << ", ";
+        get_dim("height");
+        out_ << ", ";
+        get_dim("depth");
+        out_ << ")";
+        break;
+    }
+    return true;
+  }
+
   if (!EmitExpression(params[pidx.texture]))
     return false;
 
diff --git a/src/writer/msl/generator_impl_intrinsic_texture_test.cc b/src/writer/msl/generator_impl_intrinsic_texture_test.cc
index 9f04372..ca00a75 100644
--- a/src/writer/msl/generator_impl_intrinsic_texture_test.cc
+++ b/src/writer/msl/generator_impl_intrinsic_texture_test.cc
@@ -33,6 +33,43 @@
     ast::intrinsic::test::ValidTextureOverload overload) {
   using ValidTextureOverload = ast::intrinsic::test::ValidTextureOverload;
   switch (overload) {
+    case ValidTextureOverload::kDimensions1d:
+    case ValidTextureOverload::kDimensions1dArray:
+    case ValidTextureOverload::kDimensionsStorageRO1d:
+    case ValidTextureOverload::kDimensionsStorageRO1dArray:
+    case ValidTextureOverload::kDimensionsStorageWO1d:
+    case ValidTextureOverload::kDimensionsStorageWO1dArray:
+      return R"(test_texture.get_width())";
+    case ValidTextureOverload::kDimensions2d:
+    case ValidTextureOverload::kDimensions2dArray:
+    case ValidTextureOverload::kDimensionsMultisampled_2d:
+    case ValidTextureOverload::kDimensionsMultisampled_2dArray:
+    case ValidTextureOverload::kDimensionsDepth2d:
+    case ValidTextureOverload::kDimensionsDepth2dArray:
+    case ValidTextureOverload::kDimensionsStorageRO2d:
+    case ValidTextureOverload::kDimensionsStorageRO2dArray:
+    case ValidTextureOverload::kDimensionsStorageWO2d:
+    case ValidTextureOverload::kDimensionsStorageWO2dArray:
+      return R"(int2(test_texture.get_width(), test_texture.get_height()))";
+    case ValidTextureOverload::kDimensions3d:
+    case ValidTextureOverload::kDimensionsCube:
+    case ValidTextureOverload::kDimensionsCubeArray:
+    case ValidTextureOverload::kDimensionsDepthCube:
+    case ValidTextureOverload::kDimensionsDepthCubeArray:
+    case ValidTextureOverload::kDimensionsStorageRO3d:
+    case ValidTextureOverload::kDimensionsStorageWO3d:
+      return R"(int3(test_texture.get_width(), test_texture.get_height(), test_texture.get_depth()))";
+    case ValidTextureOverload::kDimensions2dLevel:
+    case ValidTextureOverload::kDimensions2dArrayLevel:
+    case ValidTextureOverload::kDimensionsDepth2dLevel:
+    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+      return R"(int2(test_texture.get_width(1), test_texture.get_height(1)))";
+    case ValidTextureOverload::kDimensions3dLevel:
+    case ValidTextureOverload::kDimensionsCubeLevel:
+    case ValidTextureOverload::kDimensionsCubeArrayLevel:
+    case ValidTextureOverload::kDimensionsDepthCubeLevel:
+    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+      return R"(int3(test_texture.get_width(1), test_texture.get_height(1), test_texture.get_depth(1)))";
     case ValidTextureOverload::kSample1dF32:
       return R"(test_texture.sample(test_sampler, 1.0f))";
     case ValidTextureOverload::kSample1dArrayF32:
@@ -275,7 +312,7 @@
   ASSERT_TRUE(gen.EmitExpression(call)) << gen.error();
 
   auto expected = expected_texture_overload(param.overload);
-  EXPECT_EQ(gen.result(), expected);
+  EXPECT_EQ(expected, gen.result());
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 8736c59..9cdf602 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -1850,6 +1850,15 @@
 
   auto intrinsic = ident->intrinsic();
 
+  if (ast::intrinsic::IsFineDerivative(intrinsic) ||
+      ast::intrinsic::IsCoarseDerivative(intrinsic)) {
+    push_capability(SpvCapabilityDerivativeControl);
+  }
+
+  if (ast::intrinsic::IsImageQueryIntrinsic(intrinsic)) {
+    push_capability(SpvCapabilityImageQuery);
+  }
+
   if (ast::intrinsic::IsTextureIntrinsic(intrinsic)) {
     if (!GenerateTextureIntrinsic(ident, call, Operand::Int(result_type_id),
                                   result)) {
@@ -1860,11 +1869,6 @@
 
   OperandList params = {Operand::Int(result_type_id), result};
 
-  if (ast::intrinsic::IsFineDerivative(intrinsic) ||
-      ast::intrinsic::IsCoarseDerivative(intrinsic)) {
-    push_capability(SpvCapabilityDerivativeControl);
-  }
-
   spv::Op op = spv::Op::OpNop;
   if (intrinsic == ast::Intrinsic::kAny) {
     op = spv::Op::OpAny;
@@ -1982,8 +1986,8 @@
 
 bool Builder::GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
                                        ast::CallExpression* call,
-                                       spirv::Operand result_type,
-                                       spirv::Operand result_id) {
+                                       Operand result_type,
+                                       Operand result_id) {
   auto* texture_type =
       call->params()[0]->result_type()->UnwrapAll()->As<ast::type::Texture>();
 
@@ -2008,22 +2012,26 @@
     return Operand::Int(val_id);
   };
 
+  // Custom function to call after the texture-intrinsic op has been generated.
+  std::function<bool()> post_emission = [] { return true; };
+
   // Populate the spirv_params with common parameters
   OperandList spirv_params;
   spirv_params.reserve(8);  // Enough to fit most parameter lists
-  if (ident->intrinsic() != ast::Intrinsic::kTextureStore) {
-    spirv_params.emplace_back(std::move(result_type));
-    spirv_params.emplace_back(std::move(result_id));
-  }
 
   // Extra image operands, appended to spirv_params.
   struct ImageOperand {
     SpvImageOperandsMask mask;
-    tint::writer::spirv::Operand operand;
+    Operand operand;
   };
   std::vector<ImageOperand> image_operands;
   image_operands.reserve(4);  // Enough to fit most parameter lists
 
+  auto append_result_type_and_id_to_spirv_params = [&]() {
+    spirv_params.emplace_back(std::move(result_type));
+    spirv_params.emplace_back(std::move(result_id));
+  };
+
   auto append_coords_to_spirv_params = [&]() -> bool {
     if (pidx.array_index != kNotUsed) {
       // Array index needs to be appended to the coordinates.
@@ -2062,10 +2070,67 @@
   };
 
   switch (ident->intrinsic()) {
+    case ast::Intrinsic::kTextureDimensions: {
+      if (ast::type::IsTextureArray(texture_type->dim())) {
+        // OpImageQuerySize[Lod] will append another element to the returned
+        // vector describing the number of array elements. textureDimensions()
+        // does not include this in the returned vector, so it needs to be
+        // stripped from the resulting vector.
+        auto unstripped_result = result_op();
+
+        ast::type::Type* unstripped_result_type;
+        if (auto* v = call->result_type()->As<ast::type::Vector>()) {
+          unstripped_result_type =
+              mod_->create<ast::type::Vector>(v->type(), v->size() + 1);
+          post_emission = [=] {
+            // Swizzle the unstripped vector to form a vec2 or vec3
+            OperandList operands{
+                result_type,
+                result_id,
+                unstripped_result,
+                unstripped_result,
+            };
+            for (uint32_t i = 0; i < v->size(); i++) {
+              operands.emplace_back(Operand::Int(i));
+            }
+            return push_function_inst(spv::Op::OpVectorShuffle, operands);
+          };
+        } else {
+          unstripped_result_type =
+              mod_->create<ast::type::Vector>(call->result_type(), 2);
+          post_emission = [=] {
+            // Extract the first element of the unstripped vec2 to form a scalar
+            return push_function_inst(
+                spv::Op::OpCompositeExtract,
+                {result_type, result_id, unstripped_result, Operand::Int(0)});
+          };
+        }
+
+        auto unstripped_result_type_id =
+            GenerateTypeIfNeeded(unstripped_result_type);
+        if (unstripped_result_type_id == 0) {
+          return false;
+        }
+        spirv_params.emplace_back(Operand::Int(unstripped_result_type_id));
+        spirv_params.emplace_back(unstripped_result);
+      } else {
+        append_result_type_and_id_to_spirv_params();
+      }
+
+      spirv_params.emplace_back(gen_param(pidx.texture));
+      if (pidx.level != kNotUsed) {
+        op = spv::Op::OpImageQuerySizeLod;
+        spirv_params.emplace_back(gen_param(pidx.level));
+      } else {
+        op = spv::Op::OpImageQuerySize;
+      }
+      break;
+    }
     case ast::Intrinsic::kTextureLoad: {
       op = texture_type->Is<ast::type::StorageTexture>()
                ? spv::Op::OpImageRead
                : spv::Op::OpImageFetch;
+      append_result_type_and_id_to_spirv_params();
       spirv_params.emplace_back(gen_param(pidx.texture));
       if (!append_coords_to_spirv_params()) {
         return false;
@@ -2094,6 +2159,7 @@
     }
     case ast::Intrinsic::kTextureSample: {
       op = spv::Op::OpImageSampleImplicitLod;
+      append_result_type_and_id_to_spirv_params();
       if (!append_image_and_coords_to_spirv_params()) {
         return false;
       }
@@ -2101,6 +2167,7 @@
     }
     case ast::Intrinsic::kTextureSampleBias: {
       op = spv::Op::OpImageSampleImplicitLod;
+      append_result_type_and_id_to_spirv_params();
       if (!append_image_and_coords_to_spirv_params()) {
         return false;
       }
@@ -2111,6 +2178,7 @@
     }
     case ast::Intrinsic::kTextureSampleLevel: {
       op = spv::Op::OpImageSampleExplicitLod;
+      append_result_type_and_id_to_spirv_params();
       if (!append_image_and_coords_to_spirv_params()) {
         return false;
       }
@@ -2121,6 +2189,7 @@
     }
     case ast::Intrinsic::kTextureSampleGrad: {
       op = spv::Op::OpImageSampleExplicitLod;
+      append_result_type_and_id_to_spirv_params();
       if (!append_image_and_coords_to_spirv_params()) {
         return false;
       }
@@ -2134,6 +2203,7 @@
     }
     case ast::Intrinsic::kTextureSampleCompare: {
       op = spv::Op::OpImageSampleDrefExplicitLod;
+      append_result_type_and_id_to_spirv_params();
       if (!append_image_and_coords_to_spirv_params()) {
         return false;
       }
@@ -2175,7 +2245,11 @@
     return false;
   }
 
-  return push_function_inst(op, spirv_params);
+  if (!push_function_inst(op, spirv_params)) {
+    return false;
+  }
+
+  return post_emission();
 }
 
 uint32_t Builder::GenerateSampledImage(ast::type::Type* texture_type,
diff --git a/src/writer/spirv/builder_intrinsic_texture_test.cc b/src/writer/spirv/builder_intrinsic_texture_test.cc
index 1651f12..fdc9856 100644
--- a/src/writer/spirv/builder_intrinsic_texture_test.cc
+++ b/src/writer/spirv/builder_intrinsic_texture_test.cc
@@ -34,12 +34,694 @@
 struct expected_texture_overload_spirv {
   std::string types;
   std::string instructions;
+  std::string capabilities;
 };
 
 expected_texture_overload_spirv expected_texture_overload(
     ast::intrinsic::test::ValidTextureOverload overload) {
   using ValidTextureOverload = ast::intrinsic::test::ValidTextureOverload;
   switch (overload) {
+    case ValidTextureOverload::kDimensions1d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeInt 32 1
+)",
+          R"(
+%10 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %10
+)",
+          R"(
+OpCapability Sampled1D
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensions1dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeInt 32 1
+%11 = OpTypeVector %9 2
+)",
+          R"(
+%12 = OpLoad %3 %1
+%10 = OpImageQuerySize %11 %12
+%8 = OpCompositeExtract %9 %10 0
+)",
+          R"(
+OpCapability Sampled1D
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensions2d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensions2dLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpConstant %10 1
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySizeLod %9 %11 %12
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensions2dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpTypeVector %10 3
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySize %12 %13
+%8 = OpVectorShuffle %9 %11 %11 0 1
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensions2dArrayLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpTypeVector %10 3
+%14 = OpConstant %10 1
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySizeLod %12 %13 %14
+%8 = OpVectorShuffle %9 %11 %11 0 1
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensions3d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensions3dLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 3D 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+%12 = OpConstant %10 1
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySizeLod %9 %11 %12
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsCube:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsCubeLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+%12 = OpConstant %10 1
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySizeLod %9 %11 %12
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsCubeArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+%12 = OpTypeVector %10 4
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySize %12 %13
+%8 = OpVectorShuffle %9 %11 %11 0 1 2
+)",
+          R"(
+OpCapability SampledCubeArray
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsCubeArrayLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+%12 = OpTypeVector %10 4
+%14 = OpConstant %10 1
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySizeLod %12 %13 %14
+%8 = OpVectorShuffle %9 %11 %11 0 1 2
+)",
+          R"(
+OpCapability SampledCubeArray
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsMultisampled_2d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsMultisampled_2dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 1 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpTypeVector %10 3
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySize %12 %13
+%8 = OpVectorShuffle %9 %11 %11 0 1
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepth2d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepth2dLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpConstant %10 1
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySizeLod %9 %11 %12
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepth2dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpTypeVector %10 3
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySize %12 %13
+%8 = OpVectorShuffle %9 %11 %11 0 1
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 1 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpTypeVector %10 3
+%14 = OpConstant %10 1
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySizeLod %12 %13 %14
+%8 = OpVectorShuffle %9 %11 %11 0 1
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepthCube:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 1 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepthCubeLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 1 0 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+%12 = OpConstant %10 1
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySizeLod %9 %11 %12
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepthCubeArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 1 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+%12 = OpTypeVector %10 4
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySize %12 %13
+%8 = OpVectorShuffle %9 %11 %11 0 1 2
+)",
+          R"(
+OpCapability SampledCubeArray
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 Cube 1 1 0 1 Unknown
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+%12 = OpTypeVector %10 4
+%14 = OpConstant %10 1
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySizeLod %12 %13 %14
+%8 = OpVectorShuffle %9 %11 %11 0 1 2
+)",
+          R"(
+OpCapability SampledCubeArray
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageRO1d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeInt 32 1
+)",
+          R"(
+%10 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %10
+)",
+          R"(
+OpCapability Image1D
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageRO1dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 1 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeInt 32 1
+%11 = OpTypeVector %9 2
+)",
+          R"(
+%12 = OpLoad %3 %1
+%10 = OpImageQuerySize %11 %12
+%8 = OpCompositeExtract %9 %10 0
+)",
+          R"(
+OpCapability Image1D
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageRO2d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageRO2dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpTypeVector %10 3
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySize %12 %13
+%8 = OpVectorShuffle %9 %11 %11 0 1
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageRO3d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 3D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageWO1d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeInt 32 1
+)",
+          R"(
+%10 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %10
+)",
+          R"(
+OpCapability Image1D
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageWO1dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 1D 0 1 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%9 = OpTypeInt 32 1
+%11 = OpTypeVector %9 2
+)",
+          R"(
+%12 = OpLoad %3 %1
+%10 = OpImageQuerySize %11 %12
+%8 = OpCompositeExtract %9 %10 0
+)",
+          R"(
+OpCapability Image1D
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageWO2d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageWO2dArray:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 2
+%12 = OpTypeVector %10 3
+)",
+          R"(
+%13 = OpLoad %3 %1
+%11 = OpImageQuerySize %12 %13
+%8 = OpVectorShuffle %9 %11 %11 0 1
+)",
+          R"(
+OpCapability ImageQuery
+)"};
+    case ValidTextureOverload::kDimensionsStorageWO3d:
+      return {
+          R"(
+%4 = OpTypeFloat 32
+%3 = OpTypeImage %4 3D 0 0 0 2 Rgba32f
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%7 = OpTypeSampler
+%6 = OpTypePointer Private %7
+%5 = OpVariable %6 Private
+%10 = OpTypeInt 32 1
+%9 = OpTypeVector %10 3
+)",
+          R"(
+%11 = OpLoad %3 %1
+%8 = OpImageQuerySize %9 %11
+)",
+          R"(
+OpCapability ImageQuery
+)"};
     case ValidTextureOverload::kSample1dF32:
       return {
           R"(
@@ -59,6 +741,9 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %14
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kSample1dArrayF32:
       return {
@@ -84,6 +769,9 @@
 %16 = OpConvertSToF %4 %18
 %19 = OpCompositeConstruct %14 %15 %16
 %8 = OpImageSampleImplicitLod %9 %13 %19
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kSample2dF32:
       return {
@@ -107,6 +795,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSample2dOffsetF32:
       return {
@@ -135,6 +825,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17 Offset %22
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSample2dArrayF32:
       return {
@@ -161,6 +853,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSample2dArrayOffsetF32:
       return {
@@ -191,6 +885,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 Offset %24
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSample3dF32:
       return {
@@ -215,6 +911,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSample3dOffsetF32:
       return {
@@ -245,6 +943,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 Offset %24
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleCubeF32:
       return {
@@ -269,6 +969,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleCubeArrayF32:
       return {
@@ -295,6 +997,9 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20
+)",
+          R"(
+OpCapability SampledCubeArray
 )"};
     case ValidTextureOverload::kSampleDepth2dF32:
       return {
@@ -317,6 +1022,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleImplicitLod %4 %12 %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleDepth2dOffsetF32:
       return {
@@ -344,6 +1051,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleImplicitLod %4 %12 %16 Offset %21
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleDepth2dArrayF32:
       return {
@@ -369,6 +1078,8 @@
 %16 = OpConvertSToF %4 %18
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleImplicitLod %4 %12 %19
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
       return {
@@ -398,6 +1109,8 @@
 %16 = OpConvertSToF %4 %18
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleImplicitLod %4 %12 %19 Offset %23
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleDepthCubeF32:
       return {
@@ -421,6 +1134,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleImplicitLod %4 %12 %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleDepthCubeArrayF32:
       return {
@@ -447,6 +1162,9 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %13 %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %4 %12 %20
+)",
+          R"(
+OpCapability SampledCubeArray
 )"};
     case ValidTextureOverload::kSampleBias2dF32:
       return {
@@ -471,6 +1189,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17 Bias %18
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleBias2dOffsetF32:
       return {
@@ -500,6 +1220,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17 Bias|Offset %18 %23
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleBias2dArrayF32:
       return {
@@ -527,6 +1249,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 Bias %21
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
       return {
@@ -558,6 +1282,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 Bias|Offset %21 %25
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleBias3dF32:
       return {
@@ -583,6 +1309,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 Bias %19
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleBias3dOffsetF32:
       return {
@@ -614,6 +1342,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 Bias|Offset %19 %25
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleBiasCubeF32:
       return {
@@ -639,6 +1369,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 Bias %19
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleBiasCubeArrayF32:
       return {
@@ -666,6 +1398,9 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 Bias %21
+)",
+          R"(
+OpCapability SampledCubeArray
 )"};
     case ValidTextureOverload::kSampleLevel2dF32:
       return {
@@ -690,6 +1425,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Lod %18
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevel2dOffsetF32:
       return {
@@ -719,6 +1456,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Lod|Offset %18 %23
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevel2dArrayF32:
       return {
@@ -746,6 +1485,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Lod %21
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
       return {
@@ -777,6 +1518,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Lod|Offset %21 %25
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevel3dF32:
       return {
@@ -802,6 +1545,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Lod %19
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevel3dOffsetF32:
       return {
@@ -833,6 +1578,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Lod|Offset %19 %25
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevelCubeF32:
       return {
@@ -858,6 +1605,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Lod %19
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevelCubeArrayF32:
       return {
@@ -885,6 +1634,9 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Lod %21
+)",
+          R"(
+OpCapability SampledCubeArray
 )"};
     case ValidTextureOverload::kSampleLevelDepth2dF32:
       return {
@@ -909,6 +1661,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleExplicitLod %4 %12 %16 Lod %18
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
       return {
@@ -937,6 +1691,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleExplicitLod %4 %12 %16 Lod|Offset %18 %22
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
       return {
@@ -963,6 +1719,8 @@
 %16 = OpConvertSToF %4 %18
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleExplicitLod %4 %12 %19 Lod %20
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
       return {
@@ -993,6 +1751,8 @@
 %16 = OpConvertSToF %4 %18
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleExplicitLod %4 %12 %19 Lod|Offset %20 %24
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevelDepthCubeF32:
       return {
@@ -1018,6 +1778,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleExplicitLod %4 %12 %17 Lod %19
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
       return {
@@ -1045,6 +1807,9 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %13 %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %4 %12 %20 Lod %21
+)",
+          R"(
+OpCapability SampledCubeArray
 )"};
     case ValidTextureOverload::kSampleGrad2dF32:
       return {
@@ -1074,6 +1839,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Grad %20 %23
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGrad2dOffsetF32:
       return {
@@ -1108,6 +1875,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Grad|Offset %20 %23 %28
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGrad2dArrayF32:
       return {
@@ -1141,6 +1910,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Grad %24 %27
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
       return {
@@ -1178,6 +1949,8 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Grad|Offset %24 %27 %31
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGrad3dF32:
       return {
@@ -1210,6 +1983,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Grad %22 %26
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGrad3dOffsetF32:
       return {
@@ -1248,6 +2023,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Grad|Offset %22 %26 %32
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGradCubeF32:
       return {
@@ -1280,6 +2057,8 @@
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Grad %22 %26
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGradCubeArrayF32:
       return {
@@ -1315,6 +2094,9 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Grad %25 %29
+)",
+          R"(
+OpCapability SampledCubeArray
 )"};
     case ValidTextureOverload::kSampleGradDepth2dF32:
       return {
@@ -1339,6 +2121,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefExplicitLod %4 %12 %16 %17 Lod %18
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGradDepth2dOffsetF32:
       return {
@@ -1368,6 +2152,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefExplicitLod %4 %12 %16 %17 Lod|Offset %18 %23
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGradDepth2dArrayF32:
       return {
@@ -1395,6 +2181,8 @@
 %16 = OpConvertSToF %4 %18
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleDrefExplicitLod %4 %12 %19 %20 Lod %21
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGradDepth2dArrayOffsetF32:
       return {
@@ -1426,6 +2214,8 @@
 %16 = OpConvertSToF %4 %18
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleDrefExplicitLod %4 %12 %19 %20 Lod|Offset %21 %25
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGradDepthCubeF32:
       return {
@@ -1451,6 +2241,8 @@
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefExplicitLod %4 %12 %17 %18 Lod %19
+)",
+          R"(
 )"};
     case ValidTextureOverload::kSampleGradDepthCubeArrayF32:
       return {
@@ -1479,9 +2271,13 @@
 %17 = OpConvertSToF %4 %19
 %20 = OpCompositeConstruct %13 %14 %15 %16 %17
 %8 = OpImageSampleDrefExplicitLod %4 %12 %20 %21 Lod %22
+)",
+          R"(
+OpCapability SampledCubeArray
 )"};
     case ValidTextureOverload::kLoad1dF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1493,12 +2289,16 @@
 %11 = OpTypeInt 32 1
 %12 = OpConstant %11 1
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %12
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kLoad1dU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1510,12 +2310,16 @@
 %11 = OpTypeInt 32 1
 %12 = OpConstant %11 1
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %12
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kLoad1dI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1526,12 +2330,16 @@
 %9 = OpTypeVector %4 4
 %11 = OpConstant %4 1
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %11
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kLoad1dArrayF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1546,12 +2354,16 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kLoad1dArrayU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 1D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1566,12 +2378,16 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kLoad1dArrayI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 1D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1585,12 +2401,16 @@
 %13 = OpConstant %4 2
 %14 = OpConstantComposite %11 %12 %13
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %14
+)",
+          R"(
+OpCapability Sampled1D
 )"};
     case ValidTextureOverload::kLoad2dF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1605,12 +2425,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1625,12 +2448,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1644,12 +2470,15 @@
 %13 = OpConstant %4 2
 %14 = OpConstantComposite %11 %12 %13
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %14
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dLevelF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1665,12 +2494,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dLevelU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1686,12 +2518,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dLevelI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1706,12 +2541,15 @@
 %14 = OpConstantComposite %11 %12 %13
 %15 = OpConstant %4 3
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %14 Lod %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dArrayF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1727,12 +2565,15 @@
 %15 = OpConstant %12 3
 %16 = OpConstantComposite %11 %13 %14 %15
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dArrayU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1748,12 +2589,15 @@
 %15 = OpConstant %12 3
 %16 = OpConstantComposite %11 %13 %14 %15
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dArrayI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1768,12 +2612,15 @@
 %14 = OpConstant %4 3
 %15 = OpConstantComposite %11 %12 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dArrayLevelF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1790,12 +2637,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dArrayLevelU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1812,12 +2662,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad2dArrayLevelI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1833,12 +2686,15 @@
 %15 = OpConstantComposite %11 %12 %13 %14
 %16 = OpConstant %4 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad3dF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1854,12 +2710,15 @@
 %15 = OpConstant %12 3
 %16 = OpConstantComposite %11 %13 %14 %15
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad3dU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1875,12 +2734,15 @@
 %15 = OpConstant %12 3
 %16 = OpConstantComposite %11 %13 %14 %15
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad3dI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1895,12 +2757,15 @@
 %14 = OpConstant %4 3
 %15 = OpConstantComposite %11 %12 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad3dLevelF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1917,12 +2782,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad3dLevelU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1939,12 +2807,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoad3dLevelI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1960,12 +2831,15 @@
 %15 = OpConstantComposite %11 %12 %13 %14
 %16 = OpConstant %4 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadMultisampled2dF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer Private %3
@@ -1981,12 +2855,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Sample %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadMultisampled2dU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2002,12 +2879,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Sample %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadMultisampled2dI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2022,12 +2902,15 @@
 %14 = OpConstantComposite %11 %12 %13
 %15 = OpConstant %4 3
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %14 Sample %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadMultisampled2dArrayF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 1 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2044,12 +2927,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Sample %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadMultisampled2dArrayU32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 1 1 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2066,12 +2952,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Sample %17
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadMultisampled2dArrayI32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 1 1 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2087,12 +2976,15 @@
 %15 = OpConstantComposite %11 %12 %13 %14
 %16 = OpConstant %4 4
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Sample %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadDepth2dF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 1 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2106,12 +2998,15 @@
 %13 = OpConstant %11 2
 %14 = OpConstantComposite %10 %12 %13
 )",
-              R"(
+          R"(
 %9 = OpLoad %3 %1
 %8 = OpImageFetch %4 %9 %14
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadDepth2dLevelF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 1 0 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2126,12 +3021,15 @@
 %14 = OpConstantComposite %10 %12 %13
 %15 = OpConstant %11 3
 )",
-              R"(
+          R"(
 %9 = OpLoad %3 %1
 %8 = OpImageFetch %4 %9 %14 Lod %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadDepth2dArrayF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 1 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2146,12 +3044,15 @@
 %14 = OpConstant %11 3
 %15 = OpConstantComposite %10 %12 %13 %14
 )",
-              R"(
+          R"(
 %9 = OpLoad %3 %1
 %8 = OpImageFetch %4 %9 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 1 1 0 1 Unknown
 %2 = OpTypePointer Private %3
@@ -2167,12 +3068,15 @@
 %15 = OpConstantComposite %10 %12 %13 %14
 %16 = OpConstant %11 4
 )",
-              R"(
+          R"(
 %9 = OpLoad %3 %1
 %8 = OpImageFetch %4 %9 %15 Lod %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO1dRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2184,12 +3088,16 @@
 %11 = OpTypeInt 32 1
 %12 = OpConstant %11 1
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %12
+)",
+          R"(
+OpCapability Image1D
 )"};
     case ValidTextureOverload::kLoadStorageRO1dArrayRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 1 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2204,12 +3112,16 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
+OpCapability Image1D
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba8unorm:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba8
 %2 = OpTypePointer Private %3
@@ -2224,12 +3136,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba8snorm:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba8Snorm
 %2 = OpTypePointer Private %3
@@ -2244,12 +3159,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba8uint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba8ui
 %2 = OpTypePointer Private %3
@@ -2264,12 +3182,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba8sint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba8i
 %2 = OpTypePointer Private %3
@@ -2283,12 +3204,15 @@
 %13 = OpConstant %4 2
 %14 = OpConstantComposite %11 %12 %13
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %14
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba16uint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba16ui
 %2 = OpTypePointer Private %3
@@ -2303,12 +3227,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba16sint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba16i
 %2 = OpTypePointer Private %3
@@ -2322,12 +3249,15 @@
 %13 = OpConstant %4 2
 %14 = OpConstantComposite %11 %12 %13
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %14
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba16float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba16f
 %2 = OpTypePointer Private %3
@@ -2342,12 +3272,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dR32uint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 2 R32ui
 %2 = OpTypePointer Private %3
@@ -2362,12 +3295,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dR32sint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 2 R32i
 %2 = OpTypePointer Private %3
@@ -2381,12 +3317,15 @@
 %13 = OpConstant %4 2
 %14 = OpConstantComposite %11 %12 %13
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %14
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dR32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 R32f
 %2 = OpTypePointer Private %3
@@ -2401,12 +3340,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRg32uint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 2 Rg32ui
 %2 = OpTypePointer Private %3
@@ -2421,12 +3363,16 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
+OpCapability StorageImageExtendedFormats
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRg32sint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 2 Rg32i
 %2 = OpTypePointer Private %3
@@ -2440,12 +3386,16 @@
 %13 = OpConstant %4 2
 %14 = OpConstantComposite %11 %12 %13
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %14
+)",
+          R"(
+OpCapability StorageImageExtendedFormats
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRg32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rg32f
 %2 = OpTypePointer Private %3
@@ -2460,12 +3410,16 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
+OpCapability StorageImageExtendedFormats
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba32uint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba32ui
 %2 = OpTypePointer Private %3
@@ -2480,12 +3434,15 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba32sint:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba32i
 %2 = OpTypePointer Private %3
@@ -2499,12 +3456,15 @@
 %13 = OpConstant %4 2
 %14 = OpConstantComposite %11 %12 %13
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %14
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2519,13 +3479,16 @@
 %14 = OpConstant %12 2
 %15 = OpConstantComposite %11 %13 %14
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %15
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO2dArrayRgba32float:
 
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2541,12 +3504,15 @@
 %15 = OpConstant %12 3
 %16 = OpConstantComposite %11 %13 %14 %15
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kLoadStorageRO3dRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2562,12 +3528,15 @@
 %15 = OpConstant %12 3
 %16 = OpConstantComposite %11 %13 %14 %15
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 %8 = OpImageRead %9 %10 %16
+)",
+          R"(
 )"};
     case ValidTextureOverload::kStoreWO1dRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2585,12 +3554,16 @@
 %17 = OpConstant %4 5
 %18 = OpConstantComposite %13 %14 %15 %16 %17
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %12 %18
+)",
+          R"(
+OpCapability Image1D
 )"};
     case ValidTextureOverload::kStoreWO1dArrayRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 1 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2611,12 +3584,16 @@
 %20 = OpConstant %4 6
 %21 = OpConstantComposite %16 %17 %18 %19 %20
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %15 %21
+)",
+          R"(
+OpCapability Image1D
 )"};
     case ValidTextureOverload::kStoreWO2dRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2637,12 +3614,15 @@
 %20 = OpConstant %4 6
 %21 = OpConstantComposite %16 %17 %18 %19 %20
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %15 %21
+)",
+          R"(
 )"};
     case ValidTextureOverload::kStoreWO2dArrayRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2664,12 +3644,15 @@
 %21 = OpConstant %4 7
 %22 = OpConstantComposite %17 %18 %19 %20 %21
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %16 %22
+)",
+          R"(
 )"};
     case ValidTextureOverload::kStoreWO3dRgba32float:
-      return {R"(
+      return {
+          R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 2 Rgba32f
 %2 = OpTypePointer Private %3
@@ -2691,13 +3674,16 @@
 %21 = OpConstant %4 7
 %22 = OpConstantComposite %17 %18 %19 %20 %21
 )",
-              R"(
+          R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %16 %22
+)",
+          R"(
 )"};
   }
 
-  return {"<unmatched texture overload>", "<unmatched texture overload>"};
+  return {"<unmatched texture overload>", "<unmatched texture overload>",
+          "<unmatched texture overload>"};
 }  // NOLINT - Ignore the length of this function
 
 class IntrinsicTextureTest
@@ -2741,6 +3727,7 @@
   EXPECT_EQ(expected.types, "\n" + DumpInstructions(b.types()));
   EXPECT_EQ(expected.instructions,
             "\n" + DumpInstructions(b.functions()[0].instructions()));
+  EXPECT_EQ(expected.capabilities, "\n" + DumpInstructions(b.capabilities()));
 }
 
 TEST_P(IntrinsicTextureTest, OutsideFunction_IsError) {