Remove `ast::VariableBindingPoint` in favour of `sem::BindingPoint`.
This CL removes `VariableBindingPoint`. The `Variable` object has a `has_binding_point` method added which returns true if there is _both_ a `Group` and `Binding` attribute. Code has all been updated to use the `sem::BindingPoint` which is populated during the resolve. Bug: tint:1633 Change-Id: I79a0da662be61d5fb1c1b61342ab239cc4c66809 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/100240 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
98d7eb4009
commit
acdf6e1a53
|
@ -37,16 +37,4 @@ Variable::Variable(Variable&&) = default;
|
||||||
|
|
||||||
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
|
} // namespace tint::ast
|
||||||
|
|
|
@ -20,31 +20,19 @@
|
||||||
|
|
||||||
#include "src/tint/ast/access.h"
|
#include "src/tint/ast/access.h"
|
||||||
#include "src/tint/ast/attribute.h"
|
#include "src/tint/ast/attribute.h"
|
||||||
|
#include "src/tint/ast/binding_attribute.h"
|
||||||
#include "src/tint/ast/expression.h"
|
#include "src/tint/ast/expression.h"
|
||||||
|
#include "src/tint/ast/group_attribute.h"
|
||||||
#include "src/tint/ast/storage_class.h"
|
#include "src/tint/ast/storage_class.h"
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
class BindingAttribute;
|
|
||||||
class GroupAttribute;
|
|
||||||
class LocationAttribute;
|
class LocationAttribute;
|
||||||
class Type;
|
class Type;
|
||||||
} // namespace tint::ast
|
} // namespace tint::ast
|
||||||
|
|
||||||
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.
|
/// 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"
|
/// An instance of this class represents one of five constructs in WGSL: "var" declaration, "let"
|
||||||
|
@ -75,9 +63,11 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Variable() override;
|
~Variable() override;
|
||||||
|
|
||||||
/// @returns the binding point information from the variable's attributes.
|
/// @returns true if the variable has both group and binding attributes
|
||||||
/// @note binding points should only be applied to Var and Parameter types.
|
bool HasBindingPoint() const {
|
||||||
VariableBindingPoint BindingPoint() const;
|
return ast::GetAttribute<ast::BindingAttribute>(attributes) != nullptr &&
|
||||||
|
ast::GetAttribute<ast::GroupAttribute>(attributes) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns the kind of the variable, which can be used in diagnostics
|
/// @returns the kind of the variable, which can be used in diagnostics
|
||||||
/// e.g. "var", "let", "const", etc
|
/// e.g. "var", "let", "const", etc
|
||||||
|
|
|
@ -105,36 +105,24 @@ TEST_F(VariableTest, WithAttributes) {
|
||||||
EXPECT_EQ(1u, location->value);
|
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));
|
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Binding(2), Group(1));
|
||||||
EXPECT_TRUE(var->BindingPoint());
|
EXPECT_TRUE(var->HasBindingPoint());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, BindingPointAttributes) {
|
TEST_F(VariableTest, HasBindingPoint_NeitherProvided) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, utils::Empty);
|
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, utils::Empty);
|
||||||
EXPECT_FALSE(var->BindingPoint());
|
EXPECT_FALSE(var->HasBindingPoint());
|
||||||
EXPECT_EQ(var->BindingPoint().group, nullptr);
|
|
||||||
EXPECT_EQ(var->BindingPoint().binding, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, BindingPointMissingGroupAttribute) {
|
TEST_F(VariableTest, HasBindingPoint_MissingGroupAttribute) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Binding(2));
|
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Binding(2));
|
||||||
EXPECT_FALSE(var->BindingPoint());
|
EXPECT_FALSE(var->HasBindingPoint());
|
||||||
ASSERT_NE(var->BindingPoint().binding, nullptr);
|
|
||||||
EXPECT_EQ(var->BindingPoint().binding->value, 2u);
|
|
||||||
EXPECT_EQ(var->BindingPoint().group, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VariableTest, BindingPointMissingBindingAttribute) {
|
TEST_F(VariableTest, HasBindingPoint_MissingBindingAttribute) {
|
||||||
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Group(1));
|
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, Group(1));
|
||||||
EXPECT_FALSE(var->BindingPoint());
|
EXPECT_FALSE(var->HasBindingPoint());
|
||||||
ASSERT_NE(var->BindingPoint().group, nullptr);
|
|
||||||
EXPECT_EQ(var->BindingPoint().group->value, 1u);
|
|
||||||
EXPECT_EQ(var->BindingPoint().binding, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -370,8 +370,8 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
|
entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
|
||||||
entry.bind_group = binding_info.group->value;
|
entry.bind_group = binding_info.group;
|
||||||
entry.binding = binding_info.binding->value;
|
entry.binding = binding_info.binding;
|
||||||
entry.size = unwrapped_type->Size();
|
entry.size = unwrapped_type->Size();
|
||||||
entry.size_no_padding = entry.size;
|
entry.size_no_padding = entry.size;
|
||||||
if (auto* str = unwrapped_type->As<sem::Struct>()) {
|
if (auto* str = unwrapped_type->As<sem::Struct>()) {
|
||||||
|
@ -410,8 +410,8 @@ std::vector<ResourceBinding> Inspector::GetSamplerResourceBindings(const std::st
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type = ResourceBinding::ResourceType::kSampler;
|
entry.resource_type = ResourceBinding::ResourceType::kSampler;
|
||||||
entry.bind_group = binding_info.group->value;
|
entry.bind_group = binding_info.group;
|
||||||
entry.binding = binding_info.binding->value;
|
entry.binding = binding_info.binding;
|
||||||
|
|
||||||
result.push_back(entry);
|
result.push_back(entry);
|
||||||
}
|
}
|
||||||
|
@ -434,8 +434,8 @@ std::vector<ResourceBinding> Inspector::GetComparisonSamplerResourceBindings(
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type = ResourceBinding::ResourceType::kComparisonSampler;
|
entry.resource_type = ResourceBinding::ResourceType::kComparisonSampler;
|
||||||
entry.bind_group = binding_info.group->value;
|
entry.bind_group = binding_info.group;
|
||||||
entry.binding = binding_info.binding->value;
|
entry.binding = binding_info.binding;
|
||||||
|
|
||||||
result.push_back(entry);
|
result.push_back(entry);
|
||||||
}
|
}
|
||||||
|
@ -475,8 +475,8 @@ std::vector<ResourceBinding> Inspector::GetTextureResourceBindings(
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type = resource_type;
|
entry.resource_type = resource_type;
|
||||||
entry.bind_group = binding_info.group->value;
|
entry.bind_group = binding_info.group;
|
||||||
entry.binding = binding_info.binding->value;
|
entry.binding = binding_info.binding;
|
||||||
|
|
||||||
auto* tex = var->Type()->UnwrapRef()->As<sem::Texture>();
|
auto* tex = var->Type()->UnwrapRef()->As<sem::Texture>();
|
||||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(tex->dim());
|
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(tex->dim());
|
||||||
|
@ -692,8 +692,8 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type = read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
|
entry.resource_type = read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
|
||||||
: ResourceBinding::ResourceType::kStorageBuffer;
|
: ResourceBinding::ResourceType::kStorageBuffer;
|
||||||
entry.bind_group = binding_info.group->value;
|
entry.bind_group = binding_info.group;
|
||||||
entry.binding = binding_info.binding->value;
|
entry.binding = binding_info.binding;
|
||||||
entry.size = unwrapped_type->Size();
|
entry.size = unwrapped_type->Size();
|
||||||
if (auto* str = unwrapped_type->As<sem::Struct>()) {
|
if (auto* str = unwrapped_type->As<sem::Struct>()) {
|
||||||
entry.size_no_padding = str->SizeNoPadding();
|
entry.size_no_padding = str->SizeNoPadding();
|
||||||
|
@ -728,8 +728,8 @@ std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
|
||||||
entry.resource_type = multisampled_only
|
entry.resource_type = multisampled_only
|
||||||
? ResourceBinding::ResourceType::kMultisampledTexture
|
? ResourceBinding::ResourceType::kMultisampledTexture
|
||||||
: ResourceBinding::ResourceType::kSampledTexture;
|
: ResourceBinding::ResourceType::kSampledTexture;
|
||||||
entry.bind_group = binding_info.group->value;
|
entry.bind_group = binding_info.group;
|
||||||
entry.binding = binding_info.binding->value;
|
entry.binding = binding_info.binding;
|
||||||
|
|
||||||
auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
|
auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
|
||||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
|
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
|
||||||
|
@ -765,8 +765,8 @@ std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type = ResourceBinding::ResourceType::kWriteOnlyStorageTexture;
|
entry.resource_type = ResourceBinding::ResourceType::kWriteOnlyStorageTexture;
|
||||||
entry.bind_group = binding_info.group->value;
|
entry.bind_group = binding_info.group;
|
||||||
entry.binding = binding_info.binding->value;
|
entry.binding = binding_info.binding;
|
||||||
|
|
||||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
|
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
|
||||||
|
|
||||||
|
@ -838,13 +838,8 @@ void Inspector::GenerateSamplerTargets() {
|
||||||
GetOriginatingResources(
|
GetOriginatingResources(
|
||||||
std::array<const ast::Expression*, 2>{t, s},
|
std::array<const ast::Expression*, 2>{t, s},
|
||||||
[&](std::array<const sem::GlobalVariable*, 2> globals) {
|
[&](std::array<const sem::GlobalVariable*, 2> globals) {
|
||||||
auto* texture = globals[0]->Declaration()->As<ast::Var>();
|
auto texture_binding_point = globals[0]->BindingPoint();
|
||||||
sem::BindingPoint texture_binding_point = {texture->BindingPoint().group->value,
|
auto sampler_binding_point = globals[1]->BindingPoint();
|
||||||
texture->BindingPoint().binding->value};
|
|
||||||
|
|
||||||
auto* sampler = globals[1]->Declaration()->As<ast::Var>();
|
|
||||||
sem::BindingPoint sampler_binding_point = {sampler->BindingPoint().group->value,
|
|
||||||
sampler->BindingPoint().binding->value};
|
|
||||||
|
|
||||||
for (auto* entry_point : entry_points) {
|
for (auto* entry_point : entry_points) {
|
||||||
const auto& ep_name =
|
const auto& ep_name =
|
||||||
|
|
|
@ -578,8 +578,21 @@ sem::Variable* Resolver::Var(const ast::Var* var, bool is_global) {
|
||||||
sem::Variable* sem = nullptr;
|
sem::Variable* sem = nullptr;
|
||||||
if (is_global) {
|
if (is_global) {
|
||||||
sem::BindingPoint binding_point;
|
sem::BindingPoint binding_point;
|
||||||
if (auto bp = var->BindingPoint()) {
|
if (var->HasBindingPoint()) {
|
||||||
binding_point = {bp.group->value, bp.binding->value};
|
uint32_t binding = 0;
|
||||||
|
{
|
||||||
|
auto* attr = ast::GetAttribute<ast::BindingAttribute>(var->attributes);
|
||||||
|
// TODO(dsinclair): Materialize when binding attribute is an expression
|
||||||
|
binding = attr->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t group = 0;
|
||||||
|
{
|
||||||
|
auto* attr = ast::GetAttribute<ast::GroupAttribute>(var->attributes);
|
||||||
|
// TODO(dsinclair): Materialize when group attribute is an expression
|
||||||
|
group = attr->value;
|
||||||
|
}
|
||||||
|
binding_point = {group, binding};
|
||||||
}
|
}
|
||||||
sem = builder_->create<sem::GlobalVariable>(var, var_ty, sem::EvaluationStage::kRuntime,
|
sem = builder_->create<sem::GlobalVariable>(var, var_ty, sem::EvaluationStage::kRuntime,
|
||||||
storage_class, access,
|
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<ast::BindingAttribute>(param->attributes);
|
||||||
|
// TODO(dsinclair): Materialize the binding information
|
||||||
|
binding_point.binding = attr->value;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto* attr = ast::GetAttribute<ast::GroupAttribute>(param->attributes);
|
||||||
|
// TODO(dsinclair): Materialize the group information
|
||||||
|
binding_point.group = attr->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto* sem = builder_->create<sem::Parameter>(param, index, ty, ast::StorageClass::kNone,
|
auto* sem = builder_->create<sem::Parameter>(param, index, ty, ast::StorageClass::kNone,
|
||||||
ast::Access::kUndefined);
|
ast::Access::kUndefined,
|
||||||
|
sem::ParameterUsage::kNone, binding_point);
|
||||||
builder_->Sem().Add(param, sem);
|
builder_->Sem().Add(param, sem);
|
||||||
return sem;
|
return sem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -664,7 +664,6 @@ bool Validator::GlobalVariable(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto binding_point = decl->BindingPoint();
|
|
||||||
switch (global->StorageClass()) {
|
switch (global->StorageClass()) {
|
||||||
case ast::StorageClass::kUniform:
|
case ast::StorageClass::kUniform:
|
||||||
case ast::StorageClass::kStorage:
|
case ast::StorageClass::kStorage:
|
||||||
|
@ -672,20 +671,23 @@ bool Validator::GlobalVariable(
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
|
// https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
|
||||||
// Each resource variable must be declared with both group and binding
|
// Each resource variable must be declared with both group and binding
|
||||||
// attributes.
|
// attributes.
|
||||||
if (!binding_point) {
|
if (!decl->HasBindingPoint()) {
|
||||||
AddError("resource variables require @group and @binding attributes", decl->source);
|
AddError("resource variables require @group and @binding attributes", decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
if (binding_point.binding || binding_point.group) {
|
auto* binding_attr = ast::GetAttribute<ast::BindingAttribute>(decl->attributes);
|
||||||
|
auto* group_attr = ast::GetAttribute<ast::GroupAttribute>(decl->attributes);
|
||||||
|
if (binding_attr || group_attr) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
|
// https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
|
||||||
// Must only be applied to a resource variable
|
// Must only be applied to a resource variable
|
||||||
AddError("non-resource variables must not have @group or @binding attributes",
|
AddError("non-resource variables must not have @group or @binding attributes",
|
||||||
decl->source);
|
decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1351,7 +1353,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
|
||||||
std::unordered_map<sem::BindingPoint, const ast::Variable*> binding_points;
|
std::unordered_map<sem::BindingPoint, const ast::Variable*> binding_points;
|
||||||
for (auto* global : func->TransitivelyReferencedGlobals()) {
|
for (auto* global : func->TransitivelyReferencedGlobals()) {
|
||||||
auto* var_decl = global->Declaration()->As<ast::Var>();
|
auto* var_decl = global->Declaration()->As<ast::Var>();
|
||||||
if (!var_decl || !var_decl->BindingPoint()) {
|
if (!var_decl || !var_decl->HasBindingPoint()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto bp = global->BindingPoint();
|
auto bp = global->BindingPoint();
|
||||||
|
|
|
@ -70,8 +70,8 @@ Function::VariableBindings Function::TransitivelyReferencedUniformVariables() co
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto binding_point = global->Declaration()->BindingPoint()) {
|
if (global->Declaration()->HasBindingPoint()) {
|
||||||
ret.push_back({global, binding_point});
|
ret.push_back({global, global->BindingPoint()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -85,8 +85,8 @@ Function::VariableBindings Function::TransitivelyReferencedStorageBufferVariable
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto binding_point = global->Declaration()->BindingPoint()) {
|
if (global->Declaration()->HasBindingPoint()) {
|
||||||
ret.push_back({global, binding_point});
|
ret.push_back({global, global->BindingPoint()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -129,8 +129,8 @@ Function::VariableBindings Function::TransitivelyReferencedVariablesOfType(
|
||||||
for (auto* global : TransitivelyReferencedGlobals()) {
|
for (auto* global : TransitivelyReferencedGlobals()) {
|
||||||
auto* unwrapped_type = global->Type()->UnwrapRef();
|
auto* unwrapped_type = global->Type()->UnwrapRef();
|
||||||
if (unwrapped_type->TypeInfo().Is(type)) {
|
if (unwrapped_type->TypeInfo().Is(type)) {
|
||||||
if (auto binding_point = global->Declaration()->BindingPoint()) {
|
if (global->Declaration()->HasBindingPoint()) {
|
||||||
ret.push_back({global, binding_point});
|
ret.push_back({global, global->BindingPoint()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,8 +157,8 @@ Function::VariableBindings Function::TransitivelyReferencedSamplerVariablesImpl(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto binding_point = global->Declaration()->BindingPoint()) {
|
if (global->Declaration()->HasBindingPoint()) {
|
||||||
ret.push_back({global, binding_point});
|
ret.push_back({global, global->BindingPoint()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -182,8 +182,8 @@ Function::VariableBindings Function::TransitivelyReferencedSampledTextureVariabl
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto binding_point = global->Declaration()->BindingPoint()) {
|
if (global->Declaration()->HasBindingPoint()) {
|
||||||
ret.push_back({global, binding_point});
|
ret.push_back({global, global->BindingPoint()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ using WorkgroupSize = std::array<WorkgroupDimension, 3>;
|
||||||
/// Function holds the semantic information for function nodes.
|
/// Function holds the semantic information for function nodes.
|
||||||
class Function final : public Castable<Function, CallTarget> {
|
class Function final : public Castable<Function, CallTarget> {
|
||||||
public:
|
public:
|
||||||
/// A vector of [Variable*, ast::VariableBindingPoint] pairs
|
/// A vector of [Variable*, sem::BindingPoint] pairs
|
||||||
using VariableBindings = std::vector<std::pair<const Variable*, ast::VariableBindingPoint>>;
|
using VariableBindings = std::vector<std::pair<const Variable*, sem::BindingPoint>>;
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param declaration the ast::Function
|
/// @param declaration the ast::Function
|
||||||
|
|
|
@ -72,10 +72,12 @@ Parameter::Parameter(const ast::Parameter* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class,
|
||||||
ast::Access access,
|
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),
|
: Base(declaration, type, EvaluationStage::kRuntime, storage_class, access, nullptr),
|
||||||
index_(index),
|
index_(index),
|
||||||
usage_(usage) {}
|
usage_(usage),
|
||||||
|
binding_point_(binding_point) {}
|
||||||
|
|
||||||
Parameter::~Parameter() = default;
|
Parameter::~Parameter() = default;
|
||||||
|
|
||||||
|
|
|
@ -188,12 +188,14 @@ class Parameter final : public Castable<Parameter, Variable> {
|
||||||
/// @param storage_class the variable storage class
|
/// @param storage_class the variable storage class
|
||||||
/// @param access the variable access control type
|
/// @param access the variable access control type
|
||||||
/// @param usage the semantic usage for the parameter
|
/// @param usage the semantic usage for the parameter
|
||||||
|
/// @param binding_point the optional resource binding point of the parameter
|
||||||
Parameter(const ast::Parameter* declaration,
|
Parameter(const ast::Parameter* declaration,
|
||||||
uint32_t index,
|
uint32_t index,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class,
|
||||||
ast::Access access,
|
ast::Access access,
|
||||||
const ParameterUsage usage = ParameterUsage::kNone);
|
const ParameterUsage usage = ParameterUsage::kNone,
|
||||||
|
sem::BindingPoint binding_point = {});
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Parameter() override;
|
~Parameter() override;
|
||||||
|
@ -217,11 +219,15 @@ class Parameter final : public Castable<Parameter, Variable> {
|
||||||
/// @param shadows the Type, Function or Variable that this variable shadows
|
/// @param shadows the Type, Function or Variable that this variable shadows
|
||||||
void SetShadows(const sem::Node* shadows) { shadows_ = 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:
|
private:
|
||||||
const uint32_t index_;
|
const uint32_t index_;
|
||||||
const ParameterUsage usage_;
|
const ParameterUsage usage_;
|
||||||
CallTarget const* owner_ = nullptr;
|
CallTarget const* owner_ = nullptr;
|
||||||
const sem::Node* shadows_ = nullptr;
|
const sem::Node* shadows_ = nullptr;
|
||||||
|
const sem::BindingPoint binding_point_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// VariableUser holds the semantic information for an identifier expression
|
/// VariableUser holds the semantic information for an identifier expression
|
||||||
|
|
|
@ -69,8 +69,9 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
|
||||||
auto* func = ctx.src->Sem().Get(func_ast);
|
auto* func = ctx.src->Sem().Get(func_ast);
|
||||||
std::unordered_map<sem::BindingPoint, int> binding_point_counts;
|
std::unordered_map<sem::BindingPoint, int> binding_point_counts;
|
||||||
for (auto* global : func->TransitivelyReferencedGlobals()) {
|
for (auto* global : func->TransitivelyReferencedGlobals()) {
|
||||||
if (auto binding_point = global->Declaration()->BindingPoint()) {
|
if (global->Declaration()->HasBindingPoint()) {
|
||||||
BindingPoint from{binding_point.group->value, binding_point.binding->value};
|
BindingPoint from = global->BindingPoint();
|
||||||
|
|
||||||
auto bp_it = remappings->binding_points.find(from);
|
auto bp_it = remappings->binding_points.find(from);
|
||||||
if (bp_it != remappings->binding_points.end()) {
|
if (bp_it != remappings->binding_points.end()) {
|
||||||
// Remapped
|
// Remapped
|
||||||
|
@ -90,9 +91,11 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* var : ctx.src->AST().Globals<ast::Var>()) {
|
for (auto* var : ctx.src->AST().Globals<ast::Var>()) {
|
||||||
if (auto binding_point = var->BindingPoint()) {
|
if (var->HasBindingPoint()) {
|
||||||
|
auto* global_sem = ctx.src->Sem().Get<sem::GlobalVariable>(var);
|
||||||
|
|
||||||
// The original binding point
|
// The original binding point
|
||||||
BindingPoint from{binding_point.group->value, binding_point.binding->value};
|
BindingPoint from = global_sem->BindingPoint();
|
||||||
|
|
||||||
// The binding point after remapping
|
// The binding point after remapping
|
||||||
BindingPoint bp = from;
|
BindingPoint bp = from;
|
||||||
|
@ -106,8 +109,11 @@ void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) co
|
||||||
auto* new_group = ctx.dst->create<ast::GroupAttribute>(to.group);
|
auto* new_group = ctx.dst->create<ast::GroupAttribute>(to.group);
|
||||||
auto* new_binding = ctx.dst->create<ast::BindingAttribute>(to.binding);
|
auto* new_binding = ctx.dst->create<ast::BindingAttribute>(to.binding);
|
||||||
|
|
||||||
ctx.Replace(binding_point.group, new_group);
|
auto* old_group = ast::GetAttribute<ast::GroupAttribute>(var->attributes);
|
||||||
ctx.Replace(binding_point.binding, new_binding);
|
auto* old_binding = ast::GetAttribute<ast::BindingAttribute>(var->attributes);
|
||||||
|
|
||||||
|
ctx.Replace(old_group, new_group);
|
||||||
|
ctx.Replace(old_binding, new_binding);
|
||||||
bp = to;
|
bp = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,12 +149,14 @@ struct CombineSamplers::State {
|
||||||
// Remove all texture and sampler global variables. These will be replaced
|
// Remove all texture and sampler global variables. These will be replaced
|
||||||
// by combined samplers.
|
// by combined samplers.
|
||||||
for (auto* global : ctx.src->AST().GlobalVariables()) {
|
for (auto* global : ctx.src->AST().GlobalVariables()) {
|
||||||
|
auto* global_sem = sem.Get(global)->As<sem::GlobalVariable>();
|
||||||
auto* type = sem.Get(global->type);
|
auto* type = sem.Get(global->type);
|
||||||
if (tint::IsAnyOf<sem::Texture, sem::Sampler>(type) &&
|
if (tint::IsAnyOf<sem::Texture, sem::Sampler>(type) &&
|
||||||
!type->Is<sem::StorageTexture>()) {
|
!type->Is<sem::StorageTexture>()) {
|
||||||
ctx.Remove(ctx.src->AST().GlobalDeclarations(), global);
|
ctx.Remove(ctx.src->AST().GlobalDeclarations(), global);
|
||||||
} else if (auto binding_point = global->BindingPoint()) {
|
} else if (global->HasBindingPoint()) {
|
||||||
if (binding_point.group->value == 0 && binding_point.binding->value == 0) {
|
auto binding_point = global_sem->BindingPoint();
|
||||||
|
if (binding_point.group == 0 && binding_point.binding == 0) {
|
||||||
auto* attribute =
|
auto* attribute =
|
||||||
ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
|
ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
|
||||||
ctx.InsertFront(global->attributes, attribute);
|
ctx.InsertFront(global->attributes, attribute);
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct MultiplanarExternalTexture::State {
|
||||||
// represent the secondary plane and one uniform buffer for the
|
// represent the secondary plane and one uniform buffer for the
|
||||||
// ExternalTextureParams struct).
|
// ExternalTextureParams struct).
|
||||||
for (auto* global : ctx.src->AST().GlobalVariables()) {
|
for (auto* global : ctx.src->AST().GlobalVariables()) {
|
||||||
auto* sem_var = sem.Get(global);
|
auto* sem_var = sem.Get<sem::GlobalVariable>(global);
|
||||||
if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
|
if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -109,8 +109,7 @@ struct MultiplanarExternalTexture::State {
|
||||||
// provided to this transform. We fetch the new binding points by
|
// provided to this transform. We fetch the new binding points by
|
||||||
// providing the original texture_external binding points into the
|
// providing the original texture_external binding points into the
|
||||||
// passed map.
|
// passed map.
|
||||||
BindingPoint bp = {global->BindingPoint().group->value,
|
BindingPoint bp = sem_var->BindingPoint();
|
||||||
global->BindingPoint().binding->value};
|
|
||||||
|
|
||||||
BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
|
BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
|
||||||
if (it == new_binding_points->bindings_map.end()) {
|
if (it == new_binding_points->bindings_map.end()) {
|
||||||
|
|
|
@ -136,9 +136,11 @@ void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, Dat
|
||||||
group = 0;
|
group = 0;
|
||||||
|
|
||||||
for (auto* global : ctx.src->AST().GlobalVariables()) {
|
for (auto* global : ctx.src->AST().GlobalVariables()) {
|
||||||
if (auto binding_point = global->BindingPoint()) {
|
if (global->HasBindingPoint()) {
|
||||||
if (binding_point.group->value >= group) {
|
auto* global_sem = ctx.src->Sem().Get<sem::GlobalVariable>(global);
|
||||||
group = binding_point.group->value + 1;
|
auto binding_point = global_sem->BindingPoint();
|
||||||
|
if (binding_point.group >= group) {
|
||||||
|
group = binding_point.group + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ std::optional<Program> FlattenBindings(const Program* program) {
|
||||||
auto entry_points = inspector.GetEntryPoints();
|
auto entry_points = inspector.GetEntryPoints();
|
||||||
for (auto& entry_point : entry_points) {
|
for (auto& entry_point : entry_points) {
|
||||||
auto bindings = inspector.GetResourceBindings(entry_point.name);
|
auto bindings = inspector.GetResourceBindings(entry_point.name);
|
||||||
|
|
||||||
for (auto& binding : bindings) {
|
for (auto& binding : bindings) {
|
||||||
BindingPoint src = {binding.bind_group, binding.binding};
|
BindingPoint src = {binding.bind_group, binding.binding};
|
||||||
if (binding_points.count(src)) {
|
if (binding_points.count(src)) {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "src/tint/program_builder.h"
|
#include "src/tint/program_builder.h"
|
||||||
#include "src/tint/resolver/resolver.h"
|
|
||||||
#include "src/tint/sem/variable.h"
|
#include "src/tint/sem/variable.h"
|
||||||
|
|
||||||
namespace tint::writer {
|
namespace tint::writer {
|
||||||
|
@ -28,9 +27,6 @@ class FlattenBindingsTest : public ::testing::Test {};
|
||||||
|
|
||||||
TEST_F(FlattenBindingsTest, NoBindings) {
|
TEST_F(FlattenBindingsTest, NoBindings) {
|
||||||
ProgramBuilder b;
|
ProgramBuilder b;
|
||||||
|
|
||||||
resolver::Resolver resolver(&b);
|
|
||||||
|
|
||||||
Program program(std::move(b));
|
Program program(std::move(b));
|
||||||
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
|
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("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));
|
b.GlobalVar("c", b.ty.i32(), ast::StorageClass::kUniform, b.Group(0), b.Binding(2));
|
||||||
|
|
||||||
resolver::Resolver resolver(&b);
|
|
||||||
|
|
||||||
Program program(std::move(b));
|
Program program(std::move(b));
|
||||||
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
|
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.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"));
|
b.WrapInFunction(b.Expr("a"), b.Expr("b"), b.Expr("c"));
|
||||||
|
|
||||||
resolver::Resolver resolver(&b);
|
|
||||||
|
|
||||||
Program program(std::move(b));
|
Program program(std::move(b));
|
||||||
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
|
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
|
||||||
|
|
||||||
|
@ -69,12 +61,21 @@ TEST_F(FlattenBindingsTest, NotFlat_SingleNamespace) {
|
||||||
EXPECT_TRUE(flattened);
|
EXPECT_TRUE(flattened);
|
||||||
|
|
||||||
auto& vars = flattened->AST().GlobalVariables();
|
auto& vars = flattened->AST().GlobalVariables();
|
||||||
EXPECT_EQ(vars[0]->BindingPoint().group->value, 0u);
|
|
||||||
EXPECT_EQ(vars[0]->BindingPoint().binding->value, 0u);
|
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[0]);
|
||||||
EXPECT_EQ(vars[1]->BindingPoint().group->value, 0u);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(vars[1]->BindingPoint().binding->value, 1u);
|
EXPECT_EQ(sem->BindingPoint().group, 0u);
|
||||||
EXPECT_EQ(vars[2]->BindingPoint().group->value, 0u);
|
EXPECT_EQ(sem->BindingPoint().binding, 0u);
|
||||||
EXPECT_EQ(vars[2]->BindingPoint().binding->value, 2u);
|
|
||||||
|
sem = flattened->Sem().Get<sem::GlobalVariable>(vars[1]);
|
||||||
|
ASSERT_NE(sem, nullptr);
|
||||||
|
EXPECT_EQ(sem->BindingPoint().group, 0u);
|
||||||
|
EXPECT_EQ(sem->BindingPoint().binding, 1u);
|
||||||
|
|
||||||
|
sem = flattened->Sem().Get<sem::GlobalVariable>(vars[2]);
|
||||||
|
ASSERT_NE(sem, nullptr);
|
||||||
|
EXPECT_EQ(sem->BindingPoint().group, 0u);
|
||||||
|
EXPECT_EQ(sem->BindingPoint().binding, 2u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) {
|
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(), "texture4"), b.Assign(b.Phony(), "texture5"),
|
||||||
b.Assign(b.Phony(), "texture6"));
|
b.Assign(b.Phony(), "texture6"));
|
||||||
|
|
||||||
resolver::Resolver resolver(&b);
|
|
||||||
|
|
||||||
Program program(std::move(b));
|
Program program(std::move(b));
|
||||||
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
|
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
|
||||||
|
|
||||||
|
@ -124,16 +123,22 @@ TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) {
|
||||||
auto& vars = flattened->AST().GlobalVariables();
|
auto& vars = flattened->AST().GlobalVariables();
|
||||||
|
|
||||||
for (size_t i = 0; i < num_buffers; ++i) {
|
for (size_t i = 0; i < num_buffers; ++i) {
|
||||||
EXPECT_EQ(vars[i]->BindingPoint().group->value, 0u);
|
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[i]);
|
||||||
EXPECT_EQ(vars[i]->BindingPoint().binding->value, 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) {
|
for (size_t i = 0; i < num_samplers; ++i) {
|
||||||
EXPECT_EQ(vars[i + num_buffers]->BindingPoint().group->value, 0u);
|
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[i + num_buffers]);
|
||||||
EXPECT_EQ(vars[i + num_buffers]->BindingPoint().binding->value, i);
|
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) {
|
for (size_t i = 0; i < num_textures; ++i) {
|
||||||
EXPECT_EQ(vars[i + num_buffers + num_samplers]->BindingPoint().group->value, 0u);
|
auto* sem = flattened->Sem().Get<sem::GlobalVariable>(vars[i + num_buffers + num_samplers]);
|
||||||
EXPECT_EQ(vars[i + num_buffers + num_samplers]->BindingPoint().binding->value, i);
|
ASSERT_NE(sem, nullptr);
|
||||||
|
EXPECT_EQ(sem->BindingPoint().group, 0u);
|
||||||
|
EXPECT_EQ(sem->BindingPoint().binding, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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";
|
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ast::VariableBindingPoint bp = var->BindingPoint();
|
auto bp = sem->As<sem::GlobalVariable>()->BindingPoint();
|
||||||
{
|
{
|
||||||
auto out = line();
|
auto out = line();
|
||||||
out << "layout(binding = " << bp.binding->value;
|
out << "layout(binding = " << bp.binding;
|
||||||
if (version_.IsDesktop()) {
|
if (version_.IsDesktop()) {
|
||||||
out << ", std140";
|
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";
|
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ast::VariableBindingPoint bp = var->BindingPoint();
|
auto bp = sem->As<sem::GlobalVariable>()->BindingPoint();
|
||||||
line() << "layout(binding = " << bp.binding->value << ", std430) buffer "
|
line() << "layout(binding = " << bp.binding << ", std430) buffer "
|
||||||
<< UniqueIdentifier(StructName(str)) << " {";
|
<< UniqueIdentifier(StructName(str)) << " {";
|
||||||
EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
|
EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
|
||||||
auto name = builder_.Symbols().NameFor(var->symbol);
|
auto name = builder_.Symbols().NameFor(var->symbol);
|
||||||
|
|
|
@ -136,15 +136,15 @@ bool PrintF16(std::ostream& out, float value) {
|
||||||
// Helper for writing " : register(RX, spaceY)", where R is the register, X is
|
// 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.
|
// the binding point binding value, and Y is the binding point group value.
|
||||||
struct RegisterAndSpace {
|
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;
|
const char reg;
|
||||||
ast::VariableBindingPoint const binding_point;
|
sem::BindingPoint const binding_point;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& s, const RegisterAndSpace& rs) {
|
std::ostream& operator<<(std::ostream& s, const RegisterAndSpace& rs) {
|
||||||
s << " : register(" << rs.reg << rs.binding_point.binding->value << ", space"
|
s << " : register(" << rs.reg << rs.binding_point.binding << ", space" << rs.binding_point.group
|
||||||
<< rs.binding_point.group->value << ")";
|
<< ")";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2861,7 +2861,7 @@ bool GeneratorImpl::EmitGlobalVariable(const ast::Variable* global) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) {
|
bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) {
|
||||||
auto binding_point = var->BindingPoint();
|
auto binding_point = sem->As<sem::GlobalVariable>()->BindingPoint();
|
||||||
auto* type = sem->Type()->UnwrapRef();
|
auto* type = sem->Type()->UnwrapRef();
|
||||||
auto name = builder_.Symbols().NameFor(var->symbol);
|
auto name = builder_.Symbols().NameFor(var->symbol);
|
||||||
line() << "cbuffer cbuffer_" << name << RegisterAndSpace('b', binding_point) << " {";
|
line() << "cbuffer cbuffer_" << name << RegisterAndSpace('b', binding_point) << " {";
|
||||||
|
@ -2888,7 +2888,9 @@ bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << RegisterAndSpace(sem->Access() == ast::Access::kRead ? 't' : 'u', var->BindingPoint())
|
auto* global_sem = sem->As<sem::GlobalVariable>();
|
||||||
|
out << RegisterAndSpace(sem->Access() == ast::Access::kRead ? 't' : 'u',
|
||||||
|
global_sem->BindingPoint())
|
||||||
<< ";";
|
<< ";";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -2916,9 +2918,8 @@ bool GeneratorImpl::EmitHandleVariable(const ast::Var* var, const sem::Variable*
|
||||||
}
|
}
|
||||||
|
|
||||||
if (register_space) {
|
if (register_space) {
|
||||||
auto bp = var->BindingPoint();
|
auto bp = sem->As<sem::GlobalVariable>()->BindingPoint();
|
||||||
out << " : register(" << register_space << bp.binding->value << ", space" << bp.group->value
|
out << " : register(" << register_space << bp.binding << ", space" << bp.group << ")";
|
||||||
<< ")";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out << ";";
|
out << ";";
|
||||||
|
|
|
@ -1914,18 +1914,19 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
|
||||||
// attribute have a value of zero.
|
// attribute have a value of zero.
|
||||||
const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max();
|
const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max();
|
||||||
auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t {
|
auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t {
|
||||||
auto bp = param->BindingPoint();
|
if (!param->HasBindingPoint()) {
|
||||||
if (bp.group == nullptr || bp.binding == nullptr) {
|
|
||||||
TINT_ICE(Writer, diagnostics_)
|
TINT_ICE(Writer, diagnostics_)
|
||||||
<< "missing binding attributes for entry point parameter";
|
<< "missing binding attributes for entry point parameter";
|
||||||
return kInvalidBindingIndex;
|
return kInvalidBindingIndex;
|
||||||
}
|
}
|
||||||
if (bp.group->value != 0) {
|
auto* param_sem = program_->Sem().Get<sem::Parameter>(param);
|
||||||
|
auto bp = param_sem->BindingPoint();
|
||||||
|
if (bp.group != 0) {
|
||||||
TINT_ICE(Writer, diagnostics_) << "encountered non-zero resource group index (use "
|
TINT_ICE(Writer, diagnostics_) << "encountered non-zero resource group index (use "
|
||||||
"BindingRemapper to fix)";
|
"BindingRemapper to fix)";
|
||||||
return kInvalidBindingIndex;
|
return kInvalidBindingIndex;
|
||||||
}
|
}
|
||||||
return bp.binding->value;
|
return bp.binding;
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue