From 1a9a2dd07d07180e5019c2bf19c28dda8d97cf15 Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Mon, 5 Oct 2020 14:52:36 +0000 Subject: [PATCH] Add Inspector class This class is used to examine a module and get information about its contents. This is the getting side of shader of reflection. Future work will add transforms that perform the setting side of reflection. In addition to the basic class and infrastructure, this CL adds a GetEntryPoints() function demonstrate it works. More functionality will be added in later CLs. BUG=tint:257 Change-Id: If41dbb6c93302e0332754c086c75729d6ffe04d0 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/29320 Commit-Queue: dan sinclair Reviewed-by: dan sinclair Reviewed-by: David Neto --- BUILD.gn | 3 ++ src/CMakeLists.txt | 5 +- src/inspector.cc | 38 ++++++++++++++ src/inspector.h | 59 +++++++++++++++++++++ src/inspector_test.cc | 116 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 src/inspector.cc create mode 100644 src/inspector.h create mode 100644 src/inspector_test.cc diff --git a/BUILD.gn b/BUILD.gn index 26bc2211c8..591365013f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -369,6 +369,8 @@ source_set("libtint_core_src") { "src/ast/workgroup_decoration.h", "src/context.cc", "src/context.h", + "src/inspector.cc", + "src/inspector.h", "src/reader/reader.cc", "src/reader/reader.h", "src/scope_stack.h", @@ -750,6 +752,7 @@ source_set("tint_unittests_core_src") { "src/ast/variable_decl_statement_test.cc", "src/ast/variable_test.cc", "src/ast/workgroup_decoration_test.cc", + "src/inspector_test.cc", "src/scope_stack_test.cc", "src/transform/bound_array_accessors_transform_test.cc", "src/transform/vertex_pulling_transform_test.cc", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f5c76c5c6d..882b884795 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -188,8 +188,10 @@ set(TINT_LIB_SRCS ast/variable_decl_statement.h ast/workgroup_decoration.cc ast/workgroup_decoration.h - context.h context.cc + context.h + inspector.cc + inspector.h reader/reader.cc reader/reader.h scope_stack.h @@ -360,6 +362,7 @@ set(TINT_TEST_SRCS ast/variable_decl_statement_test.cc ast/variable_test.cc ast/workgroup_decoration_test.cc + inspector_test.cc scope_stack_test.cc transform/bound_array_accessors_transform_test.cc transform/vertex_pulling_transform_test.cc diff --git a/src/inspector.cc b/src/inspector.cc new file mode 100644 index 0000000000..804ae1842a --- /dev/null +++ b/src/inspector.cc @@ -0,0 +1,38 @@ +// Copyright 2020 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/inspector.h" + +#include "src/ast/function.h" + +namespace tint { +namespace inspector { + +Inspector::Inspector(const ast::Module& module) : module_(module) {} + +Inspector::~Inspector() = default; + +std::vector Inspector::GetEntryPoints() { + std::vector result; + for (const auto& func : module_.functions()) { + if (func->IsEntryPoint()) { + result.push_back({func->name(), func->pipeline_stage()}); + } + } + + return result; +} + +} // namespace inspector +} // namespace tint diff --git a/src/inspector.h b/src/inspector.h new file mode 100644 index 0000000000..86ef88e777 --- /dev/null +++ b/src/inspector.h @@ -0,0 +1,59 @@ +// Copyright 2020 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_INSPECTOR_H_ +#define SRC_INSPECTOR_H_ + +#include +#include +#include + +#include "src/ast/module.h" +#include "src/ast/pipeline_stage.h" + +namespace tint { +namespace inspector { + +struct EntryPoint { + /// The entry point name + std::string name; + /// The entry point stage + ast::PipelineStage stage = ast::PipelineStage::kNone; +}; + +/// Extracts information from a module +class Inspector { + public: + /// Constructor + /// @param module Shader module to extract information from. + explicit Inspector(const ast::Module& module); + ~Inspector(); + + /// @returns error messages from the Inspector + const std::string& error() { return error_; } + /// @returns true if an error was encountered + bool has_error() const { return !error_.empty(); } + + /// @returns vector of entry point information + std::vector GetEntryPoints(); + + private: + const ast::Module& module_; + std::string error_; +}; + +} // namespace inspector +} // namespace tint + +#endif // SRC_INSPECTOR_H_ diff --git a/src/inspector_test.cc b/src/inspector_test.cc new file mode 100644 index 0000000000..deff66c6be --- /dev/null +++ b/src/inspector_test.cc @@ -0,0 +1,116 @@ +// Copyright 2020 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/inspector.h" + +#include "gtest/gtest.h" +#include "src/ast/function.h" +#include "src/ast/pipeline_stage.h" +#include "src/ast/stage_decoration.h" +#include "src/ast/type/void_type.h" +#include "src/context.h" + +namespace tint { +namespace inspector { +namespace { + +class InspectorHelper { + public: + InspectorHelper() + : mod_(std::make_unique()), + inspector_(std::make_unique(*mod_)) {} + + void AddFunction(const std::string& name, ast::PipelineStage stage) { + auto func = std::make_unique( + name, ast::VariableList{}, + ctx_.type_mgr().Get(std::make_unique())); + if (stage != ast::PipelineStage::kNone) { + func->add_decoration(std::make_unique(stage)); + } + mod()->AddFunction(std::move(func)); + } + + Context* ctx() { return &ctx_; } + ast::Module* mod() { return mod_.get(); } + Inspector* inspector() { return inspector_.get(); } + + private: + Context ctx_; + std::unique_ptr mod_; + std::unique_ptr inspector_; +}; + +class InspectorTest : public InspectorHelper, public testing::Test {}; + +class InspectorGetEntryPointTest : public InspectorTest {}; + +TEST_F(InspectorGetEntryPointTest, NoFunctions) { + auto result = inspector()->GetEntryPoints(); + ASSERT_FALSE(inspector()->has_error()); + + EXPECT_EQ(0u, result.size()); +} + +TEST_F(InspectorGetEntryPointTest, NoEntryPoints) { + AddFunction("foo", ast::PipelineStage::kNone); + + auto result = inspector()->GetEntryPoints(); + ASSERT_FALSE(inspector()->has_error()); + + EXPECT_EQ(0u, result.size()); +} + +TEST_F(InspectorGetEntryPointTest, OneEntryPoint) { + AddFunction("foo", ast::PipelineStage::kVertex); + + auto result = inspector()->GetEntryPoints(); + ASSERT_FALSE(inspector()->has_error()); + + EXPECT_EQ(1u, result.size()); + EXPECT_EQ("foo", result[0].name); + EXPECT_EQ(ast::PipelineStage::kVertex, result[0].stage); +} + +TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) { + AddFunction("foo", ast::PipelineStage::kVertex); + AddFunction("bar", ast::PipelineStage::kCompute); + + auto result = inspector()->GetEntryPoints(); + ASSERT_FALSE(inspector()->has_error()); + + EXPECT_EQ(2u, result.size()); + EXPECT_EQ("foo", result[0].name); + EXPECT_EQ(ast::PipelineStage::kVertex, result[0].stage); + EXPECT_EQ("bar", result[1].name); + EXPECT_EQ(ast::PipelineStage::kCompute, result[1].stage); +} + +TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) { + AddFunction("foo", ast::PipelineStage::kVertex); + AddFunction("func", ast::PipelineStage::kNone); + AddFunction("bar", ast::PipelineStage::kCompute); + + auto result = inspector()->GetEntryPoints(); + EXPECT_FALSE(inspector()->has_error()); + + EXPECT_EQ(2u, result.size()); + EXPECT_EQ("foo", result[0].name); + EXPECT_EQ(ast::PipelineStage::kVertex, result[0].stage); + EXPECT_EQ("bar", result[1].name); + EXPECT_EQ(ast::PipelineStage::kCompute, result[1].stage); +} + +} // namespace +} // namespace inspector +} // namespace tint