[inspector] Add Multisampled Texture data extraction

BUG=tint:257

Change-Id: I3feff89822762014e12e098f00474484139f83c9
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32382
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/ast/function.cc b/src/ast/function.cc
index 1c4d948..d910290 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -180,32 +180,12 @@
 
 const std::vector<std::pair<Variable*, Function::BindingInfo>>
 Function::referenced_sampled_texture_variables() const {
-  std::vector<std::pair<Variable*, Function::BindingInfo>> ret;
+  return ReferencedSampledTextureVariablesImpl(false);
+}
 
-  for (auto* var : referenced_module_variables()) {
-    auto* unwrapped_type = var->type()->UnwrapIfNeeded();
-    if (!var->IsDecorated() || !unwrapped_type->IsTexture() ||
-        !unwrapped_type->AsTexture()->IsSampled()) {
-      continue;
-    }
-
-    BindingDecoration* binding = nullptr;
-    SetDecoration* set = nullptr;
-    for (const auto& deco : var->AsDecorated()->decorations()) {
-      if (deco->IsBinding()) {
-        binding = deco->AsBinding();
-      } else if (deco->IsSet()) {
-        set = deco->AsSet();
-      }
-    }
-    if (binding == nullptr || set == nullptr) {
-      continue;
-    }
-
-    ret.push_back({var, BindingInfo{binding, set}});
-  }
-
-  return ret;
+const std::vector<std::pair<Variable*, Function::BindingInfo>>
+Function::referenced_multisampled_texture_variables() const {
+  return ReferencedSampledTextureVariablesImpl(true);
 }
 
 void Function::add_ancestor_entry_point(const std::string& ep) {
@@ -323,5 +303,39 @@
   return ret;
 }
 
+const std::vector<std::pair<Variable*, Function::BindingInfo>>
+Function::ReferencedSampledTextureVariablesImpl(bool multisampled) const {
+  std::vector<std::pair<Variable*, Function::BindingInfo>> ret;
+
+  for (auto* var : referenced_module_variables()) {
+    auto* unwrapped_type = var->type()->UnwrapIfNeeded();
+    if (!var->IsDecorated() || !unwrapped_type->IsTexture()) {
+      continue;
+    }
+
+    if ((multisampled && !unwrapped_type->AsTexture()->IsMultisampled()) ||
+        (!multisampled && !unwrapped_type->AsTexture()->IsSampled())) {
+      continue;
+    }
+
+    BindingDecoration* binding = nullptr;
+    SetDecoration* set = nullptr;
+    for (const auto& deco : var->AsDecorated()->decorations()) {
+      if (deco->IsBinding()) {
+        binding = deco->AsBinding();
+      } else if (deco->IsSet()) {
+        set = deco->AsSet();
+      }
+    }
+    if (binding == nullptr || set == nullptr) {
+      continue;
+    }
+
+    ret.push_back({var, BindingInfo{binding, set}});
+  }
+
+  return ret;
+}
+
 }  // namespace ast
 }  // namespace tint
diff --git a/src/ast/function.h b/src/ast/function.h
index 8ed17c7..2dbeab4 100644
--- a/src/ast/function.h
+++ b/src/ast/function.h
@@ -154,6 +154,11 @@
   /// @returns the referenced sampled textures
   const std::vector<std::pair<Variable*, Function::BindingInfo>>
   referenced_sampled_texture_variables() const;
+  /// Retrieves any referenced multisampled textures variables. Note, the
+  /// variables must be decorated with both binding and set decorations.
+  /// @returns the referenced sampled textures
+  const std::vector<std::pair<Variable*, Function::BindingInfo>>
+  referenced_multisampled_texture_variables() const;
 
   /// Adds an ancestor entry point
   /// @param ep the entry point ancestor
@@ -201,6 +206,8 @@
   Function(const Function&) = delete;
   const std::vector<std::pair<Variable*, Function::BindingInfo>>
   ReferencedSamplerVariablesImpl(type::SamplerKind kind) const;
+  const std::vector<std::pair<Variable*, Function::BindingInfo>>
+  ReferencedSampledTextureVariablesImpl(bool multisampled) const;
 
   std::string name_;
   VariableList params_;
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index 151a199..5f4936e 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -27,9 +27,14 @@
 #include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/sint_literal.h"
 #include "src/ast/type/access_control_type.h"
+#include "src/ast/type/array_type.h"
+#include "src/ast/type/matrix_type.h"
+#include "src/ast/type/multisampled_texture_type.h"
+#include "src/ast/type/sampled_texture_type.h"
 #include "src/ast/type/struct_type.h"
 #include "src/ast/type/texture_type.h"
 #include "src/ast/type/type.h"
+#include "src/ast/type/vector_type.h"
 #include "src/ast/uint_literal.h"
 #include "src/namer.h"
 
@@ -253,52 +258,12 @@
 
 std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindings(
     const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
+  return GetSampledTextureResourceBindingsImpl(entry_point, false);
+}
 
-  std::vector<ResourceBinding> result;
-
-  for (auto& rcs : func->referenced_sampled_texture_variables()) {
-    ResourceBinding entry;
-    ast::Variable* var = nullptr;
-    ast::Function::BindingInfo binding_info;
-    std::tie(var, binding_info) = rcs;
-
-    entry.bind_group = binding_info.set->value();
-    entry.binding = binding_info.binding->value();
-
-    switch (var->type()->UnwrapIfNeeded()->AsTexture()->dim()) {
-      case ast::type::TextureDimension::k1d:
-        entry.dim = ResourceBinding::TextureDimension::k1d;
-        break;
-      case ast::type::TextureDimension::k1dArray:
-        entry.dim = ResourceBinding::TextureDimension::k1dArray;
-        break;
-      case ast::type::TextureDimension::k2d:
-        entry.dim = ResourceBinding::TextureDimension::k2d;
-        break;
-      case ast::type::TextureDimension::k2dArray:
-        entry.dim = ResourceBinding::TextureDimension::k2dArray;
-        break;
-      case ast::type::TextureDimension::k3d:
-        entry.dim = ResourceBinding::TextureDimension::k3d;
-        break;
-      case ast::type::TextureDimension::kCube:
-        entry.dim = ResourceBinding::TextureDimension::kCube;
-        break;
-      case ast::type::TextureDimension::kCubeArray:
-        entry.dim = ResourceBinding::TextureDimension::kCubeArray;
-        break;
-      default:
-        entry.dim = ResourceBinding::TextureDimension::kNone;
-        break;
-    }
-    result.push_back(std::move(entry));
-  }
-
-  return result;
+std::vector<ResourceBinding> Inspector::GetMultisampledTextureResourceBindings(
+    const std::string& entry_point) {
+  return GetSampledTextureResourceBindingsImpl(entry_point, true);
 }
 
 ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
@@ -354,5 +319,85 @@
   return result;
 }
 
+std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
+    const std::string& entry_point,
+    bool multisampled_only) {
+  auto* func = FindEntryPointByName(entry_point);
+  if (!func) {
+    return {};
+  }
+
+  std::vector<ResourceBinding> result;
+  auto& referenced_variables =
+      multisampled_only ? func->referenced_multisampled_texture_variables()
+                        : func->referenced_sampled_texture_variables();
+  for (auto& ref : referenced_variables) {
+    ResourceBinding entry;
+    ast::Variable* var = nullptr;
+    ast::Function::BindingInfo binding_info;
+    std::tie(var, binding_info) = ref;
+
+    entry.bind_group = binding_info.set->value();
+    entry.binding = binding_info.binding->value();
+
+    auto* texture_type = var->type()->UnwrapIfNeeded()->AsTexture();
+    switch (texture_type->dim()) {
+      case ast::type::TextureDimension::k1d:
+        entry.dim = ResourceBinding::TextureDimension::k1d;
+        break;
+      case ast::type::TextureDimension::k1dArray:
+        entry.dim = ResourceBinding::TextureDimension::k1dArray;
+        break;
+      case ast::type::TextureDimension::k2d:
+        entry.dim = ResourceBinding::TextureDimension::k2d;
+        break;
+      case ast::type::TextureDimension::k2dArray:
+        entry.dim = ResourceBinding::TextureDimension::k2dArray;
+        break;
+      case ast::type::TextureDimension::k3d:
+        entry.dim = ResourceBinding::TextureDimension::k3d;
+        break;
+      case ast::type::TextureDimension::kCube:
+        entry.dim = ResourceBinding::TextureDimension::kCube;
+        break;
+      case ast::type::TextureDimension::kCubeArray:
+        entry.dim = ResourceBinding::TextureDimension::kCubeArray;
+        break;
+      default:
+        entry.dim = ResourceBinding::TextureDimension::kNone;
+        break;
+    }
+
+    ast::type::Type* base_type = nullptr;
+    if (multisampled_only) {
+      base_type = texture_type->AsMultisampled()->type()->UnwrapIfNeeded();
+    } else {
+      base_type = texture_type->AsSampled()->type()->UnwrapIfNeeded();
+    }
+
+    if (base_type->IsArray()) {
+      base_type = base_type->AsArray()->type();
+    } else if (base_type->IsMatrix()) {
+      base_type = base_type->AsMatrix()->type();
+    } else if (base_type->IsVector()) {
+      base_type = base_type->AsVector()->type();
+    }
+
+    if (base_type->IsF32()) {
+      entry.sampled_kind = ResourceBinding::SampledKind::kFloat;
+    } else if (base_type->IsU32()) {
+      entry.sampled_kind = ResourceBinding::SampledKind::kUInt;
+    } else if (base_type->IsI32()) {
+      entry.sampled_kind = ResourceBinding::SampledKind::kSInt;
+    } else {
+      entry.sampled_kind = ResourceBinding::SampledKind::kUnknown;
+    }
+
+    result.push_back(std::move(entry));
+  }
+
+  return result;
+}
+
 }  // namespace inspector
 }  // namespace tint
diff --git a/src/inspector/inspector.h b/src/inspector/inspector.h
index b2b6573..01d0f73 100644
--- a/src/inspector/inspector.h
+++ b/src/inspector/inspector.h
@@ -52,6 +52,10 @@
     kCubeArray,
   };
 
+  /// Component type of the texture's data. Same as the Sampled Type parameter
+  /// in SPIR-V OpTypeImage.
+  enum class SampledKind { kUnknown = -1, kFloat, kUInt, kSInt };
+
   /// Bind group the binding belongs
   uint32_t bind_group;
   /// Identifier to identify this binding within the bind group
@@ -60,6 +64,8 @@
   uint64_t min_buffer_binding_size;
   /// Dimensionality of this binding, if defined.
   TextureDimension dim;
+  /// Kind of data being sampled, if defined.
+  SampledKind sampled_kind;
 };
 
 /// Extracts information from a module
@@ -116,6 +122,11 @@
   std::vector<ResourceBinding> GetSampledTextureResourceBindings(
       const std::string& entry_point);
 
+  /// @param entry_point name of the entry point to get information about.
+  /// @returns vector of all of the bindings for multisampled textures.
+  std::vector<ResourceBinding> GetMultisampledTextureResourceBindings(
+      const std::string& entry_point);
+
  private:
   const ast::Module& module_;
   std::string error_;
@@ -133,6 +144,14 @@
   std::vector<ResourceBinding> GetStorageBufferResourceBindingsImpl(
       const std::string& entry_point,
       bool read_only);
+
+  /// @param entry_point name of the entry point to get information about.
+  /// @param multisampled_only only get multisampled textures if true, otherwise
+  ///                          only get sampled textures.
+  /// @returns vector of all of the bindings for the request storage buffers.
+  std::vector<ResourceBinding> GetSampledTextureResourceBindingsImpl(
+      const std::string& entry_point,
+      bool multisampled_only);
 };
 
 }  // namespace inspector
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index 19bad67..9a1a4aa 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -46,6 +46,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/matrix_type.h"
+#include "src/ast/type/multisampled_texture_type.h"
 #include "src/ast/type/pointer_type.h"
 #include "src/ast/type/sampled_texture_type.h"
 #include "src/ast/type/sampler_type.h"
@@ -463,6 +464,16 @@
     return std::make_unique<ast::type::DepthTextureType>(dim);
   }
 
+  /// Generates a MultisampledTextureType appropriate for the params
+  /// @param dim the dimensions of the texture
+  /// @param type the data type of the sampled texture
+  /// @returns the generated SampleTextureType
+  std::unique_ptr<ast::type::MultisampledTextureType>
+  MakeMultisampledTextureType(ast::type::TextureDimension dim,
+                              ast::type::Type* type) {
+    return std::make_unique<ast::type::MultisampledTextureType>(dim, type);
+  }
+
   /// Adds a sampled texture variable to the module
   /// @param name the name of the variable
   /// @param type the type to use
@@ -475,9 +486,21 @@
     AddBinding(name, type, ast::StorageClass::kUniformConstant, set, binding);
   }
 
-  void AddF32(const std::string& name) {
+  /// Adds a multi-sampled texture variable to the module
+  /// @param name the name of the variable
+  /// @param type the type to use
+  /// @param set the binding group/set to use for the multi-sampled texture
+  /// @param binding the binding number to use for the multi-sampled texture
+  void AddMultisampledTexture(const std::string& name,
+                              ast::type::Type* type,
+                              uint32_t set,
+                              uint32_t binding) {
+    AddBinding(name, type, ast::StorageClass::kUniformConstant, set, binding);
+  }
+
+  void AddGlobalVariable(const std::string& name, ast::type::Type* type) {
     mod()->AddGlobalVariable(std::make_unique<ast::Variable>(
-        name, ast::StorageClass::kUniformConstant, f32_type()));
+        name, ast::StorageClass::kUniformConstant, type));
   }
 
   /// Adds a depth texture variable to the module
@@ -498,13 +521,14 @@
       const std::string& func_name,
       const std::string& texture_name,
       const std::string& sampler_name,
-      const std::string& coords_name) {
+      const std::string& coords_name,
+      ast::type::Type* base_type) {
     std::string result_name = "sampler_result";
 
     auto body = std::make_unique<ast::BlockStatement>();
 
     auto call_result = std::make_unique<ast::Variable>(
-        "sampler_result", ast::StorageClass::kFunction, f32_vec_type(4));
+        "sampler_result", ast::StorageClass::kFunction, vec_type(base_type, 4));
     body->append(
         std::make_unique<ast::VariableDeclStatement>(std::move(call_result)));
 
@@ -543,13 +567,14 @@
       const std::string& texture_name,
       const std::string& sampler_name,
       const std::string& coords_name,
-      const std::string& depth_name) {
+      const std::string& depth_name,
+      ast::type::Type* base_type) {
     std::string result_name = "sampler_result";
 
     auto body = std::make_unique<ast::BlockStatement>();
 
     auto call_result = std::make_unique<ast::Variable>(
-        "sampler_result", ast::StorageClass::kFunction, f32_type());
+        "sampler_result", ast::StorageClass::kFunction, base_type);
     body->append(
         std::make_unique<ast::VariableDeclStatement>(std::move(call_result)));
 
@@ -577,20 +602,39 @@
     return func;
   }
 
+  /// Gets an appropriate type for the data in a given texture type.
+  /// @param sampled_kind type of in the texture
+  /// @returns a pointer to a type appropriate for the coord param
+  ast::type::Type* GetBaseType(ResourceBinding::SampledKind sampled_kind) {
+    switch (sampled_kind) {
+      case ResourceBinding::SampledKind::kFloat:
+        return f32_type();
+      case ResourceBinding::SampledKind::kSInt:
+        return i32_type();
+      case ResourceBinding::SampledKind::kUInt:
+        return u32_type();
+      default:
+        return nullptr;
+    }
+  }
+
   /// Gets an appropriate type for the coords parameter depending the the
   /// dimensionality of the texture being sampled.
-  /// @param dim dimensionality of the texture being sampled.
+  /// @param dim dimensionality of the texture being sampled
+  /// @param sampled_kind type of data in the texture
   /// @returns a pointer to a type appropriate for the coord param
-  ast::type::Type* GetCoordsType(ast::type::TextureDimension dim) {
+  ast::type::Type* GetCoordsType(ast::type::TextureDimension dim,
+                                 ResourceBinding::SampledKind sampled_kind) {
+    ast::type::Type* base_type = GetBaseType(sampled_kind);
     if (dim == ast::type::TextureDimension::k1d) {
-      f32_type();
+      return base_type;
     } else if (dim == ast::type::TextureDimension::k1dArray ||
                dim == ast::type::TextureDimension::k2d) {
-      return f32_vec_type(2);
+      return vec_type(base_type, 2);
     } else if (dim == ast::type::TextureDimension::kCubeArray) {
-      return f32_vec_type(4);
+      return vec_type(base_type, 4);
     }
-    return f32_vec_type(3);
+    return vec_type(base_type, 3);
   }
 
   ast::Module* mod() { return &mod_; }
@@ -611,12 +655,13 @@
     }
     return array_type_memo_[count].get();
   }
-  ast::type::VectorType* f32_vec_type(uint32_t count) {
-    if (vector_type_memo_.find(count) == vector_type_memo_.end()) {
-      vector_type_memo_[count] =
+  ast::type::VectorType* vec_type(ast::type::Type* type, uint32_t count) {
+    if (vector_type_memo_.find(std::tie(type, count)) ==
+        vector_type_memo_.end()) {
+      vector_type_memo_[std::tie(type, count)] =
           std::make_unique<ast::type::VectorType>(u32_type(), count);
     }
-    return vector_type_memo_[count].get();
+    return vector_type_memo_[std::tie(type, count)].get();
   }
   ast::type::VoidType* void_type() { return &void_type_; }
   ast::type::SamplerType* sampler_type() { return &sampler_type_; }
@@ -638,7 +683,9 @@
   ast::type::SamplerType sampler_type_;
   ast::type::SamplerType comparison_sampler_type_;
   std::map<uint32_t, std::unique_ptr<ast::type::ArrayType>> array_type_memo_;
-  std::map<uint32_t, std::unique_ptr<ast::type::VectorType>> vector_type_memo_;
+  std::map<std::tuple<ast::type::Type*, uint32_t>,
+           std::unique_ptr<ast::type::VectorType>>
+      vector_type_memo_;
 };
 
 class InspectorGetEntryPointTest : public InspectorHelper,
@@ -659,17 +706,25 @@
 class InspectorGetComparisonSamplerResourceBindingsTest
     : public InspectorHelper,
       public testing::Test {};
-
 class InspectorGetSampledTextureResourceBindingsTest : public InspectorHelper,
                                                        public testing::Test {};
 struct GetSampledTextureTestParams {
   ast::type::TextureDimension type_dim;
   inspector::ResourceBinding::TextureDimension inspector_dim;
+  inspector::ResourceBinding::SampledKind sampled_kind;
 };
 class InspectorGetSampledTextureResourceBindingsTestWithParam
     : public InspectorHelper,
       public testing::TestWithParam<GetSampledTextureTestParams> {};
 
+class InspectorGetMultisampledTextureResourceBindingsTest
+    : public InspectorHelper,
+      public testing::Test {};
+typedef GetSampledTextureTestParams GetMultisampledTextureTestParams;
+class InspectorGetMultisampledTextureResourceBindingsTestWithParam
+    : public InspectorHelper,
+      public testing::TestWithParam<GetMultisampledTextureTestParams> {};
+
 TEST_F(InspectorGetEntryPointTest, NoFunctions) {
   auto result = inspector()->GetEntryPoints();
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -1721,10 +1776,10 @@
       MakeSampledTextureType(ast::type::TextureDimension::k1d, f32_type());
   AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0);
   AddSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
+  AddGlobalVariable("foo_coords", f32_type());
 
-  auto func = MakeSamplerReferenceBodyFunction("ep", "foo_texture",
-                                               "foo_sampler", "foo_coords");
+  auto func = MakeSamplerReferenceBodyFunction(
+      "ep", "foo_texture", "foo_sampler", "foo_coords", f32_type());
   func->add_decoration(std::make_unique<ast::StageDecoration>(
       ast::PipelineStage::kVertex, Source{}));
   mod()->AddFunction(std::move(func));
@@ -1758,10 +1813,10 @@
       MakeSampledTextureType(ast::type::TextureDimension::k1d, f32_type());
   AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0);
   AddSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
+  AddGlobalVariable("foo_coords", f32_type());
 
-  auto foo_func = MakeSamplerReferenceBodyFunction("foo_func", "foo_texture",
-                                                   "foo_sampler", "foo_coords");
+  auto foo_func = MakeSamplerReferenceBodyFunction(
+      "foo_func", "foo_texture", "foo_sampler", "foo_coords", f32_type());
   mod()->AddFunction(std::move(foo_func));
 
   auto ep_func = MakeCallerBodyFunction("ep_func", "foo_func");
@@ -1784,10 +1839,10 @@
       MakeSampledTextureType(ast::type::TextureDimension::k1d, f32_type());
   AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0);
   AddSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
+  AddGlobalVariable("foo_coords", f32_type());
 
-  auto func = MakeSamplerReferenceBodyFunction("ep", "foo_texture",
-                                               "foo_sampler", "foo_coords");
+  auto func = MakeSamplerReferenceBodyFunction(
+      "ep", "foo_texture", "foo_sampler", "foo_coords", f32_type());
   func->add_decoration(std::make_unique<ast::StageDecoration>(
       ast::PipelineStage::kVertex, Source{}));
   mod()->AddFunction(std::move(func));
@@ -1803,11 +1858,12 @@
       MakeDepthTextureType(ast::type::TextureDimension::k2d);
   AddDepthTexture("foo_texture", depth_texture_type.get());
   AddComparisonSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
-  AddF32("foo_depth");
+  AddGlobalVariable("foo_coords", f32_type());
+  AddGlobalVariable("foo_depth", f32_type());
 
   auto func = MakeComparisonSamplerReferenceBodyFunction(
-      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth");
+      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth",
+      f32_type());
   func->add_decoration(std::make_unique<ast::StageDecoration>(
       ast::PipelineStage::kVertex, Source{}));
   mod()->AddFunction(std::move(func));
@@ -1825,11 +1881,12 @@
       MakeDepthTextureType(ast::type::TextureDimension::k2d);
   AddDepthTexture("foo_texture", depth_texture_type.get());
   AddComparisonSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
-  AddF32("foo_depth");
+  AddGlobalVariable("foo_coords", f32_type());
+  AddGlobalVariable("foo_depth", f32_type());
 
   auto func = MakeComparisonSamplerReferenceBodyFunction(
-      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth");
+      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth",
+      f32_type());
   func->add_decoration(std::make_unique<ast::StageDecoration>(
       ast::PipelineStage::kVertex, Source{}));
   mod()->AddFunction(std::move(func));
@@ -1863,11 +1920,12 @@
       MakeDepthTextureType(ast::type::TextureDimension::k2d);
   AddDepthTexture("foo_texture", depth_texture_type.get());
   AddComparisonSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
-  AddF32("foo_depth");
+  AddGlobalVariable("foo_coords", f32_type());
+  AddGlobalVariable("foo_depth", f32_type());
 
   auto foo_func = MakeComparisonSamplerReferenceBodyFunction(
-      "foo_func", "foo_texture", "foo_sampler", "foo_coords", "foo_depth");
+      "foo_func", "foo_texture", "foo_sampler", "foo_coords", "foo_depth",
+      f32_type());
   mod()->AddFunction(std::move(foo_func));
 
   auto ep_func = MakeCallerBodyFunction("ep_func", "foo_func");
@@ -1890,11 +1948,12 @@
       MakeDepthTextureType(ast::type::TextureDimension::k2d);
   AddDepthTexture("foo_texture", depth_texture_type.get());
   AddComparisonSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
-  AddF32("foo_depth");
+  AddGlobalVariable("foo_coords", f32_type());
+  AddGlobalVariable("foo_depth", f32_type());
 
   auto func = MakeComparisonSamplerReferenceBodyFunction(
-      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth");
+      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth",
+      f32_type());
   func->add_decoration(std::make_unique<ast::StageDecoration>(
       ast::PipelineStage::kVertex, Source{}));
   mod()->AddFunction(std::move(func));
@@ -1910,10 +1969,10 @@
       MakeSampledTextureType(ast::type::TextureDimension::k1d, f32_type());
   AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0);
   AddSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
+  AddGlobalVariable("foo_coords", f32_type());
 
-  auto func = MakeSamplerReferenceBodyFunction("ep", "foo_texture",
-                                               "foo_sampler", "foo_coords");
+  auto func = MakeSamplerReferenceBodyFunction(
+      "ep", "foo_texture", "foo_sampler", "foo_coords", f32_type());
   func->add_decoration(std::make_unique<ast::StageDecoration>(
       ast::PipelineStage::kVertex, Source{}));
   mod()->AddFunction(std::move(func));
@@ -1926,16 +1985,30 @@
   ASSERT_EQ(0u, result.size());
 }
 
-TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam, Simple) {
-  auto* coord_type = GetCoordsType(GetParam().type_dim);
-  auto sampled_texture_type =
-      MakeSampledTextureType(GetParam().type_dim, coord_type);
+TEST_F(InspectorGetSampledTextureResourceBindingsTest, Empty) {
+  auto foo = MakeEmptyBodyFunction("foo");
+  foo->add_decoration(std::make_unique<ast::StageDecoration>(
+      ast::PipelineStage::kVertex, Source{}));
+  mod()->AddFunction(std::move(foo));
+
+  auto result = inspector()->GetSampledTextureResourceBindings("foo");
+  ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
+
+  EXPECT_EQ(0u, result.size());
+}
+
+TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam, textureSample) {
+  auto sampled_texture_type = MakeSampledTextureType(
+      GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
   AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0);
   AddSampler("foo_sampler", 0, 1);
-  AddF32("foo_coords");
+  auto* coord_type =
+      GetCoordsType(GetParam().type_dim, GetParam().sampled_kind);
+  AddGlobalVariable("foo_coords", coord_type);
 
-  auto func = MakeSamplerReferenceBodyFunction("ep", "foo_texture",
-                                               "foo_sampler", "foo_coords");
+  auto func = MakeSamplerReferenceBodyFunction(
+      "ep", "foo_texture", "foo_sampler", "foo_coords",
+      GetBaseType(GetParam().sampled_kind));
   func->add_decoration(std::make_unique<ast::StageDecoration>(
       ast::PipelineStage::kVertex, Source{}));
   mod()->AddFunction(std::move(func));
@@ -1949,6 +2022,7 @@
   EXPECT_EQ(0u, result[0].bind_group);
   EXPECT_EQ(0u, result[0].binding);
   EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+  EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -1957,25 +2031,182 @@
     testing::Values(
         GetSampledTextureTestParams{
             ast::type::TextureDimension::k1d,
-            inspector::ResourceBinding::TextureDimension::k1d},
+            inspector::ResourceBinding::TextureDimension::k1d,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k1d,
+            inspector::ResourceBinding::TextureDimension::k1d,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k1d,
+            inspector::ResourceBinding::TextureDimension::k1d,
+            inspector::ResourceBinding::SampledKind::kUInt},
         GetSampledTextureTestParams{
             ast::type::TextureDimension::k1dArray,
-            inspector::ResourceBinding::TextureDimension::k1dArray},
+            inspector::ResourceBinding::TextureDimension::k1dArray,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k1dArray,
+            inspector::ResourceBinding::TextureDimension::k1dArray,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k1dArray,
+            inspector::ResourceBinding::TextureDimension::k1dArray,
+            inspector::ResourceBinding::SampledKind::kUInt},
         GetSampledTextureTestParams{
             ast::type::TextureDimension::k2d,
-            inspector::ResourceBinding::TextureDimension::k2d},
+            inspector::ResourceBinding::TextureDimension::k2d,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k2d,
+            inspector::ResourceBinding::TextureDimension::k2d,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k2d,
+            inspector::ResourceBinding::TextureDimension::k2d,
+            inspector::ResourceBinding::SampledKind::kUInt},
         GetSampledTextureTestParams{
             ast::type::TextureDimension::k2dArray,
-            inspector::ResourceBinding::TextureDimension::k2dArray},
+            inspector::ResourceBinding::TextureDimension::k2dArray,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k2dArray,
+            inspector::ResourceBinding::TextureDimension::k2dArray,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k2dArray,
+            inspector::ResourceBinding::TextureDimension::k2dArray,
+            inspector::ResourceBinding::SampledKind::kUInt},
         GetSampledTextureTestParams{
             ast::type::TextureDimension::k3d,
-            inspector::ResourceBinding::TextureDimension::k3d},
+            inspector::ResourceBinding::TextureDimension::k3d,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k3d,
+            inspector::ResourceBinding::TextureDimension::k3d,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k3d,
+            inspector::ResourceBinding::TextureDimension::k3d,
+            inspector::ResourceBinding::SampledKind::kUInt},
         GetSampledTextureTestParams{
             ast::type::TextureDimension::kCube,
-            inspector::ResourceBinding::TextureDimension::kCube},
+            inspector::ResourceBinding::TextureDimension::kCube,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::kCube,
+            inspector::ResourceBinding::TextureDimension::kCube,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::kCube,
+            inspector::ResourceBinding::TextureDimension::kCube,
+            inspector::ResourceBinding::SampledKind::kUInt},
         GetSampledTextureTestParams{
             ast::type::TextureDimension::kCubeArray,
-            inspector::ResourceBinding::TextureDimension::kCubeArray}));
+            inspector::ResourceBinding::TextureDimension::kCubeArray,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::kCubeArray,
+            inspector::ResourceBinding::TextureDimension::kCubeArray,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::kCubeArray,
+            inspector::ResourceBinding::TextureDimension::kCubeArray,
+            inspector::ResourceBinding::SampledKind::kUInt}));
+
+TEST_F(InspectorGetMultisampledTextureResourceBindingsTest, Empty) {
+  auto foo = MakeEmptyBodyFunction("foo");
+  foo->add_decoration(std::make_unique<ast::StageDecoration>(
+      ast::PipelineStage::kVertex, Source{}));
+  mod()->AddFunction(std::move(foo));
+
+  auto result = inspector()->GetSampledTextureResourceBindings("foo");
+  ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
+
+  EXPECT_EQ(0u, result.size());
+}
+
+TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
+       textureSample) {
+  auto multisampled_texture_type = MakeMultisampledTextureType(
+      GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
+  AddMultisampledTexture("foo_texture", multisampled_texture_type.get(), 0, 0);
+  AddSampler("foo_sampler", 0, 1);
+  auto* coord_type =
+      GetCoordsType(GetParam().type_dim, GetParam().sampled_kind);
+  AddGlobalVariable("foo_coords", coord_type);
+
+  auto func = MakeSamplerReferenceBodyFunction(
+      "ep", "foo_texture", "foo_sampler", "foo_coords",
+      GetBaseType(GetParam().sampled_kind));
+  func->add_decoration(std::make_unique<ast::StageDecoration>(
+      ast::PipelineStage::kVertex, Source{}));
+  mod()->AddFunction(std::move(func));
+
+  ASSERT_TRUE(td()->Determine()) << td()->error();
+
+  auto result = inspector()->GetMultisampledTextureResourceBindings("ep");
+  ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
+
+  ASSERT_EQ(1u, result.size());
+  EXPECT_EQ(0u, result[0].bind_group);
+  EXPECT_EQ(0u, result[0].binding);
+  EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+  EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    InspectorGetMultisampledTextureResourceBindingsTest,
+    InspectorGetMultisampledTextureResourceBindingsTestWithParam,
+    testing::Values(
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k1d,
+            inspector::ResourceBinding::TextureDimension::k1d,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k1d,
+            inspector::ResourceBinding::TextureDimension::k1d,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k1d,
+            inspector::ResourceBinding::TextureDimension::k1d,
+            inspector::ResourceBinding::SampledKind::kUInt},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k1dArray,
+            inspector::ResourceBinding::TextureDimension::k1dArray,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k1dArray,
+            inspector::ResourceBinding::TextureDimension::k1dArray,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k1dArray,
+            inspector::ResourceBinding::TextureDimension::k1dArray,
+            inspector::ResourceBinding::SampledKind::kUInt},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k2d,
+            inspector::ResourceBinding::TextureDimension::k2d,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k2d,
+            inspector::ResourceBinding::TextureDimension::k2d,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k2d,
+            inspector::ResourceBinding::TextureDimension::k2d,
+            inspector::ResourceBinding::SampledKind::kUInt},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k2dArray,
+            inspector::ResourceBinding::TextureDimension::k2dArray,
+            inspector::ResourceBinding::SampledKind::kFloat},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k2dArray,
+            inspector::ResourceBinding::TextureDimension::k2dArray,
+            inspector::ResourceBinding::SampledKind::kSInt},
+        GetMultisampledTextureTestParams{
+            ast::type::TextureDimension::k2dArray,
+            inspector::ResourceBinding::TextureDimension::k2dArray,
+            inspector::ResourceBinding::SampledKind::kUInt}));
 
 }  // namespace
 }  // namespace inspector