diff --git a/src/ast/function.cc b/src/ast/function.cc index 23bd0043d4..a90b0858bc 100644 --- a/src/ast/function.cc +++ b/src/ast/function.cc @@ -167,6 +167,16 @@ Function::referenced_builtin_variables() const { return ret; } +const std::vector> +Function::referenced_sampler_variables() const { + return ReferencedSamplerVariablesImpl(type::SamplerKind::kSampler); +} + +const std::vector> +Function::referenced_comparison_sampler_variables() const { + return ReferencedSamplerVariablesImpl(type::SamplerKind::kComparisonSampler); +} + void Function::add_ancestor_entry_point(const std::string& ep) { for (const auto& point : ancestor_entry_points_) { if (point == ep) { @@ -253,5 +263,34 @@ std::string Function::type_name() const { return out.str(); } +const std::vector> +Function::ReferencedSamplerVariablesImpl(type::SamplerKind kind) const { + std::vector> ret; + + for (auto* var : referenced_module_variables()) { + auto* unwrapped_type = var->type()->UnwrapIfNeeded(); + if (!var->IsDecorated() || !unwrapped_type->IsSampler() || + unwrapped_type->AsSampler()->kind() != kind) { + 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 52cff4909c..e07658f42b 100644 --- a/src/ast/function.h +++ b/src/ast/function.h @@ -32,6 +32,7 @@ #include "src/ast/pipeline_stage.h" #include "src/ast/set_decoration.h" #include "src/ast/statement.h" +#include "src/ast/type/sampler_type.h" #include "src/ast/type/type.h" #include "src/ast/variable.h" @@ -138,6 +139,16 @@ class Function : public Node { /// @returns the referenced storagebuffers const std::vector> referenced_storagebuffer_variables() const; + /// Retrieves any referenced regular Sampler variables. Note, the + /// storagebuffer must be decorated with both binding and set decorations. + /// @returns the referenced storagebuffers + const std::vector> + referenced_sampler_variables() const; + /// Retrieves any referenced comparison Sampler variables. Note, the + /// storagebuffer must be decorated with both binding and set decorations. + /// @returns the referenced storagebuffers + const std::vector> + referenced_comparison_sampler_variables() const; /// Adds an ancestor entry point /// @param ep the entry point ancestor @@ -183,6 +194,8 @@ class Function : public Node { private: Function(const Function&) = delete; + const std::vector> + ReferencedSamplerVariablesImpl(type::SamplerKind kind) const; std::string name_; VariableList params_; diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc index 7eb1aa7cb1..43d11f7605 100644 --- a/src/inspector/inspector.cc +++ b/src/inspector/inspector.cc @@ -187,6 +187,30 @@ Inspector::GetReadOnlyStorageBufferResourceBindings( return GetStorageBufferResourceBindingsImpl(entry_point, true); } +std::vector Inspector::GetSamplerResourceBindings( + const std::string& entry_point) { + auto* func = FindEntryPointByName(entry_point); + if (!func) { + return {}; + } + + std::vector result; + + for (auto& rs : func->referenced_sampler_variables()) { + ResourceBinding entry; + ast::Variable* var = nullptr; + ast::Function::BindingInfo binding_info; + std::tie(var, binding_info) = rs; + + entry.bind_group = binding_info.set->value(); + entry.binding = binding_info.binding->value(); + + result.push_back(std::move(entry)); + } + + return result; +} + ast::Function* Inspector::FindEntryPointByName(const std::string& name) { auto* func = module_.FindFunctionByName(name); if (!func) { @@ -211,11 +235,11 @@ std::vector Inspector::GetStorageBufferResourceBindingsImpl( } std::vector result; - for (auto& ruv : func->referenced_storagebuffer_variables()) { + for (auto& rsv : func->referenced_storagebuffer_variables()) { ResourceBinding entry; ast::Variable* var = nullptr; ast::Function::BindingInfo binding_info; - std::tie(var, binding_info) = ruv; + std::tie(var, binding_info) = rsv; if (!var->type()->IsAccessControl()) { continue; } diff --git a/src/inspector/inspector.h b/src/inspector/inspector.h index 2a64b3b7eb..d2e39a8ea7 100644 --- a/src/inspector/inspector.h +++ b/src/inspector/inspector.h @@ -68,14 +68,16 @@ class Inspector { std::vector GetStorageBufferResourceBindings( const std::string& entry_point); - // TODO(rharrison): Implement once - // https://dawn-review.googlesource.com/c/tint/+/31060 lands. /// @param entry_point name of the entry point to get information about. - /// @returns an empty vector and sets the error string. In the future it will - /// return of all of the bindings for read-only storage buffers. + /// @returns vector of all of the bindings for read-only storage buffers. std::vector GetReadOnlyStorageBufferResourceBindings( 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 regular samplers. + std::vector GetSamplerResourceBindings( + 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 3993b2dfdd..5edfb124b8 100644 --- a/src/inspector/inspector_test.cc +++ b/src/inspector/inspector_test.cc @@ -46,6 +46,8 @@ #include "src/ast/type/i32_type.h" #include "src/ast/type/matrix_type.h" #include "src/ast/type/pointer_type.h" +#include "src/ast/type/sampled_texture_type.h" +#include "src/ast/type/sampler_type.h" #include "src/ast/type/struct_type.h" #include "src/ast/type/type.h" #include "src/ast/type/u32_type.h" @@ -67,7 +69,9 @@ class InspectorHelper { public: InspectorHelper() : td_(std::make_unique(&ctx_, &mod_)), - inspector_(std::make_unique(mod_)) {} + inspector_(std::make_unique(mod_)), + sampler_type_(ast::type::SamplerKind::kSampler), + comparison_sampler_type_(ast::type::SamplerKind::kComparisonSampler) {} /// Generates an empty function /// @param name name of the function created @@ -368,7 +372,7 @@ class InspectorHelper { AddBinding(name, type, ast::StorageClass::kUniform, set, binding); } - /// Adds an storage buffer variable to the module + /// Adds a storage buffer 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 storage buffer @@ -420,6 +424,89 @@ class InspectorHelper { return func; } + /// Adds a regular sampler variable to the module + /// @param name the name of the variable + /// @param set the binding group/set to use for the storage buffer + /// @param binding the binding number to use for the storage buffer + void AddSampler(const std::string& name, uint32_t set, uint32_t binding) { + AddBinding(name, sampler_type(), ast::StorageClass::kUniformConstant, set, + binding); + } + + /// Adds a comparison sampler variable to the module + /// @param name the name of the variable + /// @param set the binding group/set to use for the storage buffer + /// @param binding the binding number to use for the storage buffer + void AddComparisonSampler(const std::string& name, + uint32_t set, + uint32_t binding) { + AddBinding(name, comparison_sampler_type(), + ast::StorageClass::kUniformConstant, set, binding); + } + + /// Generates a SampledTextureType 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 MakeSampledTextureType( + ast::type::TextureDimension dim, + ast::type::Type* type) { + return std::make_unique(dim, type); + } + + /// Adds a 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 sampled texture + /// @param binding the binding number to use for the sampled texture + void AddSampledTexture(const std::string& name, + ast::type::Type* type, + uint32_t set, + uint32_t binding) { + AddBinding(name, type, ast::StorageClass::kUniformConstant, set, binding); + } + + void AddF32(const std::string& name) { + mod()->AddGlobalVariable(std::make_unique( + name, ast::StorageClass::kUniformConstant, f32_type())); + } + + std::unique_ptr MakeSamplerReferenceBodyFunction( + const std::string& func_name, + const std::string& texture_name, + const std::string& sampler_name, + const std::string& coords_name) { + std::string result_name = "sampler_result"; + + auto body = std::make_unique(); + + auto call_result = std::make_unique( + "sampler_result", ast::StorageClass::kFunction, f32_type()); + body->append( + std::make_unique(std::move(call_result))); + + ast::ExpressionList call_params; + call_params.push_back( + std::make_unique(texture_name)); + call_params.push_back( + std::make_unique(sampler_name)); + call_params.push_back( + std::make_unique(coords_name)); + auto call_expr = std::make_unique( + std::make_unique("textureSample"), + std::move(call_params)); + + body->append(std::make_unique( + std::make_unique("sampler_result"), + std::move(call_expr))); + body->append(std::make_unique()); + + auto func = std::make_unique(func_name, ast::VariableList(), + void_type()); + func->set_body(std::move(body)); + return func; + } + ast::Module* mod() { return &mod_; } TypeDeterminer* td() { return td_.get(); } Inspector* inspector() { return inspector_.get(); } @@ -439,6 +526,10 @@ class InspectorHelper { return array_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() { + return &comparison_sampler_type_; + } private: Context ctx_; @@ -451,6 +542,8 @@ class InspectorHelper { ast::type::I32Type i32_type_; ast::type::U32Type u32_type_; ast::type::VoidType void_type_; + ast::type::SamplerType sampler_type_; + ast::type::SamplerType comparison_sampler_type_; std::map> array_type_memo_; }; @@ -462,10 +555,11 @@ class InspectorGetUniformBufferResourceBindingsTest : public InspectorTest {}; class InspectorGetStorageBufferResourceBindingsTest : public InspectorTest {}; class InspectorGetReadOnlyStorageBufferResourceBindingsTest : public InspectorTest {}; +class InspectorGetSamplerResourceBindingsTest : public InspectorTest {}; TEST_F(InspectorGetEntryPointTest, NoFunctions) { auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); EXPECT_EQ(0u, result.size()); } @@ -474,7 +568,7 @@ TEST_F(InspectorGetEntryPointTest, NoEntryPoints) { mod()->AddFunction(MakeEmptyBodyFunction("foo")); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); EXPECT_EQ(0u, result.size()); } @@ -486,7 +580,7 @@ TEST_F(InspectorGetEntryPointTest, OneEntryPoint) { mod()->AddFunction(std::move(foo)); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ("foo", result[0].name); @@ -505,7 +599,7 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) { mod()->AddFunction(std::move(bar)); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(2u, result.size()); EXPECT_EQ("foo", result[0].name); @@ -545,7 +639,7 @@ TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) { mod()->AddFunction(std::move(foo)); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); uint32_t x, y, z; @@ -564,7 +658,7 @@ TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) { mod()->AddFunction(std::move(foo)); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); uint32_t x, y, z; @@ -584,7 +678,7 @@ TEST_F(InspectorGetEntryPointTest, NoInOutVariables) { mod()->AddFunction(std::move(foo)); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].input_variables.size()); @@ -602,7 +696,7 @@ TEST_F(InspectorGetEntryPointTest, EntryPointInOutVariables) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); @@ -626,7 +720,7 @@ TEST_F(InspectorGetEntryPointTest, FunctionInOutVariables) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); @@ -651,7 +745,7 @@ TEST_F(InspectorGetEntryPointTest, RepeatedInOutVariables) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); @@ -673,7 +767,7 @@ TEST_F(InspectorGetEntryPointTest, EntryPointMultipleInOutVariables) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); @@ -700,7 +794,7 @@ TEST_F(InspectorGetEntryPointTest, FunctionMultipleInOutVariables) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); @@ -728,7 +822,7 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(2u, result.size()); @@ -765,7 +859,7 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsSharedInOutVariables) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetEntryPoints(); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(2u, result.size()); @@ -933,7 +1027,7 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingBlockDeco) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetUniformBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); EXPECT_EQ(0u, result.size()); } @@ -956,7 +1050,7 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetUniformBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -983,7 +1077,7 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleMembers) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetUniformBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1035,7 +1129,7 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleUniformBuffers) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetUniformBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(3u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1070,7 +1164,7 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetUniformBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1097,7 +1191,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1124,7 +1218,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1176,7 +1270,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(3u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1211,7 +1305,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1238,7 +1332,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1265,7 +1359,7 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) { ASSERT_TRUE(td()->Determine()) << td()->error(); auto result = inspector()->GetStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(0u, result.size()); } @@ -1289,7 +1383,7 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) { auto result = inspector()->GetReadOnlyStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1343,7 +1437,7 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, auto result = inspector()->GetReadOnlyStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(3u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1379,7 +1473,7 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) { auto result = inspector()->GetReadOnlyStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1408,7 +1502,7 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, auto result = inspector()->GetReadOnlyStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(1u, result.size()); EXPECT_EQ(0u, result[0].bind_group); @@ -1436,10 +1530,92 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) { auto result = inspector()->GetReadOnlyStorageBufferResourceBindings("ep_func"); - ASSERT_FALSE(inspector()->has_error()); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); ASSERT_EQ(0u, result.size()); } +TEST_F(InspectorGetSamplerResourceBindingsTest, Simple) { + auto sampled_texture_type = + MakeSampledTextureType(ast::type::TextureDimension::k1d, f32_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::PipelineStage::kVertex, Source{})); + mod()->AddFunction(std::move(func)); + + ASSERT_TRUE(td()->Determine()) << td()->error(); + + auto result = inspector()->GetSamplerResourceBindings("ep"); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); + + ASSERT_EQ(1u, result.size()); + EXPECT_EQ(0u, result[0].bind_group); + EXPECT_EQ(1u, result[0].binding); +} + +TEST_F(InspectorGetSamplerResourceBindingsTest, NoSampler) { + auto func = MakeEmptyBodyFunction("ep_func"); + func->add_decoration(std::make_unique( + ast::PipelineStage::kVertex, Source{})); + mod()->AddFunction(std::move(func)); + + ASSERT_TRUE(td()->Determine()) << td()->error(); + + auto result = inspector()->GetSamplerResourceBindings("ep_func"); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); + + ASSERT_EQ(0u, result.size()); +} + +TEST_F(InspectorGetSamplerResourceBindingsTest, InFunction) { + auto sampled_texture_type = + MakeSampledTextureType(ast::type::TextureDimension::k1d, f32_type()); + AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0); + AddSampler("foo_sampler", 0, 1); + AddF32("foo_coords"); + + auto foo_func = MakeSamplerReferenceBodyFunction("foo_func", "foo_texture", + "foo_sampler", "foo_coords"); + mod()->AddFunction(std::move(foo_func)); + + auto ep_func = MakeCallerBodyFunction("ep_func", "foo_func"); + ep_func->add_decoration(std::make_unique( + ast::PipelineStage::kVertex, Source{})); + mod()->AddFunction(std::move(ep_func)); + + ASSERT_TRUE(td()->Determine()) << td()->error(); + + auto result = inspector()->GetSamplerResourceBindings("ep_func"); + ASSERT_FALSE(inspector()->has_error()) << inspector()->error(); + + ASSERT_EQ(1u, result.size()); + EXPECT_EQ(0u, result[0].bind_group); + EXPECT_EQ(1u, result[0].binding); +} + +TEST_F(InspectorGetSamplerResourceBindingsTest, UnknownEntryPoint) { + auto sampled_texture_type = + MakeSampledTextureType(ast::type::TextureDimension::k1d, f32_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::PipelineStage::kVertex, Source{})); + mod()->AddFunction(std::move(func)); + + ASSERT_TRUE(td()->Determine()) << td()->error(); + + auto result = inspector()->GetSamplerResourceBindings("foo"); + ASSERT_TRUE(inspector()->has_error()) << inspector()->error(); +} + } // namespace } // namespace inspector } // namespace tint