diff --git a/src/tint/ast/variable.cc b/src/tint/ast/variable.cc index ec87e54bbd..bb719c062f 100644 --- a/src/tint/ast/variable.cc +++ b/src/tint/ast/variable.cc @@ -37,16 +37,4 @@ Variable::Variable(Variable&&) = default; Variable::~Variable() = default; -VariableBindingPoint Variable::BindingPoint() const { - const GroupAttribute* group = nullptr; - const BindingAttribute* binding = nullptr; - for (auto* attr : attributes) { - Switch( - attr, // - [&](const GroupAttribute* a) { group = a; }, - [&](const BindingAttribute* a) { binding = a; }); - } - return VariableBindingPoint{group, binding}; -} - } // namespace tint::ast diff --git a/src/tint/ast/variable.h b/src/tint/ast/variable.h index 1f5d77a20a..8772f5beb7 100644 --- a/src/tint/ast/variable.h +++ b/src/tint/ast/variable.h @@ -20,31 +20,19 @@ #include "src/tint/ast/access.h" #include "src/tint/ast/attribute.h" +#include "src/tint/ast/binding_attribute.h" #include "src/tint/ast/expression.h" +#include "src/tint/ast/group_attribute.h" #include "src/tint/ast/storage_class.h" // Forward declarations namespace tint::ast { -class BindingAttribute; -class GroupAttribute; class LocationAttribute; class Type; } // namespace tint::ast namespace tint::ast { -/// VariableBindingPoint holds a group and binding attribute. -struct VariableBindingPoint { - /// The `@group` part of the binding point - const GroupAttribute* group = nullptr; - /// The `@binding` part of the binding point - const BindingAttribute* binding = nullptr; - - /// @returns true if the BindingPoint has a valid group and binding - /// attribute. - inline operator bool() const { return group && binding; } -}; - /// Variable is the base class for Var, Let, Const, Override and Parameter. /// /// An instance of this class represents one of five constructs in WGSL: "var" declaration, "let" @@ -75,9 +63,11 @@ class Variable : public Castable { /// Destructor ~Variable() override; - /// @returns the binding point information from the variable's attributes. - /// @note binding points should only be applied to Var and Parameter types. - VariableBindingPoint BindingPoint() const; + /// @returns true if the variable has both group and binding attributes + bool HasBindingPoint() const { + return ast::GetAttribute(attributes) != nullptr && + ast::GetAttribute(attributes) != nullptr; + } /// @returns the kind of the variable, which can be used in diagnostics /// e.g. "var", "let", "const", etc diff --git a/src/tint/ast/variable_test.cc b/src/tint/ast/variable_test.cc index 12f528bc30..14fb766f46 100644 --- a/src/tint/ast/variable_test.cc +++ b/src/tint/ast/variable_test.cc @@ -105,36 +105,24 @@ TEST_F(VariableTest, WithAttributes) { EXPECT_EQ(1u, location->value); } -TEST_F(VariableTest, BindingPoint) { +TEST_F(VariableTest, HasBindingPoint_BothProvided) { auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Binding(2), Group(1)); - EXPECT_TRUE(var->BindingPoint()); - ASSERT_NE(var->BindingPoint().binding, nullptr); - ASSERT_NE(var->BindingPoint().group, nullptr); - EXPECT_EQ(var->BindingPoint().binding->value, 2u); - EXPECT_EQ(var->BindingPoint().group->value, 1u); + EXPECT_TRUE(var->HasBindingPoint()); } -TEST_F(VariableTest, BindingPointAttributes) { +TEST_F(VariableTest, HasBindingPoint_NeitherProvided) { auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, utils::Empty); - EXPECT_FALSE(var->BindingPoint()); - EXPECT_EQ(var->BindingPoint().group, nullptr); - EXPECT_EQ(var->BindingPoint().binding, nullptr); + EXPECT_FALSE(var->HasBindingPoint()); } -TEST_F(VariableTest, BindingPointMissingGroupAttribute) { +TEST_F(VariableTest, HasBindingPoint_MissingGroupAttribute) { auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Binding(2)); - EXPECT_FALSE(var->BindingPoint()); - ASSERT_NE(var->BindingPoint().binding, nullptr); - EXPECT_EQ(var->BindingPoint().binding->value, 2u); - EXPECT_EQ(var->BindingPoint().group, nullptr); + EXPECT_FALSE(var->HasBindingPoint()); } -TEST_F(VariableTest, BindingPointMissingBindingAttribute) { +TEST_F(VariableTest, HasBindingPoint_MissingBindingAttribute) { auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Group(1)); - EXPECT_FALSE(var->BindingPoint()); - ASSERT_NE(var->BindingPoint().group, nullptr); - EXPECT_EQ(var->BindingPoint().group->value, 1u); - EXPECT_EQ(var->BindingPoint().binding, nullptr); + EXPECT_FALSE(var->HasBindingPoint()); } } // namespace diff --git a/src/tint/inspector/inspector.cc b/src/tint/inspector/inspector.cc index 60734709d8..2f8d09ac02 100644 --- a/src/tint/inspector/inspector.cc +++ b/src/tint/inspector/inspector.cc @@ -370,8 +370,8 @@ std::vector Inspector::GetUniformBufferResourceBindings( ResourceBinding entry; entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer; - entry.bind_group = binding_info.group->value; - entry.binding = binding_info.binding->value; + entry.bind_group = binding_info.group; + entry.binding = binding_info.binding; entry.size = unwrapped_type->Size(); entry.size_no_padding = entry.size; if (auto* str = unwrapped_type->As()) { @@ -410,8 +410,8 @@ std::vector Inspector::GetSamplerResourceBindings(const std::st ResourceBinding entry; entry.resource_type = ResourceBinding::ResourceType::kSampler; - entry.bind_group = binding_info.group->value; - entry.binding = binding_info.binding->value; + entry.bind_group = binding_info.group; + entry.binding = binding_info.binding; result.push_back(entry); } @@ -434,8 +434,8 @@ std::vector Inspector::GetComparisonSamplerResourceBindings( ResourceBinding entry; entry.resource_type = ResourceBinding::ResourceType::kComparisonSampler; - entry.bind_group = binding_info.group->value; - entry.binding = binding_info.binding->value; + entry.bind_group = binding_info.group; + entry.binding = binding_info.binding; result.push_back(entry); } @@ -475,8 +475,8 @@ std::vector Inspector::GetTextureResourceBindings( ResourceBinding entry; entry.resource_type = resource_type; - entry.bind_group = binding_info.group->value; - entry.binding = binding_info.binding->value; + entry.bind_group = binding_info.group; + entry.binding = binding_info.binding; auto* tex = var->Type()->UnwrapRef()->As(); entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(tex->dim()); @@ -692,8 +692,8 @@ std::vector Inspector::GetStorageBufferResourceBindingsImpl( ResourceBinding entry; entry.resource_type = read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer : ResourceBinding::ResourceType::kStorageBuffer; - entry.bind_group = binding_info.group->value; - entry.binding = binding_info.binding->value; + entry.bind_group = binding_info.group; + entry.binding = binding_info.binding; entry.size = unwrapped_type->Size(); if (auto* str = unwrapped_type->As()) { entry.size_no_padding = str->SizeNoPadding(); @@ -728,8 +728,8 @@ std::vector Inspector::GetSampledTextureResourceBindingsImpl( entry.resource_type = multisampled_only ? ResourceBinding::ResourceType::kMultisampledTexture : ResourceBinding::ResourceType::kSampledTexture; - entry.bind_group = binding_info.group->value; - entry.binding = binding_info.binding->value; + entry.bind_group = binding_info.group; + entry.binding = binding_info.binding; auto* texture_type = var->Type()->UnwrapRef()->As(); entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim()); @@ -765,8 +765,8 @@ std::vector Inspector::GetStorageTextureResourceBindingsImpl( ResourceBinding entry; entry.resource_type = ResourceBinding::ResourceType::kWriteOnlyStorageTexture; - entry.bind_group = binding_info.group->value; - entry.binding = binding_info.binding->value; + entry.bind_group = binding_info.group; + entry.binding = binding_info.binding; entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim()); @@ -838,13 +838,8 @@ void Inspector::GenerateSamplerTargets() { GetOriginatingResources( std::array{t, s}, [&](std::array globals) { - auto* texture = globals[0]->Declaration()->As(); - sem::BindingPoint texture_binding_point = {texture->BindingPoint().group->value, - texture->BindingPoint().binding->value}; - - auto* sampler = globals[1]->Declaration()->As(); - sem::BindingPoint sampler_binding_point = {sampler->BindingPoint().group->value, - sampler->BindingPoint().binding->value}; + auto texture_binding_point = globals[0]->BindingPoint(); + auto sampler_binding_point = globals[1]->BindingPoint(); for (auto* entry_point : entry_points) { const auto& ep_name = diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 40156c941c..ed0739923e 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -578,8 +578,21 @@ sem::Variable* Resolver::Var(const ast::Var* var, bool is_global) { sem::Variable* sem = nullptr; if (is_global) { sem::BindingPoint binding_point; - if (auto bp = var->BindingPoint()) { - binding_point = {bp.group->value, bp.binding->value}; + if (var->HasBindingPoint()) { + uint32_t binding = 0; + { + auto* attr = ast::GetAttribute(var->attributes); + // TODO(dsinclair): Materialize when binding attribute is an expression + binding = attr->value; + } + + uint32_t group = 0; + { + auto* attr = ast::GetAttribute(var->attributes); + // TODO(dsinclair): Materialize when group attribute is an expression + group = attr->value; + } + binding_point = {group, binding}; } sem = builder_->create(var, var_ty, sem::EvaluationStage::kRuntime, storage_class, access, @@ -629,8 +642,23 @@ sem::Parameter* Resolver::Parameter(const ast::Parameter* param, uint32_t index) } } + sem::BindingPoint binding_point; + if (param->HasBindingPoint()) { + { + auto* attr = ast::GetAttribute(param->attributes); + // TODO(dsinclair): Materialize the binding information + binding_point.binding = attr->value; + } + { + auto* attr = ast::GetAttribute(param->attributes); + // TODO(dsinclair): Materialize the group information + binding_point.group = attr->value; + } + } + auto* sem = builder_->create(param, index, ty, ast::StorageClass::kNone, - ast::Access::kUndefined); + ast::Access::kUndefined, + sem::ParameterUsage::kNone, binding_point); builder_->Sem().Add(param, sem); return sem; } diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc index 6382d34d93..08451f0466 100644 --- a/src/tint/resolver/validator.cc +++ b/src/tint/resolver/validator.cc @@ -664,7 +664,6 @@ bool Validator::GlobalVariable( return false; } - auto binding_point = decl->BindingPoint(); switch (global->StorageClass()) { case ast::StorageClass::kUniform: case ast::StorageClass::kStorage: @@ -672,20 +671,23 @@ bool Validator::GlobalVariable( // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface // Each resource variable must be declared with both group and binding // attributes. - if (!binding_point) { + if (!decl->HasBindingPoint()) { AddError("resource variables require @group and @binding attributes", decl->source); return false; } break; } - default: - if (binding_point.binding || binding_point.group) { + default: { + auto* binding_attr = ast::GetAttribute(decl->attributes); + auto* group_attr = ast::GetAttribute(decl->attributes); + if (binding_attr || group_attr) { // https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding // Must only be applied to a resource variable AddError("non-resource variables must not have @group or @binding attributes", decl->source); return false; } + } } return true; @@ -1351,7 +1353,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage) std::unordered_map binding_points; for (auto* global : func->TransitivelyReferencedGlobals()) { auto* var_decl = global->Declaration()->As(); - if (!var_decl || !var_decl->BindingPoint()) { + if (!var_decl || !var_decl->HasBindingPoint()) { continue; } auto bp = global->BindingPoint(); diff --git a/src/tint/sem/function.cc b/src/tint/sem/function.cc index ff3a2a7085..97171fe470 100644 --- a/src/tint/sem/function.cc +++ b/src/tint/sem/function.cc @@ -70,8 +70,8 @@ Function::VariableBindings Function::TransitivelyReferencedUniformVariables() co continue; } - if (auto binding_point = global->Declaration()->BindingPoint()) { - ret.push_back({global, binding_point}); + if (global->Declaration()->HasBindingPoint()) { + ret.push_back({global, global->BindingPoint()}); } } return ret; @@ -85,8 +85,8 @@ Function::VariableBindings Function::TransitivelyReferencedStorageBufferVariable continue; } - if (auto binding_point = global->Declaration()->BindingPoint()) { - ret.push_back({global, binding_point}); + if (global->Declaration()->HasBindingPoint()) { + ret.push_back({global, global->BindingPoint()}); } } return ret; @@ -129,8 +129,8 @@ Function::VariableBindings Function::TransitivelyReferencedVariablesOfType( for (auto* global : TransitivelyReferencedGlobals()) { auto* unwrapped_type = global->Type()->UnwrapRef(); if (unwrapped_type->TypeInfo().Is(type)) { - if (auto binding_point = global->Declaration()->BindingPoint()) { - ret.push_back({global, binding_point}); + if (global->Declaration()->HasBindingPoint()) { + ret.push_back({global, global->BindingPoint()}); } } } @@ -157,8 +157,8 @@ Function::VariableBindings Function::TransitivelyReferencedSamplerVariablesImpl( continue; } - if (auto binding_point = global->Declaration()->BindingPoint()) { - ret.push_back({global, binding_point}); + if (global->Declaration()->HasBindingPoint()) { + ret.push_back({global, global->BindingPoint()}); } } return ret; @@ -182,8 +182,8 @@ Function::VariableBindings Function::TransitivelyReferencedSampledTextureVariabl continue; } - if (auto binding_point = global->Declaration()->BindingPoint()) { - ret.push_back({global, binding_point}); + if (global->Declaration()->HasBindingPoint()) { + ret.push_back({global, global->BindingPoint()}); } } diff --git a/src/tint/sem/function.h b/src/tint/sem/function.h index a09f81c756..d4cb1c7eac 100644 --- a/src/tint/sem/function.h +++ b/src/tint/sem/function.h @@ -54,8 +54,8 @@ using WorkgroupSize = std::array; /// Function holds the semantic information for function nodes. class Function final : public Castable { public: - /// A vector of [Variable*, ast::VariableBindingPoint] pairs - using VariableBindings = std::vector>; + /// A vector of [Variable*, sem::BindingPoint] pairs + using VariableBindings = std::vector>; /// Constructor /// @param declaration the ast::Function diff --git a/src/tint/sem/variable.cc b/src/tint/sem/variable.cc index 28a373b613..f2330538fd 100644 --- a/src/tint/sem/variable.cc +++ b/src/tint/sem/variable.cc @@ -72,10 +72,12 @@ Parameter::Parameter(const ast::Parameter* declaration, const sem::Type* type, ast::StorageClass storage_class, ast::Access access, - const ParameterUsage usage /* = ParameterUsage::kNone */) + const ParameterUsage usage /* = ParameterUsage::kNone */, + sem::BindingPoint binding_point /* = {} */) : Base(declaration, type, EvaluationStage::kRuntime, storage_class, access, nullptr), index_(index), - usage_(usage) {} + usage_(usage), + binding_point_(binding_point) {} Parameter::~Parameter() = default; diff --git a/src/tint/sem/variable.h b/src/tint/sem/variable.h index 2bf6d23ee6..b511563cc4 100644 --- a/src/tint/sem/variable.h +++ b/src/tint/sem/variable.h @@ -188,12 +188,14 @@ class Parameter final : public Castable { /// @param storage_class the variable storage class /// @param access the variable access control type /// @param usage the semantic usage for the parameter + /// @param binding_point the optional resource binding point of the parameter Parameter(const ast::Parameter* declaration, uint32_t index, const sem::Type* type, ast::StorageClass storage_class, ast::Access access, - const ParameterUsage usage = ParameterUsage::kNone); + const ParameterUsage usage = ParameterUsage::kNone, + sem::BindingPoint binding_point = {}); /// Destructor ~Parameter() override; @@ -217,11 +219,15 @@ class Parameter final : public Castable { /// @param shadows the Type, Function or Variable that this variable shadows void SetShadows(const sem::Node* shadows) { shadows_ = shadows; } + /// @returns the resource binding point for the parameter + sem::BindingPoint BindingPoint() const { return binding_point_; } + private: const uint32_t index_; const ParameterUsage usage_; CallTarget const* owner_ = nullptr; const sem::Node* shadows_ = nullptr; + const sem::BindingPoint binding_point_; }; /// VariableUser holds the semantic information for an identifier expression diff --git a/src/tint/transform/binding_remapper.cc b/src/tint/transform/binding_remapper.cc index 28071453c7..eaf9725453 100644 --- a/src/tint/transform/binding_remapper.cc +++ b/src/tint/transform/binding_remapper.cc @@ -69,8 +69,9 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co auto* func = ctx.src->Sem().Get(func_ast); std::unordered_map binding_point_counts; for (auto* global : func->TransitivelyReferencedGlobals()) { - if (auto binding_point = global->Declaration()->BindingPoint()) { - BindingPoint from{binding_point.group->value, binding_point.binding->value}; + if (global->Declaration()->HasBindingPoint()) { + BindingPoint from = global->BindingPoint(); + auto bp_it = remappings->binding_points.find(from); if (bp_it != remappings->binding_points.end()) { // Remapped @@ -90,9 +91,11 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co } for (auto* var : ctx.src->AST().Globals()) { - if (auto binding_point = var->BindingPoint()) { + if (var->HasBindingPoint()) { + auto* global_sem = ctx.src->Sem().Get(var); + // The original binding point - BindingPoint from{binding_point.group->value, binding_point.binding->value}; + BindingPoint from = global_sem->BindingPoint(); // The binding point after remapping BindingPoint bp = from; @@ -106,8 +109,11 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co auto* new_group = ctx.dst->create(to.group); auto* new_binding = ctx.dst->create(to.binding); - ctx.Replace(binding_point.group, new_group); - ctx.Replace(binding_point.binding, new_binding); + auto* old_group = ast::GetAttribute(var->attributes); + auto* old_binding = ast::GetAttribute(var->attributes); + + ctx.Replace(old_group, new_group); + ctx.Replace(old_binding, new_binding); bp = to; } diff --git a/src/tint/transform/combine_samplers.cc b/src/tint/transform/combine_samplers.cc index 13e6de4c22..6290b26490 100644 --- a/src/tint/transform/combine_samplers.cc +++ b/src/tint/transform/combine_samplers.cc @@ -149,12 +149,14 @@ struct CombineSamplers::State { // Remove all texture and sampler global variables. These will be replaced // by combined samplers. for (auto* global : ctx.src->AST().GlobalVariables()) { + auto* global_sem = sem.Get(global)->As(); auto* type = sem.Get(global->type); if (tint::IsAnyOf(type) && !type->Is()) { ctx.Remove(ctx.src->AST().GlobalDeclarations(), global); - } else if (auto binding_point = global->BindingPoint()) { - if (binding_point.group->value == 0 && binding_point.binding->value == 0) { + } else if (global->HasBindingPoint()) { + auto binding_point = global_sem->BindingPoint(); + if (binding_point.group == 0 && binding_point.binding == 0) { auto* attribute = ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision); ctx.InsertFront(global->attributes, attribute); diff --git a/src/tint/transform/multiplanar_external_texture.cc b/src/tint/transform/multiplanar_external_texture.cc index d3ac05f03d..2fb4248549 100644 --- a/src/tint/transform/multiplanar_external_texture.cc +++ b/src/tint/transform/multiplanar_external_texture.cc @@ -87,7 +87,7 @@ struct MultiplanarExternalTexture::State { // represent the secondary plane and one uniform buffer for the // ExternalTextureParams struct). for (auto* global : ctx.src->AST().GlobalVariables()) { - auto* sem_var = sem.Get(global); + auto* sem_var = sem.Get(global); if (!sem_var->Type()->UnwrapRef()->Is()) { continue; } @@ -109,8 +109,7 @@ struct MultiplanarExternalTexture::State { // provided to this transform. We fetch the new binding points by // providing the original texture_external binding points into the // passed map. - BindingPoint bp = {global->BindingPoint().group->value, - global->BindingPoint().binding->value}; + BindingPoint bp = sem_var->BindingPoint(); BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp); if (it == new_binding_points->bindings_map.end()) { diff --git a/src/tint/transform/num_workgroups_from_uniform.cc b/src/tint/transform/num_workgroups_from_uniform.cc index 293c6c49e9..5772424426 100644 --- a/src/tint/transform/num_workgroups_from_uniform.cc +++ b/src/tint/transform/num_workgroups_from_uniform.cc @@ -136,9 +136,11 @@ void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, Dat group = 0; for (auto* global : ctx.src->AST().GlobalVariables()) { - if (auto binding_point = global->BindingPoint()) { - if (binding_point.group->value >= group) { - group = binding_point.group->value + 1; + if (global->HasBindingPoint()) { + auto* global_sem = ctx.src->Sem().Get(global); + auto binding_point = global_sem->BindingPoint(); + if (binding_point.group >= group) { + group = binding_point.group + 1; } } } diff --git a/src/tint/writer/flatten_bindings.cc b/src/tint/writer/flatten_bindings.cc index 1efc02a87f..bedec75969 100644 --- a/src/tint/writer/flatten_bindings.cc +++ b/src/tint/writer/flatten_bindings.cc @@ -33,6 +33,7 @@ std::optional FlattenBindings(const Program* program) { auto entry_points = inspector.GetEntryPoints(); for (auto& entry_point : entry_points) { auto bindings = inspector.GetResourceBindings(entry_point.name); + for (auto& binding : bindings) { BindingPoint src = {binding.bind_group, binding.binding}; if (binding_points.count(src)) { diff --git a/src/tint/writer/flatten_bindings_test.cc b/src/tint/writer/flatten_bindings_test.cc index 830e7203dd..7137218c08 100644 --- a/src/tint/writer/flatten_bindings_test.cc +++ b/src/tint/writer/flatten_bindings_test.cc @@ -18,7 +18,6 @@ #include "gtest/gtest.h" #include "src/tint/program_builder.h" -#include "src/tint/resolver/resolver.h" #include "src/tint/sem/variable.h" namespace tint::writer { @@ -28,9 +27,6 @@ class FlattenBindingsTest : public ::testing::Test {}; TEST_F(FlattenBindingsTest, NoBindings) { ProgramBuilder b; - - resolver::Resolver resolver(&b); - Program program(std::move(b)); ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str(); @@ -44,8 +40,6 @@ TEST_F(FlattenBindingsTest, AlreadyFlat) { b.GlobalVar("b", b.ty.i32(), ast::StorageClass::kUniform, b.Group(0), b.Binding(1)); b.GlobalVar("c", b.ty.i32(), ast::StorageClass::kUniform, b.Group(0), b.Binding(2)); - resolver::Resolver resolver(&b); - Program program(std::move(b)); ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str(); @@ -60,8 +54,6 @@ TEST_F(FlattenBindingsTest, NotFlat_SingleNamespace) { b.GlobalVar("c", b.ty.i32(), ast::StorageClass::kUniform, b.Group(2), b.Binding(2)); b.WrapInFunction(b.Expr("a"), b.Expr("b"), b.Expr("c")); - resolver::Resolver resolver(&b); - Program program(std::move(b)); ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str(); @@ -69,12 +61,21 @@ TEST_F(FlattenBindingsTest, NotFlat_SingleNamespace) { EXPECT_TRUE(flattened); auto& vars = flattened->AST().GlobalVariables(); - EXPECT_EQ(vars[0]->BindingPoint().group->value, 0u); - EXPECT_EQ(vars[0]->BindingPoint().binding->value, 0u); - EXPECT_EQ(vars[1]->BindingPoint().group->value, 0u); - EXPECT_EQ(vars[1]->BindingPoint().binding->value, 1u); - EXPECT_EQ(vars[2]->BindingPoint().group->value, 0u); - EXPECT_EQ(vars[2]->BindingPoint().binding->value, 2u); + + auto* sem = flattened->Sem().Get(vars[0]); + ASSERT_NE(sem, nullptr); + EXPECT_EQ(sem->BindingPoint().group, 0u); + EXPECT_EQ(sem->BindingPoint().binding, 0u); + + sem = flattened->Sem().Get(vars[1]); + ASSERT_NE(sem, nullptr); + EXPECT_EQ(sem->BindingPoint().group, 0u); + EXPECT_EQ(sem->BindingPoint().binding, 1u); + + sem = flattened->Sem().Get(vars[2]); + ASSERT_NE(sem, nullptr); + EXPECT_EQ(sem->BindingPoint().group, 0u); + EXPECT_EQ(sem->BindingPoint().binding, 2u); } TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) { @@ -113,8 +114,6 @@ TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) { b.Assign(b.Phony(), "texture4"), b.Assign(b.Phony(), "texture5"), b.Assign(b.Phony(), "texture6")); - resolver::Resolver resolver(&b); - Program program(std::move(b)); ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str(); @@ -124,16 +123,22 @@ TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) { auto& vars = flattened->AST().GlobalVariables(); for (size_t i = 0; i < num_buffers; ++i) { - EXPECT_EQ(vars[i]->BindingPoint().group->value, 0u); - EXPECT_EQ(vars[i]->BindingPoint().binding->value, i); + auto* sem = flattened->Sem().Get(vars[i]); + ASSERT_NE(sem, nullptr); + EXPECT_EQ(sem->BindingPoint().group, 0u); + EXPECT_EQ(sem->BindingPoint().binding, i); } for (size_t i = 0; i < num_samplers; ++i) { - EXPECT_EQ(vars[i + num_buffers]->BindingPoint().group->value, 0u); - EXPECT_EQ(vars[i + num_buffers]->BindingPoint().binding->value, i); + auto* sem = flattened->Sem().Get(vars[i + num_buffers]); + ASSERT_NE(sem, nullptr); + EXPECT_EQ(sem->BindingPoint().group, 0u); + EXPECT_EQ(sem->BindingPoint().binding, i); } for (size_t i = 0; i < num_textures; ++i) { - EXPECT_EQ(vars[i + num_buffers + num_samplers]->BindingPoint().group->value, 0u); - EXPECT_EQ(vars[i + num_buffers + num_samplers]->BindingPoint().binding->value, i); + auto* sem = flattened->Sem().Get(vars[i + num_buffers + num_samplers]); + ASSERT_NE(sem, nullptr); + EXPECT_EQ(sem->BindingPoint().group, 0u); + EXPECT_EQ(sem->BindingPoint().binding, i); } } diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc index c2a667fbbb..31f749fb81 100644 --- a/src/tint/writer/glsl/generator_impl.cc +++ b/src/tint/writer/glsl/generator_impl.cc @@ -1906,10 +1906,10 @@ bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type"; return false; } - ast::VariableBindingPoint bp = var->BindingPoint(); + auto bp = sem->As()->BindingPoint(); { auto out = line(); - out << "layout(binding = " << bp.binding->value; + out << "layout(binding = " << bp.binding; if (version_.IsDesktop()) { out << ", std140"; } @@ -1930,8 +1930,8 @@ bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type"; return false; } - ast::VariableBindingPoint bp = var->BindingPoint(); - line() << "layout(binding = " << bp.binding->value << ", std430) buffer " + auto bp = sem->As()->BindingPoint(); + line() << "layout(binding = " << bp.binding << ", std430) buffer " << UniqueIdentifier(StructName(str)) << " {"; EmitStructMembers(current_buffer_, str, /* emit_offsets */ true); auto name = builder_.Symbols().NameFor(var->symbol); diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc index a7367dcbda..fca1515dd9 100644 --- a/src/tint/writer/hlsl/generator_impl.cc +++ b/src/tint/writer/hlsl/generator_impl.cc @@ -136,15 +136,15 @@ bool PrintF16(std::ostream& out, float value) { // Helper for writing " : register(RX, spaceY)", where R is the register, X is // the binding point binding value, and Y is the binding point group value. struct RegisterAndSpace { - RegisterAndSpace(char r, ast::VariableBindingPoint bp) : reg(r), binding_point(bp) {} + RegisterAndSpace(char r, sem::BindingPoint bp) : reg(r), binding_point(bp) {} const char reg; - ast::VariableBindingPoint const binding_point; + sem::BindingPoint const binding_point; }; std::ostream& operator<<(std::ostream& s, const RegisterAndSpace& rs) { - s << " : register(" << rs.reg << rs.binding_point.binding->value << ", space" - << rs.binding_point.group->value << ")"; + s << " : register(" << rs.reg << rs.binding_point.binding << ", space" << rs.binding_point.group + << ")"; return s; } @@ -2861,7 +2861,7 @@ bool GeneratorImpl::EmitGlobalVariable(const ast::Variable* global) { } bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) { - auto binding_point = var->BindingPoint(); + auto binding_point = sem->As()->BindingPoint(); auto* type = sem->Type()->UnwrapRef(); auto name = builder_.Symbols().NameFor(var->symbol); line() << "cbuffer cbuffer_" << name << RegisterAndSpace('b', binding_point) << " {"; @@ -2888,7 +2888,9 @@ bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable return false; } - out << RegisterAndSpace(sem->Access() == ast::Access::kRead ? 't' : 'u', var->BindingPoint()) + auto* global_sem = sem->As(); + out << RegisterAndSpace(sem->Access() == ast::Access::kRead ? 't' : 'u', + global_sem->BindingPoint()) << ";"; return true; @@ -2916,9 +2918,8 @@ bool GeneratorImpl::EmitHandleVariable(const ast::Var* var, const sem::Variable* } if (register_space) { - auto bp = var->BindingPoint(); - out << " : register(" << register_space << bp.binding->value << ", space" << bp.group->value - << ")"; + auto bp = sem->As()->BindingPoint(); + out << " : register(" << register_space << bp.binding << ", space" << bp.group << ")"; } out << ";"; diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc index 837f9ac3c6..76176786ff 100644 --- a/src/tint/writer/msl/generator_impl.cc +++ b/src/tint/writer/msl/generator_impl.cc @@ -1914,18 +1914,19 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) { // attribute have a value of zero. const uint32_t kInvalidBindingIndex = std::numeric_limits::max(); auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t { - auto bp = param->BindingPoint(); - if (bp.group == nullptr || bp.binding == nullptr) { + if (!param->HasBindingPoint()) { TINT_ICE(Writer, diagnostics_) << "missing binding attributes for entry point parameter"; return kInvalidBindingIndex; } - if (bp.group->value != 0) { + auto* param_sem = program_->Sem().Get(param); + auto bp = param_sem->BindingPoint(); + if (bp.group != 0) { TINT_ICE(Writer, diagnostics_) << "encountered non-zero resource group index (use " "BindingRemapper to fix)"; return kInvalidBindingIndex; } - return bp.binding->value; + return bp.binding; }; {