[inspector] Extract Sampled Texture data

BUG=tint:257

Change-Id: I146591d052edfc959df33ccf235ea466cb59e59d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32260
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
diff --git a/src/ast/function.cc b/src/ast/function.cc
index a90b085..1c4d948 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -18,6 +18,7 @@
 
 #include "src/ast/decorated_variable.h"
 #include "src/ast/stage_decoration.h"
+#include "src/ast/type/texture_type.h"
 #include "src/ast/workgroup_decoration.h"
 
 namespace tint {
@@ -177,6 +178,36 @@
   return ReferencedSamplerVariablesImpl(type::SamplerKind::kComparisonSampler);
 }
 
+const std::vector<std::pair<Variable*, Function::BindingInfo>>
+Function::referenced_sampled_texture_variables() 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() ||
+        !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;
+}
+
 void Function::add_ancestor_entry_point(const std::string& ep) {
   for (const auto& point : ancestor_entry_points_) {
     if (point == ep) {
diff --git a/src/ast/function.h b/src/ast/function.h
index e07658f..8ed17c7 100644
--- a/src/ast/function.h
+++ b/src/ast/function.h
@@ -129,26 +129,31 @@
   /// @returns the <variable, decoration> pair.
   const std::vector<std::pair<Variable*, BuiltinDecoration*>>
   referenced_builtin_variables() const;
-  /// Retrieves any referenced uniform variables. Note, the uniform must be
+  /// Retrieves any referenced uniform variables. Note, the variables must be
   /// decorated with both binding and set decorations.
   /// @returns the referenced uniforms
   const std::vector<std::pair<Variable*, Function::BindingInfo>>
   referenced_uniform_variables() const;
-  /// Retrieves any referenced storagebuffer variables. Note, the storagebuffer
+  /// Retrieves any referenced storagebuffer variables. Note, the variables
   /// must be decorated with both binding and set decorations.
   /// @returns the referenced storagebuffers
   const std::vector<std::pair<Variable*, Function::BindingInfo>>
   referenced_storagebuffer_variables() const;
   /// Retrieves any referenced regular Sampler variables. Note, the
-  /// storagebuffer must be decorated with both binding and set decorations.
+  /// variables must be decorated with both binding and set decorations.
   /// @returns the referenced storagebuffers
   const std::vector<std::pair<Variable*, Function::BindingInfo>>
   referenced_sampler_variables() const;
   /// Retrieves any referenced comparison Sampler variables. Note, the
-  /// storagebuffer must be decorated with both binding and set decorations.
+  /// variables must be decorated with both binding and set decorations.
   /// @returns the referenced storagebuffers
   const std::vector<std::pair<Variable*, Function::BindingInfo>>
   referenced_comparison_sampler_variables() const;
+  /// Retrieves any referenced sampled 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_sampled_texture_variables() const;
 
   /// Adds an ancestor entry point
   /// @param ep the entry point ancestor
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index ed278af..b170d87 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -28,6 +28,7 @@
 #include "src/ast/sint_literal.h"
 #include "src/ast/type/access_control_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/uint_literal.h"
 #include "src/namer.h"
@@ -237,6 +238,56 @@
   return result;
 }
 
+std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindings(
+    const std::string& entry_point) {
+  auto* func = FindEntryPointByName(entry_point);
+  if (!func) {
+    return {};
+  }
+
+  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;
+}
+
 ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
   auto* func = module_.FindFunctionByName(name);
   if (!func) {
diff --git a/src/inspector/inspector.h b/src/inspector/inspector.h
index 7034a8a..da49ff1 100644
--- a/src/inspector/inspector.h
+++ b/src/inspector/inspector.h
@@ -31,12 +31,34 @@
 
 /// Container for information about how a resource is bound
 struct ResourceBinding {
+  /// The dimensionality of a texture
+  enum class TextureDimension {
+    /// Invalid texture
+    kNone = -1,
+    /// 1 dimensional texture
+    k1d,
+    /// 1 dimenstional array texture
+    k1dArray,
+    /// 2 dimensional texture
+    k2d,
+    /// 2 dimensional array texture
+    k2dArray,
+    /// 3 dimensional texture
+    k3d,
+    /// cube texture
+    kCube,
+    /// cube array texture
+    kCubeArray,
+  };
+
   /// Bind group the binding belongs
   uint32_t bind_group;
   /// Identifier to identify this binding within the bind group
   uint32_t binding;
-  /// Minimum size required for this binding, in bytes.
+  /// Minimum size required for this binding, in bytes, if defined.
   uint64_t min_buffer_binding_size;
+  /// Dimensionality of this binding, if defined.
+  TextureDimension dim;
 };
 
 /// Extracts information from a module
@@ -83,6 +105,11 @@
   std::vector<ResourceBinding> GetComparisonSamplerResourceBindings(
       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 sampled textures.
+  std::vector<ResourceBinding> GetSampledTextureResourceBindings(
+      const std::string& entry_point);
+
  private:
   const ast::Module& module_;
   std::string error_;
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index d52001c..822aeee 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -480,6 +480,11 @@
         name, ast::StorageClass::kUniformConstant, f32_type()));
   }
 
+  void AddF32Vec(const std::string& name, uint32_t count) {
+    mod()->AddGlobalVariable(std::make_unique<ast::Variable>(
+        name, ast::StorageClass::kUniformConstant, f32_vec_type(count)));
+  }
+
   /// Adds a depth texture variable to the module
   /// @param name the name of the variable
   /// @param type the type to use
@@ -504,7 +509,7 @@
     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, f32_vec_type(4));
     body->append(
         std::make_unique<ast::VariableDeclStatement>(std::move(call_result)));
 
@@ -577,6 +582,22 @@
     return func;
   }
 
+  /// 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.
+  /// @returns a pointer to a type appropriate for the coord param
+  ast::type::Type* GetCoordsType(ast::type::TextureDimension dim) {
+    if (dim == ast::type::TextureDimension::k1d) {
+      f32_type();
+    } else if (dim == ast::type::TextureDimension::k1dArray ||
+               dim == ast::type::TextureDimension::k2d) {
+      return f32_vec_type(2);
+    } else if (dim == ast::type::TextureDimension::kCubeArray) {
+      return f32_vec_type(4);
+    }
+    return f32_vec_type(3);
+  }
+
   ast::Module* mod() { return &mod_; }
   TypeDeterminer* td() { return td_.get(); }
   Inspector* inspector() { return inspector_.get(); }
@@ -595,6 +616,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] =
+          std::make_unique<ast::type::VectorType>(u32_type(), count);
+    }
+    return vector_type_memo_[count].get();
+  }
   ast::type::VoidType* void_type() { return &void_type_; }
   ast::type::SamplerType* sampler_type() { return &sampler_type_; }
   ast::type::SamplerType* comparison_sampler_type() {
@@ -615,19 +643,35 @@
   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_;
 };
 
-class InspectorTest : public InspectorHelper, public testing::Test {};
-
-class InspectorGetEntryPointTest : public InspectorTest {};
-class InspectorGetConstantIDsTest : public InspectorTest {};
-class InspectorGetUniformBufferResourceBindingsTest : public InspectorTest {};
-class InspectorGetStorageBufferResourceBindingsTest : public InspectorTest {};
+class InspectorGetEntryPointTest : public InspectorHelper,
+                                   public testing::Test {};
+class InspectorGetConstantIDsTest : public InspectorHelper,
+                                    public testing::Test {};
+class InspectorGetUniformBufferResourceBindingsTest : public InspectorHelper,
+                                                      public testing::Test {};
+class InspectorGetStorageBufferResourceBindingsTest : public InspectorHelper,
+                                                      public testing::Test {};
 class InspectorGetReadOnlyStorageBufferResourceBindingsTest
-    : public InspectorTest {};
-class InspectorGetSamplerResourceBindingsTest : public InspectorTest {};
-class InspectorGetComparisonSamplerResourceBindingsTest : public InspectorTest {
+    : public InspectorHelper,
+      public testing::Test {};
+class InspectorGetSamplerResourceBindingsTest : public InspectorHelper,
+                                                public testing::Test {};
+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;
 };
+class InspectorGetSampledTextureResourceBindingsTestWithParam
+    : public InspectorHelper,
+      public testing::TestWithParam<GetSampledTextureTestParams> {};
 
 TEST_F(InspectorGetEntryPointTest, NoFunctions) {
   auto result = inspector()->GetEntryPoints();
@@ -1816,6 +1860,57 @@
   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);
+  AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0);
+  AddSampler("foo_sampler", 0, 1);
+  AddF32("foo_coords");
+
+  auto func = MakeSamplerReferenceBodyFunction("ep", "foo_texture",
+                                               "foo_sampler", "foo_coords");
+  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()->GetSampledTextureResourceBindings("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);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    InspectorGetSampledTextureResourceBindingsTest,
+    InspectorGetSampledTextureResourceBindingsTestWithParam,
+    testing::Values(
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k1d,
+            inspector::ResourceBinding::TextureDimension::k1d},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k1dArray,
+            inspector::ResourceBinding::TextureDimension::k1dArray},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k2d,
+            inspector::ResourceBinding::TextureDimension::k2d},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k2dArray,
+            inspector::ResourceBinding::TextureDimension::k2dArray},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::k3d,
+            inspector::ResourceBinding::TextureDimension::k3d},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::kCube,
+            inspector::ResourceBinding::TextureDimension::kCube},
+        GetSampledTextureTestParams{
+            ast::type::TextureDimension::kCubeArray,
+            inspector::ResourceBinding::TextureDimension::kCubeArray}));
+
 }  // namespace
 }  // namespace inspector
 }  // namespace tint