Add texture_external to inspector

Adds texture_external to the inspector, allowing us to recognize the
type and return provide binding information. Includes a basic test.

Bug: Dawn:728
Change-Id: Ib0f39998359dc22a530ad222141229f9ba30552f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51161
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/samples/main.cc b/samples/main.cc
index 98797bd..44a9898 100644
--- a/samples/main.cc
+++ b/samples/main.cc
@@ -337,6 +337,8 @@
       return "WriteOnlyStorageTexture";
     case tint::inspector::ResourceBinding::ResourceType::kDepthTexture:
       return "DepthTexture";
+    case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
+      return "ExternalTexture";
   }
 
   return "Unknown";
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index a6c9ec2..eb79153 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -381,7 +381,8 @@
   AppendResourceBindings(
       &result, GetWriteOnlyStorageTextureResourceBindings(entry_point));
   AppendResourceBindings(&result, GetDepthTextureResourceBindings(entry_point));
-
+  AppendResourceBindings(&result,
+                         GetExternalTextureResourceBindings(entry_point));
   return result;
 }
 
@@ -531,6 +532,33 @@
   return result;
 }
 
+std::vector<ResourceBinding> Inspector::GetExternalTextureResourceBindings(
+    const std::string& entry_point) {
+  auto* func = FindEntryPointByName(entry_point);
+  if (!func) {
+    return {};
+  }
+
+  std::vector<ResourceBinding> result;
+  auto* func_sem = program_->Sem().Get(func);
+  for (auto& ref : func_sem->ReferencedExternalTextureVariables()) {
+    auto* var = ref.first;
+    auto binding_info = ref.second;
+
+    ResourceBinding entry;
+    entry.resource_type = ResourceBinding::ResourceType::kExternalTexture;
+    entry.bind_group = binding_info.group->value();
+    entry.binding = binding_info.binding->value();
+
+    auto* texture_type = var->Type()->UnwrapAccess()->As<sem::Texture>();
+    entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
+        texture_type->dim());
+
+    result.push_back(entry);
+  }
+  return result;
+}
+
 ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
   auto* func = program_->AST().Functions().Find(program_->Symbols().Get(name));
   if (!func) {
diff --git a/src/inspector/inspector.h b/src/inspector/inspector.h
index 149d70c..8d93740 100644
--- a/src/inspector/inspector.h
+++ b/src/inspector/inspector.h
@@ -104,6 +104,7 @@
     kReadOnlyStorageTexture,
     kWriteOnlyStorageTexture,
     kDepthTexture,
+    kExternalTexture
   };
 
   /// Type of resource that is bound.
@@ -209,6 +210,11 @@
   std::vector<ResourceBinding> GetDepthTextureResourceBindings(
       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 external textures.
+  std::vector<ResourceBinding> GetExternalTextureResourceBindings(
+      const std::string& entry_point);
+
  private:
   const Program* program_;
   std::string error_;
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index 39c98c6..2c5f01f 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -19,6 +19,7 @@
 #include "src/ast/struct_block_decoration.h"
 #include "src/ast/workgroup_decoration.h"
 #include "src/sem/depth_texture_type.h"
+#include "src/sem/external_texture_type.h"
 #include "src/sem/multisampled_texture_type.h"
 #include "src/sem/sampled_texture_type.h"
 #include "src/sem/variable.h"
@@ -380,6 +381,12 @@
     return ty.multisampled_texture(dim, type);
   }
 
+  /// Generates an ExternalTexture appropriate for the params
+  /// @returns the generated ExternalTexture
+  typ::ExternalTexture MakeExternalTextureType() {
+    return ty.external_texture();
+  }
+
   /// Adds a sampled texture variable to the program
   /// @param name the name of the variable
   /// @param type the type to use
@@ -420,6 +427,18 @@
     AddBinding(name, type, ast::StorageClass::kNone, group, binding);
   }
 
+  /// Adds an external texture variable to the program
+  /// @param name the name of the variable
+  /// @param type the type to use
+  /// @param group the binding/group to use for the external texture
+  /// @param binding the binding number to use for the external texture
+  void AddExternalTexture(const std::string& name,
+                          ast::Type* type,
+                          uint32_t group,
+                          uint32_t binding) {
+    AddBinding(name, type, ast::StorageClass::kNone, group, binding);
+  }
+
   /// Generates a function that references a specific sampler variable
   /// @param func_name name of the function created
   /// @param texture_name name of the texture to be sampled
@@ -697,6 +716,9 @@
     : public InspectorHelper,
       public testing::TestWithParam<GetStorageTextureTestParams> {};
 
+class InspectorGetExternalTextureResourceBindingsTest : public InspectorHelper,
+                                                        public testing::Test {};
+
 TEST_F(InspectorGetEntryPointTest, NoFunctions) {
   Inspector& inspector = Build();
 
@@ -2936,6 +2958,30 @@
             ast::TextureDimension::kCubeArray,
             inspector::ResourceBinding::TextureDimension::kCubeArray}));
 
+TEST_F(InspectorGetExternalTextureResourceBindingsTest, Simple) {
+  auto external_texture_type = MakeExternalTextureType();
+  AddExternalTexture("et", external_texture_type, 0, 0);
+
+  Func("ep", ast::VariableList(), ty.void_(),
+       ast::StatementList{
+           create<ast::CallStatement>(Call("textureDimensions", "et")),
+       },
+       ast::DecorationList{
+           Stage(ast::PipelineStage::kFragment),
+       });
+
+  Inspector& inspector = Build();
+
+  auto result = inspector.GetExternalTextureResourceBindings("ep");
+  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+  EXPECT_EQ(ResourceBinding::ResourceType::kExternalTexture,
+            result[0].resource_type);
+
+  ASSERT_EQ(1u, result.size());
+  EXPECT_EQ(0u, result[0].bind_group);
+  EXPECT_EQ(0u, result[0].binding);
+}
+
 }  // namespace
 }  // namespace inspector
 }  // namespace tint
diff --git a/src/program_builder.h b/src/program_builder.h
index 74367bc..610f1eb 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -869,6 +869,12 @@
                   dims, format, ast::AccessControl::kInvalid, sem_subtype)};
     }
 
+    /// @returns the external texture
+    typ::ExternalTexture external_texture() const {
+      return {builder->create<ast::ExternalTexture>(),
+              builder->create<sem::ExternalTexture>()};
+    }
+
     /// @param source the Source of the node
     /// @returns the external texture
     typ::ExternalTexture external_texture(const Source& source) const {
diff --git a/src/sem/function.cc b/src/sem/function.cc
index 5a5a151..35c2e71 100644
--- a/src/sem/function.cc
+++ b/src/sem/function.cc
@@ -16,6 +16,7 @@
 
 #include "src/ast/function.h"
 #include "src/sem/depth_texture_type.h"
+#include "src/sem/external_texture_type.h"
 #include "src/sem/multisampled_texture_type.h"
 #include "src/sem/sampled_texture_type.h"
 #include "src/sem/storage_texture_type.h"
@@ -168,6 +169,24 @@
   return ret;
 }
 
+Function::VariableBindings Function::ReferencedExternalTextureVariables()
+    const {
+  VariableBindings ret;
+
+  for (auto* var : ReferencedModuleVariables()) {
+    auto* unwrapped_type = var->Type()->UnwrapAccess();
+    auto* external_texture = unwrapped_type->As<sem::ExternalTexture>();
+    if (external_texture == nullptr) {
+      continue;
+    }
+
+    if (auto binding_point = var->Declaration()->binding_point()) {
+      ret.push_back({var, binding_point});
+    }
+  }
+  return ret;
+}
+
 bool Function::HasAncestorEntryPoint(Symbol symbol) const {
   for (const auto& point : ancestor_entry_points_) {
     if (point == symbol) {
diff --git a/src/sem/function.h b/src/sem/function.h
index 3b107ee..a29e318 100644
--- a/src/sem/function.h
+++ b/src/sem/function.h
@@ -135,9 +135,14 @@
 
   /// Retrieves any referenced depth texture variables. Note, the variables
   /// must be decorated with both binding and group decorations.
-  /// @returns the referenced storage textures
+  /// @returns the referenced depth textures
   VariableBindings ReferencedDepthTextureVariables() const;
 
+  /// Retrieves any referenced external texture variables. Note, the variables
+  /// must be decorated with both binding and group decorations.
+  /// @returns the referenced external textures
+  VariableBindings ReferencedExternalTextureVariables() const;
+
   /// Checks if the given entry point is an ancestor
   /// @param sym the entry point symbol
   /// @returns true if `sym` is an ancestor entry point of this function