diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9761dc11dc..9a98007449 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -615,6 +615,8 @@ if(${TINT_BUILD_TESTS}) diagnostic/formatter_test.cc diagnostic/printer_test.cc inspector/inspector_test.cc + inspector/test_inspector_builder.cc + inspector/test_inspector_builder.h intrinsic_table_test.cc program_test.cc resolver/assignment_validation_test.cc diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc index 2aa1c49d02..70d5de6f72 100644 --- a/src/inspector/inspector_test.cc +++ b/src/inspector/inspector_test.cc @@ -19,6 +19,7 @@ #include "src/ast/stage_decoration.h" #include "src/ast/struct_block_decoration.h" #include "src/ast/workgroup_decoration.h" +#include "src/inspector/test_inspector_builder.h" #include "src/program_builder.h" #include "src/sem/depth_texture_type.h" #include "src/sem/external_texture_type.h" @@ -31,683 +32,17 @@ namespace tint { namespace inspector { namespace { -class InspectorHelper : public ProgramBuilder { - public: - InspectorHelper() {} - - /// Generates an empty function - /// @param name name of the function created - /// @param decorations the function decorations - void MakeEmptyBodyFunction(std::string name, - ast::DecorationList decorations) { - Func(name, ast::VariableList(), ty.void_(), ast::StatementList{Return()}, - decorations); - } - - /// Generates a function that calls other functions - /// @param caller name of the function created - /// @param callees names of the functions to be called - /// @param decorations the function decorations - void MakeCallerBodyFunction(std::string caller, - std::vector callees, - ast::DecorationList decorations) { - ast::StatementList body; - body.reserve(callees.size() + 1); - for (auto callee : callees) { - body.push_back(create(Call(callee))); - } - body.push_back(Return()); - - Func(caller, ast::VariableList(), ty.void_(), body, decorations); - } - - /// Generates a struct that contains user-defined IO members - /// @param name the name of the generated struct - /// @param inout_vars tuples of {name, loc} that will be the struct members - ast::Struct* MakeInOutStruct( - std::string name, - std::vector> inout_vars) { - ast::StructMemberList members; - for (auto var : inout_vars) { - std::string member_name; - uint32_t location; - std::tie(member_name, location) = var; - members.push_back(Member(member_name, ty.u32(), {Location(location)})); - } - return Structure(name, members); - } - - // TODO(crbug.com/tint/697): Remove this. - /// Add In/Out variables to the global variables - /// @param inout_vars tuples of {in, out} that will be added as entries to the - /// global variables - void AddInOutVariables( - std::vector> inout_vars) { - uint32_t location = 0; - for (auto inout : inout_vars) { - std::string in, out; - std::tie(in, out) = inout; - - Global(in, ty.u32(), ast::StorageClass::kInput, nullptr, - ast::DecorationList{ - Location(location++), - ASTNodes().Create( - ID(), ast::DisabledValidation::kIgnoreStorageClass)}); - Global(out, ty.u32(), ast::StorageClass::kOutput, nullptr, - ast::DecorationList{ - Location(location++), - ASTNodes().Create( - ID(), ast::DisabledValidation::kIgnoreStorageClass)}); - } - } - - // TODO(crbug.com/tint/697): Remove this. - /// Generates a function that references in/out variables - /// @param name name of the function created - /// @param inout_vars tuples of {in, out} that will be converted into out = in - /// calls in the function body - /// @param decorations the function decorations - void MakeInOutVariableBodyFunction( - std::string name, - std::vector> inout_vars, - ast::DecorationList decorations) { - ast::StatementList stmts; - for (auto inout : inout_vars) { - std::string in, out; - std::tie(in, out) = inout; - stmts.emplace_back(Assign(out, in)); - } - stmts.emplace_back(Return()); - Func(name, ast::VariableList(), ty.void_(), stmts, decorations); - } - - // TODO(crbug.com/tint/697): Remove this. - /// Generates a function that references in/out variables and calls another - /// function. - /// @param caller name of the function created - /// @param callee name of the function to be called - /// @param inout_vars tuples of {in, out} that will be converted into out = in - /// calls in the function body - /// @param decorations the function decorations - /// @returns a function object - ast::Function* MakeInOutVariableCallerBodyFunction( - std::string caller, - std::string callee, - std::vector> inout_vars, - ast::DecorationList decorations) { - ast::StatementList stmts; - for (auto inout : inout_vars) { - std::string in, out; - std::tie(in, out) = inout; - stmts.emplace_back(Assign(out, in)); - } - stmts.emplace_back(create(Call(callee))); - stmts.emplace_back(Return()); - - return Func(caller, ast::VariableList(), ty.void_(), stmts, decorations); - } - - /// Add a pipeline constant to the global variables, with a specific ID. - /// @param name name of the variable to add - /// @param id id number for the constant id - /// @param type type of the variable - /// @param val value to initialize the variable with, if NULL no initializer - /// will be added. - /// @returns the constant that was created - template - ast::Variable* AddOverridableConstantWithID(std::string name, - uint32_t id, - ast::Type* type, - T* val) { - ast::Expression* constructor = nullptr; - if (val) { - constructor = Expr(*val); - } - return GlobalConst(name, type, constructor, - ast::DecorationList{ - Override(id), - }); - } - - /// Add a pipeline constant to the global variables, without a specific ID. - /// @param name name of the variable to add - /// @param type type of the variable - /// @param val value to initialize the variable with, if NULL no initializer - /// will be added. - /// @returns the constant that was created - template - ast::Variable* AddOverridableConstantWithoutID(std::string name, - ast::Type* type, - T* val) { - ast::Expression* constructor = nullptr; - if (val) { - constructor = Expr(*val); - } - return GlobalConst(name, type, constructor, - ast::DecorationList{ - Override(), - }); - } - - /// Generates a function that references module constant - /// @param func name of the function created - /// @param var name of the constant to be reference - /// @param type type of the const being referenced - /// @param decorations the function decorations - /// @returns a function object - ast::Function* MakeConstReferenceBodyFunction( - std::string func, - std::string var, - ast::Type* type, - ast::DecorationList decorations) { - ast::StatementList stmts; - stmts.emplace_back(Decl(Var("local_" + var, type))); - stmts.emplace_back(Assign("local_" + var, var)); - stmts.emplace_back(Return()); - - return Func(func, ast::VariableList(), ty.void_(), stmts, decorations); - } - - /// @param vec Vector of StageVariable to be searched - /// @param name Name to be searching for - /// @returns true if name is in vec, otherwise false - bool ContainsName(const std::vector& vec, - const std::string& name) { - for (auto& s : vec) { - if (s.name == name) { - return true; - } - } - return false; - } - - /// Builds a string for accessing a member in a generated struct - /// @param idx index of member - /// @param type type of member - /// @returns a string for the member - std::string StructMemberName(size_t idx, ast::Type* type) { - return std::to_string(idx) + type->type_name(); - } - - /// Generates a struct type - /// @param name name for the type - /// @param member_types a vector of member types - /// @param is_block whether or not to decorate as a Block - /// @returns a struct type - ast::Struct* MakeStructType(const std::string& name, - std::vector member_types, - bool is_block) { - ast::StructMemberList members; - for (auto* type : member_types) { - members.push_back(Member(StructMemberName(members.size(), type), type)); - } - - ast::DecorationList decos; - if (is_block) { - decos.push_back(create()); - } - - return Structure(name, members, decos); - } - - /// Generates types appropriate for using in an uniform buffer - /// @param name name for the type - /// @param member_types a vector of member types - /// @returns a struct type that has the layout for an uniform buffer. - ast::Struct* MakeUniformBufferType(const std::string& name, - std::vector member_types) { - return MakeStructType(name, member_types, true); - } - - /// Generates types appropriate for using in a storage buffer - /// @param name name for the type - /// @param member_types a vector of member types - /// @returns a function that returns the created structure. - std::function MakeStorageBufferTypes( - const std::string& name, - std::vector member_types) { - MakeStructType(name, member_types, true); - return [this, name] { return ty.type_name(name); }; - } - - /// Adds an uniform buffer 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 uniform buffer - /// @param binding the binding number to use for the uniform buffer - void AddUniformBuffer(const std::string& name, - ast::Type* type, - uint32_t group, - uint32_t binding) { - Global(name, type, ast::StorageClass::kUniform, - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// Adds a storage buffer variable to the program - /// @param name the name of the variable - /// @param type the type to use - /// @param access the storage buffer access control - /// @param group the binding/group to use for the storage buffer - /// @param binding the binding number to use for the storage buffer - void AddStorageBuffer(const std::string& name, - ast::Type* type, - ast::Access access, - uint32_t group, - uint32_t binding) { - Global(name, type, ast::StorageClass::kStorage, access, - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// Generates a function that references a specific struct variable - /// @param func_name name of the function created - /// @param struct_name name of the struct variabler to be accessed - /// @param members list of members to access, by index and type - void MakeStructVariableReferenceBodyFunction( - std::string func_name, - std::string struct_name, - std::vector> members) { - ast::StatementList stmts; - for (auto member : members) { - size_t member_idx; - ast::Type* member_type; - std::tie(member_idx, member_type) = member; - std::string member_name = StructMemberName(member_idx, member_type); - - stmts.emplace_back(Decl(Var("local" + member_name, member_type))); - } - - for (auto member : members) { - size_t member_idx; - ast::Type* member_type; - std::tie(member_idx, member_type) = member; - std::string member_name = StructMemberName(member_idx, member_type); - - stmts.emplace_back(Assign("local" + member_name, - MemberAccessor(struct_name, member_name))); - } - - stmts.emplace_back(Return()); - - Func(func_name, ast::VariableList(), ty.void_(), stmts, - ast::DecorationList{}); - } - - /// Adds a regular sampler variable to the program - /// @param name the name of the variable - /// @param group the binding/group 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 group, uint32_t binding) { - Global(name, sampler_type(), - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// Adds a comparison sampler variable to the program - /// @param name the name of the variable - /// @param group the binding/group 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 group, - uint32_t binding) { - Global(name, comparison_sampler_type(), - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// Generates a SampledTexture appropriate for the params - /// @param dim the dimensions of the texture - /// @param type the data type of the sampled texture - /// @returns the generated SampleTextureType - ast::SampledTexture* MakeSampledTextureType(ast::TextureDimension dim, - ast::Type* type) { - return ty.sampled_texture(dim, type); - } - - /// Generates a DepthTexture appropriate for the params - /// @param dim the dimensions of the texture - /// @returns the generated DepthTexture - ast::DepthTexture* MakeDepthTextureType(ast::TextureDimension dim) { - return ty.depth_texture(dim); - } - - /// Generates a MultisampledTexture appropriate for the params - /// @param dim the dimensions of the texture - /// @param type the data type of the sampled texture - /// @returns the generated SampleTextureType - ast::MultisampledTexture* MakeMultisampledTextureType( - ast::TextureDimension dim, - ast::Type* type) { - return ty.multisampled_texture(dim, type); - } - - /// Generates an ExternalTexture appropriate for the params - /// @returns the generated ExternalTexture - ast::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 - /// @param group the binding/group 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, - uint32_t group, - uint32_t binding) { - Global(name, type, - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// Adds a multi-sampled 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 multi-sampled texture - /// @param binding the binding number to use for the multi-sampled texture - void AddMultisampledTexture(const std::string& name, - ast::Type* type, - uint32_t group, - uint32_t binding) { - Global(name, type, - ast::DecorationList{ - create(binding), - create(group), - }); - } - - void AddGlobalVariable(const std::string& name, ast::Type* type) { - Global(name, type, ast::StorageClass::kPrivate); - } - - /// Adds a depth 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 depth texture - /// @param binding the binding number to use for the depth texture - void AddDepthTexture(const std::string& name, - ast::Type* type, - uint32_t group, - uint32_t binding) { - Global(name, type, - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// 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) { - Global(name, type, - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// 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 - /// @param sampler_name name of the sampler to use - /// @param coords_name name of the coords variable to use - /// @param base_type sampler base type - /// @param decorations the function decorations - /// @returns a function that references all of the values specified - ast::Function* MakeSamplerReferenceBodyFunction( - const std::string& func_name, - const std::string& texture_name, - const std::string& sampler_name, - const std::string& coords_name, - ast::Type* base_type, - ast::DecorationList decorations) { - std::string result_name = "sampler_result"; - - ast::StatementList stmts; - stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4)))); - - stmts.emplace_back(Assign(result_name, Call("textureSample", texture_name, - sampler_name, coords_name))); - stmts.emplace_back(Return()); - - return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); - } - - /// 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 - /// @param sampler_name name of the sampler to use - /// @param coords_name name of the coords variable to use - /// @param array_index name of the array index variable to use - /// @param base_type sampler base type - /// @param decorations the function decorations - /// @returns a function that references all of the values specified - ast::Function* MakeSamplerReferenceBodyFunction( - const std::string& func_name, - const std::string& texture_name, - const std::string& sampler_name, - const std::string& coords_name, - const std::string& array_index, - ast::Type* base_type, - ast::DecorationList decorations) { - std::string result_name = "sampler_result"; - - ast::StatementList stmts; - - stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4)))); - - stmts.emplace_back( - Assign("sampler_result", Call("textureSample", texture_name, - sampler_name, coords_name, array_index))); - stmts.emplace_back(Return()); - - return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); - } - - /// Generates a function that references a specific comparison sampler - /// variable. - /// @param func_name name of the function created - /// @param texture_name name of the depth texture to use - /// @param sampler_name name of the sampler to use - /// @param coords_name name of the coords variable to use - /// @param depth_name name of the depth reference to use - /// @param base_type sampler base type - /// @param decorations the function decorations - /// @returns a function that references all of the values specified - ast::Function* MakeComparisonSamplerReferenceBodyFunction( - const std::string& func_name, - const std::string& texture_name, - const std::string& sampler_name, - const std::string& coords_name, - const std::string& depth_name, - ast::Type* base_type, - ast::DecorationList decorations) { - std::string result_name = "sampler_result"; - - ast::StatementList stmts; - - stmts.emplace_back(Decl(Var("sampler_result", base_type))); - stmts.emplace_back( - Assign("sampler_result", Call("textureSampleCompare", texture_name, - sampler_name, coords_name, depth_name))); - stmts.emplace_back(Return()); - - return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); - } - - /// 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* GetBaseType(ResourceBinding::SampledKind sampled_kind) { - switch (sampled_kind) { - case ResourceBinding::SampledKind::kFloat: - return ty.f32(); - case ResourceBinding::SampledKind::kSInt: - return ty.i32(); - case ResourceBinding::SampledKind::kUInt: - return ty.u32(); - 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 scalar the scalar type - /// @returns a pointer to a type appropriate for the coord param - ast::Type* GetCoordsType(ast::TextureDimension dim, ast::Type* scalar) { - switch (dim) { - case ast::TextureDimension::k1d: - return scalar; - case ast::TextureDimension::k2d: - case ast::TextureDimension::k2dArray: - return create(scalar, 2); - case ast::TextureDimension::k3d: - case ast::TextureDimension::kCube: - case ast::TextureDimension::kCubeArray: - return create(scalar, 3); - default: - [=]() { FAIL() << "Unsupported texture dimension: " << dim; }(); - } - return nullptr; - } - - /// Generates appropriate types for a Read-Only StorageTexture - /// @param dim the texture dimension of the storage texture - /// @param format the image format of the storage texture - /// @param read_only should the access type be read only, otherwise write only - /// @returns the storage texture type - ast::Type* MakeStorageTextureTypes(ast::TextureDimension dim, - ast::ImageFormat format, - bool read_only) { - auto access = read_only ? ast::Access::kRead : ast::Access::kWrite; - return ty.storage_texture(dim, format, access); - } - - /// Adds a storage 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 sampled texture - /// @param binding the binding number to use for the sampled texture - void AddStorageTexture(const std::string& name, - ast::Type* type, - uint32_t group, - uint32_t binding) { - Global(name, type, - ast::DecorationList{ - create(binding), - create(group), - }); - } - - /// Generates a function that references a storage texture variable. - /// @param func_name name of the function created - /// @param st_name name of the storage texture to use - /// @param dim_type type expected by textureDimensons to return - /// @param decorations the function decorations - /// @returns a function that references all of the values specified - ast::Function* MakeStorageTextureBodyFunction( - const std::string& func_name, - const std::string& st_name, - ast::Type* dim_type, - ast::DecorationList decorations) { - ast::StatementList stmts; - - stmts.emplace_back(Decl(Var("dim", dim_type))); - stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name))); - stmts.emplace_back(Return()); - - return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); - } - - std::function GetTypeFunction(ComponentType component, - CompositionType composition) { - std::function func; - switch (component) { - case ComponentType::kFloat: - func = [this]() -> ast::Type* { return ty.f32(); }; - break; - case ComponentType::kSInt: - func = [this]() -> ast::Type* { return ty.i32(); }; - break; - case ComponentType::kUInt: - func = [this]() -> ast::Type* { return ty.u32(); }; - break; - case ComponentType::kUnknown: - return []() -> ast::Type* { return nullptr; }; - } - - uint32_t n; - switch (composition) { - case CompositionType::kScalar: - return func; - case CompositionType::kVec2: - n = 2; - break; - case CompositionType::kVec3: - n = 3; - break; - case CompositionType::kVec4: - n = 4; - break; - default: - return []() -> ast::Type* { return nullptr; }; - } - - return [this, func, n]() -> ast::Type* { return ty.vec(func(), n); }; - } - - Inspector& Build() { - if (inspector_) { - return *inspector_; - } - program_ = std::make_unique(std::move(*this)); - [&]() { - ASSERT_TRUE(program_->IsValid()) - << diag::Formatter().format(program_->Diagnostics()); - }(); - inspector_ = std::make_unique(program_.get()); - return *inspector_; - } - - ast::Sampler* sampler_type() { - return ty.sampler(ast::SamplerKind::kSampler); - } - ast::Sampler* comparison_sampler_type() { - return ty.sampler(ast::SamplerKind::kComparisonSampler); - } - - protected: - std::unique_ptr program_; - std::unique_ptr inspector_; -}; - -class InspectorGetEntryPointTest : public InspectorHelper, +// All the tests that descend from InspectorBuilder are expected to define their +// test state via building up the AST through InspectorBuilder and then generate +// the program with ::Build(). +// The returned Inspector from ::Build() can then be used to test expecations. +class InspectorGetEntryPointTest : public InspectorBuilder, public testing::Test {}; typedef std::tuple InspectorGetEntryPointComponentAndCompositionTestParams; class InspectorGetEntryPointComponentAndCompositionTest - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam< InspectorGetEntryPointComponentAndCompositionTestParams> {}; struct InspectorGetEntryPointInterpolateTestParams { @@ -717,35 +52,35 @@ struct InspectorGetEntryPointInterpolateTestParams { inspector::InterpolationSampling out_sampling; }; class InspectorGetEntryPointInterpolateTest - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam< InspectorGetEntryPointInterpolateTestParams> {}; -class InspectorGetRemappedNameForEntryPointTest : public InspectorHelper, +class InspectorGetRemappedNameForEntryPointTest : public InspectorBuilder, public testing::Test {}; -class InspectorGetConstantIDsTest : public InspectorHelper, +class InspectorGetConstantIDsTest : public InspectorBuilder, public testing::Test {}; -class InspectorGetConstantNameToIdMapTest : public InspectorHelper, +class InspectorGetConstantNameToIdMapTest : public InspectorBuilder, public testing::Test {}; -class InspectorGetStorageSizeTest : public InspectorHelper, +class InspectorGetStorageSizeTest : public InspectorBuilder, public testing::Test {}; -class InspectorGetResourceBindingsTest : public InspectorHelper, +class InspectorGetResourceBindingsTest : public InspectorBuilder, public testing::Test {}; -class InspectorGetUniformBufferResourceBindingsTest : public InspectorHelper, +class InspectorGetUniformBufferResourceBindingsTest : public InspectorBuilder, public testing::Test {}; -class InspectorGetStorageBufferResourceBindingsTest : public InspectorHelper, +class InspectorGetStorageBufferResourceBindingsTest : public InspectorBuilder, public testing::Test {}; class InspectorGetReadOnlyStorageBufferResourceBindingsTest - : public InspectorHelper, + : public InspectorBuilder, public testing::Test {}; -class InspectorGetSamplerResourceBindingsTest : public InspectorHelper, +class InspectorGetSamplerResourceBindingsTest : public InspectorBuilder, public testing::Test {}; class InspectorGetComparisonSamplerResourceBindingsTest - : public InspectorHelper, + : public InspectorBuilder, public testing::Test {}; -class InspectorGetSampledTextureResourceBindingsTest : public InspectorHelper, +class InspectorGetSampledTextureResourceBindingsTest : public InspectorBuilder, public testing::Test {}; class InspectorGetSampledArrayTextureResourceBindingsTest - : public InspectorHelper, + : public InspectorBuilder, public testing::Test {}; struct GetSampledTextureTestParams { ast::TextureDimension type_dim; @@ -753,32 +88,32 @@ struct GetSampledTextureTestParams { inspector::ResourceBinding::SampledKind sampled_kind; }; class InspectorGetSampledTextureResourceBindingsTestWithParam - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam {}; class InspectorGetSampledArrayTextureResourceBindingsTestWithParam - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam {}; class InspectorGetMultisampledTextureResourceBindingsTest - : public InspectorHelper, + : public InspectorBuilder, public testing::Test {}; class InspectorGetMultisampledArrayTextureResourceBindingsTest - : public InspectorHelper, + : public InspectorBuilder, public testing::Test {}; typedef GetSampledTextureTestParams GetMultisampledTextureTestParams; class InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam {}; class InspectorGetMultisampledTextureResourceBindingsTestWithParam - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam {}; -class InspectorGetStorageTextureResourceBindingsTest : public InspectorHelper, +class InspectorGetStorageTextureResourceBindingsTest : public InspectorBuilder, public testing::Test {}; struct GetDepthTextureTestParams { ast::TextureDimension type_dim; inspector::ResourceBinding::TextureDimension inspector_dim; }; class InspectorGetDepthTextureResourceBindingsTestWithParam - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam {}; typedef std::tuple @@ -790,13 +125,13 @@ typedef std::tuple GetStorageTextureTestParams; class InspectorGetStorageTextureResourceBindingsTestWithParam - : public InspectorHelper, + : public InspectorBuilder, public testing::TestWithParam {}; -class InspectorGetExternalTextureResourceBindingsTest : public InspectorHelper, +class InspectorGetExternalTextureResourceBindingsTest : public InspectorBuilder, public testing::Test {}; -class InspectorGetSamplerTextureUsesTest : public InspectorHelper, +class InspectorGetSamplerTextureUsesTest : public InspectorBuilder, public testing::Test {}; TEST_F(InspectorGetEntryPointTest, NoFunctions) { diff --git a/src/inspector/test_inspector_builder.cc b/src/inspector/test_inspector_builder.cc new file mode 100644 index 0000000000..8e1912ca01 --- /dev/null +++ b/src/inspector/test_inspector_builder.cc @@ -0,0 +1,495 @@ +// Copyright 2021 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/test_inspector_builder.h" + +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +namespace tint { +namespace inspector { + +InspectorBuilder::InspectorBuilder() = default; +InspectorBuilder::~InspectorBuilder() = default; + +void InspectorBuilder::MakeEmptyBodyFunction(std::string name, + ast::DecorationList decorations) { + Func(name, ast::VariableList(), ty.void_(), ast::StatementList{Return()}, + decorations); +} + +void InspectorBuilder::MakeCallerBodyFunction(std::string caller, + std::vector callees, + ast::DecorationList decorations) { + ast::StatementList body; + body.reserve(callees.size() + 1); + for (auto callee : callees) { + body.push_back(create(Call(callee))); + } + body.push_back(Return()); + + Func(caller, ast::VariableList(), ty.void_(), body, decorations); +} + +ast::Struct* InspectorBuilder::MakeInOutStruct( + std::string name, + std::vector> inout_vars) { + ast::StructMemberList members; + for (auto var : inout_vars) { + std::string member_name; + uint32_t location; + std::tie(member_name, location) = var; + members.push_back(Member(member_name, ty.u32(), {Location(location)})); + } + return Structure(name, members); +} + +// TODO(crbug.com/tint/697): Remove this. +void InspectorBuilder::AddInOutVariables( + std::vector> inout_vars) { + uint32_t location = 0; + for (auto inout : inout_vars) { + std::string in, out; + std::tie(in, out) = inout; + + Global(in, ty.u32(), ast::StorageClass::kInput, nullptr, + ast::DecorationList{ + Location(location++), + ASTNodes().Create( + ID(), ast::DisabledValidation::kIgnoreStorageClass)}); + Global(out, ty.u32(), ast::StorageClass::kOutput, nullptr, + ast::DecorationList{ + Location(location++), + ASTNodes().Create( + ID(), ast::DisabledValidation::kIgnoreStorageClass)}); + } +} + +// TODO(crbug.com/tint/697): Remove this. +void InspectorBuilder::MakeInOutVariableBodyFunction( + std::string name, + std::vector> inout_vars, + ast::DecorationList decorations) { + ast::StatementList stmts; + for (auto inout : inout_vars) { + std::string in, out; + std::tie(in, out) = inout; + stmts.emplace_back(Assign(out, in)); + } + stmts.emplace_back(Return()); + Func(name, ast::VariableList(), ty.void_(), stmts, decorations); +} + +// TODO(crbug.com/tint/697): Remove this. +ast::Function* InspectorBuilder::MakeInOutVariableCallerBodyFunction( + std::string caller, + std::string callee, + std::vector> inout_vars, + ast::DecorationList decorations) { + ast::StatementList stmts; + for (auto inout : inout_vars) { + std::string in, out; + std::tie(in, out) = inout; + stmts.emplace_back(Assign(out, in)); + } + stmts.emplace_back(create(Call(callee))); + stmts.emplace_back(Return()); + + return Func(caller, ast::VariableList(), ty.void_(), stmts, decorations); +} + +ast::Function* InspectorBuilder::MakeConstReferenceBodyFunction( + std::string func, + std::string var, + ast::Type* type, + ast::DecorationList decorations) { + ast::StatementList stmts; + stmts.emplace_back(Decl(Var("local_" + var, type))); + stmts.emplace_back(Assign("local_" + var, var)); + stmts.emplace_back(Return()); + + return Func(func, ast::VariableList(), ty.void_(), stmts, decorations); +} + +bool InspectorBuilder::ContainsName(const std::vector& vec, + const std::string& name) { + for (auto& s : vec) { + if (s.name == name) { + return true; + } + } + return false; +} + +std::string InspectorBuilder::StructMemberName(size_t idx, ast::Type* type) { + return std::to_string(idx) + type->type_name(); +} + +ast::Struct* InspectorBuilder::MakeStructType( + const std::string& name, + std::vector member_types, + bool is_block) { + ast::StructMemberList members; + for (auto* type : member_types) { + members.push_back(Member(StructMemberName(members.size(), type), type)); + } + + ast::DecorationList decos; + if (is_block) { + decos.push_back(create()); + } + + return Structure(name, members, decos); +} + +ast::Struct* InspectorBuilder::MakeUniformBufferType( + const std::string& name, + std::vector member_types) { + return MakeStructType(name, member_types, true); +} + +std::function InspectorBuilder::MakeStorageBufferTypes( + const std::string& name, + std::vector member_types) { + MakeStructType(name, member_types, true); + return [this, name] { return ty.type_name(name); }; +} + +void InspectorBuilder::AddUniformBuffer(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding) { + Global(name, type, ast::StorageClass::kUniform, + ast::DecorationList{ + create(binding), + create(group), + }); +} + +void InspectorBuilder::AddStorageBuffer(const std::string& name, + ast::Type* type, + ast::Access access, + uint32_t group, + uint32_t binding) { + Global(name, type, ast::StorageClass::kStorage, access, + ast::DecorationList{ + create(binding), + create(group), + }); +} + +void InspectorBuilder::MakeStructVariableReferenceBodyFunction( + std::string func_name, + std::string struct_name, + std::vector> members) { + ast::StatementList stmts; + for (auto member : members) { + size_t member_idx; + ast::Type* member_type; + std::tie(member_idx, member_type) = member; + std::string member_name = StructMemberName(member_idx, member_type); + + stmts.emplace_back(Decl(Var("local" + member_name, member_type))); + } + + for (auto member : members) { + size_t member_idx; + ast::Type* member_type; + std::tie(member_idx, member_type) = member; + std::string member_name = StructMemberName(member_idx, member_type); + + stmts.emplace_back(Assign("local" + member_name, + MemberAccessor(struct_name, member_name))); + } + + stmts.emplace_back(Return()); + + Func(func_name, ast::VariableList(), ty.void_(), stmts, + ast::DecorationList{}); +} + +void InspectorBuilder::AddSampler(const std::string& name, + uint32_t group, + uint32_t binding) { + Global(name, sampler_type(), + ast::DecorationList{ + create(binding), + create(group), + }); +} + +void InspectorBuilder::AddComparisonSampler(const std::string& name, + uint32_t group, + uint32_t binding) { + Global(name, comparison_sampler_type(), + ast::DecorationList{ + create(binding), + create(group), + }); +} + +ast::SampledTexture* InspectorBuilder::MakeSampledTextureType( + ast::TextureDimension dim, + ast::Type* type) { + return ty.sampled_texture(dim, type); +} + +ast::DepthTexture* InspectorBuilder::MakeDepthTextureType( + ast::TextureDimension dim) { + return ty.depth_texture(dim); +} + +ast::MultisampledTexture* InspectorBuilder::MakeMultisampledTextureType( + ast::TextureDimension dim, + ast::Type* type) { + return ty.multisampled_texture(dim, type); +} + +ast::ExternalTexture* InspectorBuilder::MakeExternalTextureType() { + return ty.external_texture(); +} + +void InspectorBuilder::AddSampledTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding) { + Global(name, type, + ast::DecorationList{ + create(binding), + create(group), + }); +} + +void InspectorBuilder::AddMultisampledTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding) { + Global(name, type, + ast::DecorationList{ + create(binding), + create(group), + }); +} + +void InspectorBuilder::AddGlobalVariable(const std::string& name, + ast::Type* type) { + Global(name, type, ast::StorageClass::kPrivate); +} + +void InspectorBuilder::AddDepthTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding) { + Global(name, type, + ast::DecorationList{ + create(binding), + create(group), + }); +} + +void InspectorBuilder::AddExternalTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding) { + Global(name, type, + ast::DecorationList{ + create(binding), + create(group), + }); +} + +ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction( + const std::string& func_name, + const std::string& texture_name, + const std::string& sampler_name, + const std::string& coords_name, + ast::Type* base_type, + ast::DecorationList decorations) { + std::string result_name = "sampler_result"; + + ast::StatementList stmts; + stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4)))); + + stmts.emplace_back(Assign(result_name, Call("textureSample", texture_name, + sampler_name, coords_name))); + stmts.emplace_back(Return()); + + return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); +} + +ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction( + const std::string& func_name, + const std::string& texture_name, + const std::string& sampler_name, + const std::string& coords_name, + const std::string& array_index, + ast::Type* base_type, + ast::DecorationList decorations) { + std::string result_name = "sampler_result"; + + ast::StatementList stmts; + + stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4)))); + + stmts.emplace_back( + Assign("sampler_result", Call("textureSample", texture_name, sampler_name, + coords_name, array_index))); + stmts.emplace_back(Return()); + + return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); +} + +ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction( + const std::string& func_name, + const std::string& texture_name, + const std::string& sampler_name, + const std::string& coords_name, + const std::string& depth_name, + ast::Type* base_type, + ast::DecorationList decorations) { + std::string result_name = "sampler_result"; + + ast::StatementList stmts; + + stmts.emplace_back(Decl(Var("sampler_result", base_type))); + stmts.emplace_back( + Assign("sampler_result", Call("textureSampleCompare", texture_name, + sampler_name, coords_name, depth_name))); + stmts.emplace_back(Return()); + + return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); +} + +ast::Type* InspectorBuilder::GetBaseType( + ResourceBinding::SampledKind sampled_kind) { + switch (sampled_kind) { + case ResourceBinding::SampledKind::kFloat: + return ty.f32(); + case ResourceBinding::SampledKind::kSInt: + return ty.i32(); + case ResourceBinding::SampledKind::kUInt: + return ty.u32(); + default: + return nullptr; + } +} + +ast::Type* InspectorBuilder::GetCoordsType(ast::TextureDimension dim, + ast::Type* scalar) { + switch (dim) { + case ast::TextureDimension::k1d: + return scalar; + case ast::TextureDimension::k2d: + case ast::TextureDimension::k2dArray: + return create(scalar, 2); + case ast::TextureDimension::k3d: + case ast::TextureDimension::kCube: + case ast::TextureDimension::kCubeArray: + return create(scalar, 3); + default: + [=]() { FAIL() << "Unsupported texture dimension: " << dim; }(); + } + return nullptr; +} + +ast::Type* InspectorBuilder::MakeStorageTextureTypes(ast::TextureDimension dim, + ast::ImageFormat format, + bool read_only) { + auto access = read_only ? ast::Access::kRead : ast::Access::kWrite; + return ty.storage_texture(dim, format, access); +} + +void InspectorBuilder::AddStorageTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding) { + Global(name, type, + ast::DecorationList{ + create(binding), + create(group), + }); +} + +ast::Function* InspectorBuilder::MakeStorageTextureBodyFunction( + const std::string& func_name, + const std::string& st_name, + ast::Type* dim_type, + ast::DecorationList decorations) { + ast::StatementList stmts; + + stmts.emplace_back(Decl(Var("dim", dim_type))); + stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name))); + stmts.emplace_back(Return()); + + return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); +} + +std::function InspectorBuilder::GetTypeFunction( + ComponentType component, + CompositionType composition) { + std::function func; + switch (component) { + case ComponentType::kFloat: + func = [this]() -> ast::Type* { return ty.f32(); }; + break; + case ComponentType::kSInt: + func = [this]() -> ast::Type* { return ty.i32(); }; + break; + case ComponentType::kUInt: + func = [this]() -> ast::Type* { return ty.u32(); }; + break; + case ComponentType::kUnknown: + return []() -> ast::Type* { return nullptr; }; + } + + uint32_t n; + switch (composition) { + case CompositionType::kScalar: + return func; + case CompositionType::kVec2: + n = 2; + break; + case CompositionType::kVec3: + n = 3; + break; + case CompositionType::kVec4: + n = 4; + break; + default: + return []() -> ast::Type* { return nullptr; }; + } + + return [this, func, n]() -> ast::Type* { return ty.vec(func(), n); }; +} + +Inspector& InspectorBuilder::Build() { + if (inspector_) { + return *inspector_; + } + program_ = std::make_unique(std::move(*this)); + [&]() { + ASSERT_TRUE(program_->IsValid()) + << diag::Formatter().format(program_->Diagnostics()); + }(); + inspector_ = std::make_unique(program_.get()); + return *inspector_; +} + +} // namespace inspector +} // namespace tint diff --git a/src/inspector/test_inspector_builder.h b/src/inspector/test_inspector_builder.h new file mode 100644 index 0000000000..3d1353dc0c --- /dev/null +++ b/src/inspector/test_inspector_builder.h @@ -0,0 +1,434 @@ +// Copyright 2021 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_TEST_INSPECTOR_BUILDER_H_ +#define SRC_INSPECTOR_TEST_INSPECTOR_BUILDER_H_ + +#include +#include +#include +#include + +#include "src/ast/call_statement.h" +#include "src/ast/disable_validation_decoration.h" +#include "src/ast/override_decoration.h" +#include "src/ast/stage_decoration.h" +#include "src/ast/struct_block_decoration.h" +#include "src/ast/workgroup_decoration.h" +#include "src/program_builder.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" +#include "tint/tint.h" + +namespace tint { +namespace inspector { + +/// Utility class for building programs in inspector tests +class InspectorBuilder : public ProgramBuilder { + public: + InspectorBuilder(); + ~InspectorBuilder() override; + + /// Generates an empty function + /// @param name name of the function created + /// @param decorations the function decorations + void MakeEmptyBodyFunction(std::string name, ast::DecorationList decorations); + + /// Generates a function that calls other functions + /// @param caller name of the function created + /// @param callees names of the functions to be called + /// @param decorations the function decorations + void MakeCallerBodyFunction(std::string caller, + std::vector callees, + ast::DecorationList decorations); + + /// Generates a struct that contains user-defined IO members + /// @param name the name of the generated struct + /// @param inout_vars tuples of {name, loc} that will be the struct members + /// @returns a structure object + ast::Struct* MakeInOutStruct( + std::string name, + std::vector> inout_vars); + + // TODO(crbug.com/tint/697): Remove this. + /// Add In/Out variables to the global variables + /// @param inout_vars tuples of {in, out} that will be added as entries to the + /// global variables + void AddInOutVariables( + std::vector> inout_vars); + + // TODO(crbug.com/tint/697): Remove this. + /// Generates a function that references in/out variables + /// @param name name of the function created + /// @param inout_vars tuples of {in, out} that will be converted into out = in + /// calls in the function body + /// @param decorations the function decorations + void MakeInOutVariableBodyFunction( + std::string name, + std::vector> inout_vars, + ast::DecorationList decorations); + + // TODO(crbug.com/tint/697): Remove this. + /// Generates a function that references in/out variables and calls another + /// function. + /// @param caller name of the function created + /// @param callee name of the function to be called + /// @param inout_vars tuples of {in, out} that will be converted into out = in + /// calls in the function body + /// @param decorations the function decorations + /// @returns a function object + ast::Function* MakeInOutVariableCallerBodyFunction( + std::string caller, + std::string callee, + std::vector> inout_vars, + ast::DecorationList decorations); + + /// Add a pipeline constant to the global variables, with a specific ID. + /// @param name name of the variable to add + /// @param id id number for the constant id + /// @param type type of the variable + /// @param val value to initialize the variable with, if NULL no initializer + /// will be added. + /// @returns the constant that was created + template + ast::Variable* AddOverridableConstantWithID(std::string name, + uint32_t id, + ast::Type* type, + T* val) { + ast::Expression* constructor = nullptr; + if (val) { + constructor = Expr(*val); + } + return GlobalConst(name, type, constructor, + ast::DecorationList{ + Override(id), + }); + } + + /// Add a pipeline constant to the global variables, without a specific ID. + /// @param name name of the variable to add + /// @param type type of the variable + /// @param val value to initialize the variable with, if NULL no initializer + /// will be added. + /// @returns the constant that was created + template + ast::Variable* AddOverridableConstantWithoutID(std::string name, + ast::Type* type, + T* val) { + ast::Expression* constructor = nullptr; + if (val) { + constructor = Expr(*val); + } + return GlobalConst(name, type, constructor, + ast::DecorationList{ + Override(), + }); + } + + /// Generates a function that references module constant + /// @param func name of the function created + /// @param var name of the constant to be reference + /// @param type type of the const being referenced + /// @param decorations the function decorations + /// @returns a function object + ast::Function* MakeConstReferenceBodyFunction( + std::string func, + std::string var, + ast::Type* type, + ast::DecorationList decorations); + + /// @param vec Vector of StageVariable to be searched + /// @param name Name to be searching for + /// @returns true if name is in vec, otherwise false + bool ContainsName(const std::vector& vec, + const std::string& name); + + /// Builds a string for accessing a member in a generated struct + /// @param idx index of member + /// @param type type of member + /// @returns a string for the member + std::string StructMemberName(size_t idx, ast::Type* type); + + /// Generates a struct type + /// @param name name for the type + /// @param member_types a vector of member types + /// @param is_block whether or not to decorate as a Block + /// @returns a struct type + ast::Struct* MakeStructType(const std::string& name, + std::vector member_types, + bool is_block); + + /// Generates types appropriate for using in an uniform buffer + /// @param name name for the type + /// @param member_types a vector of member types + /// @returns a struct type that has the layout for an uniform buffer. + ast::Struct* MakeUniformBufferType(const std::string& name, + std::vector member_types); + + /// Generates types appropriate for using in a storage buffer + /// @param name name for the type + /// @param member_types a vector of member types + /// @returns a function that returns the created structure. + std::function MakeStorageBufferTypes( + const std::string& name, + std::vector member_types); + + /// Adds an uniform buffer 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 uniform buffer + /// @param binding the binding number to use for the uniform buffer + void AddUniformBuffer(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding); + + /// Adds a storage buffer variable to the program + /// @param name the name of the variable + /// @param type the type to use + /// @param access the storage buffer access control + /// @param group the binding/group to use for the storage buffer + /// @param binding the binding number to use for the storage buffer + void AddStorageBuffer(const std::string& name, + ast::Type* type, + ast::Access access, + uint32_t group, + uint32_t binding); + + /// Generates a function that references a specific struct variable + /// @param func_name name of the function created + /// @param struct_name name of the struct variabler to be accessed + /// @param members list of members to access, by index and type + void MakeStructVariableReferenceBodyFunction( + std::string func_name, + std::string struct_name, + std::vector> members); + + /// Adds a regular sampler variable to the program + /// @param name the name of the variable + /// @param group the binding/group 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 group, uint32_t binding); + + /// Adds a comparison sampler variable to the program + /// @param name the name of the variable + /// @param group the binding/group 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 group, + uint32_t binding); + + /// Generates a SampledTexture appropriate for the params + /// @param dim the dimensions of the texture + /// @param type the data type of the sampled texture + /// @returns the generated SampleTextureType + ast::SampledTexture* MakeSampledTextureType(ast::TextureDimension dim, + ast::Type* type); + + /// Generates a DepthTexture appropriate for the params + /// @param dim the dimensions of the texture + /// @returns the generated DepthTexture + ast::DepthTexture* MakeDepthTextureType(ast::TextureDimension dim); + + /// Generates a MultisampledTexture appropriate for the params + /// @param dim the dimensions of the texture + /// @param type the data type of the sampled texture + /// @returns the generated SampleTextureType + ast::MultisampledTexture* MakeMultisampledTextureType( + ast::TextureDimension dim, + ast::Type* type); + + /// Generates an ExternalTexture appropriate for the params + /// @returns the generated ExternalTexture + ast::ExternalTexture* MakeExternalTextureType(); + + /// Adds a sampled 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 sampled texture + /// @param binding the binding number to use for the sampled texture + void AddSampledTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding); + + /// Adds a multi-sampled 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 multi-sampled texture + /// @param binding the binding number to use for the multi-sampled texture + void AddMultisampledTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding); + + /// Add a module scope private variable to the progames + /// @param name the name of the variable + /// @param type the type to use + void AddGlobalVariable(const std::string& name, ast::Type* type); + + /// Adds a depth 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 depth texture + /// @param binding the binding number to use for the depth texture + void AddDepthTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t 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); + + /// 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 + /// @param sampler_name name of the sampler to use + /// @param coords_name name of the coords variable to use + /// @param base_type sampler base type + /// @param decorations the function decorations + /// @returns a function that references all of the values specified + ast::Function* MakeSamplerReferenceBodyFunction( + const std::string& func_name, + const std::string& texture_name, + const std::string& sampler_name, + const std::string& coords_name, + ast::Type* base_type, + ast::DecorationList decorations); + + /// 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 + /// @param sampler_name name of the sampler to use + /// @param coords_name name of the coords variable to use + /// @param array_index name of the array index variable to use + /// @param base_type sampler base type + /// @param decorations the function decorations + /// @returns a function that references all of the values specified + ast::Function* MakeSamplerReferenceBodyFunction( + const std::string& func_name, + const std::string& texture_name, + const std::string& sampler_name, + const std::string& coords_name, + const std::string& array_index, + ast::Type* base_type, + ast::DecorationList decorations); + + /// Generates a function that references a specific comparison sampler + /// variable. + /// @param func_name name of the function created + /// @param texture_name name of the depth texture to use + /// @param sampler_name name of the sampler to use + /// @param coords_name name of the coords variable to use + /// @param depth_name name of the depth reference to use + /// @param base_type sampler base type + /// @param decorations the function decorations + /// @returns a function that references all of the values specified + ast::Function* MakeComparisonSamplerReferenceBodyFunction( + const std::string& func_name, + const std::string& texture_name, + const std::string& sampler_name, + const std::string& coords_name, + const std::string& depth_name, + ast::Type* base_type, + ast::DecorationList decorations); + + /// 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* GetBaseType(ResourceBinding::SampledKind sampled_kind); + + /// 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 scalar the scalar type + /// @returns a pointer to a type appropriate for the coord param + ast::Type* GetCoordsType(ast::TextureDimension dim, ast::Type* scalar); + + /// Generates appropriate types for a Read-Only StorageTexture + /// @param dim the texture dimension of the storage texture + /// @param format the image format of the storage texture + /// @param read_only should the access type be read only, otherwise write only + /// @returns the storage texture type + ast::Type* MakeStorageTextureTypes(ast::TextureDimension dim, + ast::ImageFormat format, + bool read_only); + + /// Adds a storage 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 sampled texture + /// @param binding the binding57 number to use for the sampled texture + void AddStorageTexture(const std::string& name, + ast::Type* type, + uint32_t group, + uint32_t binding); + + /// Generates a function that references a storage texture variable. + /// @param func_name name of the function created + /// @param st_name name of the storage texture to use + /// @param dim_type type expected by textureDimensons to return + /// @param decorations the function decorations + /// @returns a function that references all of the values specified + ast::Function* MakeStorageTextureBodyFunction( + const std::string& func_name, + const std::string& st_name, + ast::Type* dim_type, + ast::DecorationList decorations); + + /// Get a generator function that returns a type appropriate for a stage + /// variable with the given combination of component and composition type. + /// @param component component type of the stage variable + /// @param composition composition type of the stage variable + /// @returns a generator function for the stage variable's type. + std::function GetTypeFunction(ComponentType component, + CompositionType composition); + + /// Build the Program given all of the previous methods called and return an + /// Inspector for it. + /// Should only be called once per test. + /// @returns a reference to the Inspector for the built Program. + Inspector& Build(); + + /// @returns the type for a SamplerKind::kSampler + ast::Sampler* sampler_type() { + return ty.sampler(ast::SamplerKind::kSampler); + } + + /// @returns the type for a SamplerKind::kComparison + ast::Sampler* comparison_sampler_type() { + return ty.sampler(ast::SamplerKind::kComparisonSampler); + } + + protected: + /// Program built by this builder. + std::unique_ptr program_; + /// Inspector for |program_| + std::unique_ptr inspector_; +}; + +} // namespace inspector +} // namespace tint + +#endif // SRC_INSPECTOR_TEST_INSPECTOR_BUILDER_H_ diff --git a/test/BUILD.gn b/test/BUILD.gn index 2fd1d3163a..f80e0726b5 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -221,6 +221,8 @@ tint_unittests_source_set("tint_unittests_core_src") { "../src/diagnostic/formatter_test.cc", "../src/diagnostic/printer_test.cc", "../src/inspector/inspector_test.cc", + "../src/inspector/test_inspector_builder.cc", + "../src/inspector/test_inspector_builder.h", "../src/intrinsic_table_test.cc", "../src/program_builder_test.cc", "../src/program_test.cc",