Remove sem::AccessControl
In preparation for implementing https://github.com/gpuweb/gpuweb/issues/1604, this change removes the sem::AccessControl node. Instead, the ast::AccessControl::Access enum is now on the sem::StorageTexture class, as well as on sem::Variable. For sem::Variable, the field is set when the variable's type is either a storage buffer or a storage texture. Bug: tint:802 Change-Id: Id479af36b401d067b015027923f4e715f5f69f25 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51020 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
31d761329a
commit
dc4e6c1844
10
src/BUILD.gn
10
src/BUILD.gn
|
@ -298,10 +298,10 @@ libtint_source_set("libtint_core_all_src") {
|
|||
"ast/continue_statement.h",
|
||||
"ast/decoration.cc",
|
||||
"ast/decoration.h",
|
||||
"ast/disable_validation_decoration.cc",
|
||||
"ast/disable_validation_decoration.h",
|
||||
"ast/depth_texture.cc",
|
||||
"ast/depth_texture.h",
|
||||
"ast/disable_validation_decoration.cc",
|
||||
"ast/disable_validation_decoration.h",
|
||||
"ast/discard_statement.cc",
|
||||
"ast/discard_statement.h",
|
||||
"ast/else_statement.cc",
|
||||
|
@ -447,8 +447,6 @@ libtint_source_set("libtint_core_all_src") {
|
|||
"resolver/resolver.cc",
|
||||
"resolver/resolver.h",
|
||||
"scope_stack.h",
|
||||
"sem/access_control_type.cc",
|
||||
"sem/access_control_type.h",
|
||||
"sem/array.h",
|
||||
"sem/binding_point.h",
|
||||
"sem/bool_type.cc",
|
||||
|
@ -590,12 +588,12 @@ libtint_source_set("libtint_spv_reader_src") {
|
|||
"reader/spirv/function.h",
|
||||
"reader/spirv/namer.cc",
|
||||
"reader/spirv/namer.h",
|
||||
"reader/spirv/parser_type.cc",
|
||||
"reader/spirv/parser_type.h",
|
||||
"reader/spirv/parser.cc",
|
||||
"reader/spirv/parser.h",
|
||||
"reader/spirv/parser_impl.cc",
|
||||
"reader/spirv/parser_impl.h",
|
||||
"reader/spirv/parser_type.cc",
|
||||
"reader/spirv/parser_type.h",
|
||||
"reader/spirv/usage.cc",
|
||||
"reader/spirv/usage.h",
|
||||
]
|
||||
|
|
|
@ -285,8 +285,6 @@ set(TINT_LIB_SRCS
|
|||
transform/transform.h
|
||||
transform/vertex_pulling.cc
|
||||
transform/vertex_pulling.h
|
||||
sem/access_control_type.cc
|
||||
sem/access_control_type.h
|
||||
sem/bool_type.cc
|
||||
sem/bool_type.h
|
||||
sem/depth_texture_type.cc
|
||||
|
@ -567,7 +565,6 @@ if(${TINT_BUILD_TESTS})
|
|||
symbol_test.cc
|
||||
transform/transform_test.cc
|
||||
test_main.cc
|
||||
sem/access_control_type_test.cc
|
||||
sem/bool_type_test.cc
|
||||
sem/depth_texture_type_test.cc
|
||||
sem/external_texture_type_test.cc
|
||||
|
|
|
@ -37,6 +37,9 @@ AccessControl::~AccessControl() = default;
|
|||
std::string AccessControl::type_name() const {
|
||||
std::string name = "__access_control_";
|
||||
switch (access_) {
|
||||
case ast::AccessControl::kInvalid:
|
||||
name += "invalid";
|
||||
break;
|
||||
case ast::AccessControl::kReadOnly:
|
||||
name += "read_only";
|
||||
break;
|
||||
|
@ -54,6 +57,9 @@ std::string AccessControl::FriendlyName(const SymbolTable& symbols) const {
|
|||
std::ostringstream out;
|
||||
out << "[[access(";
|
||||
switch (access_) {
|
||||
case ast::AccessControl::kInvalid:
|
||||
out << "invalid";
|
||||
break;
|
||||
case ast::AccessControl::kReadOnly:
|
||||
out << "read";
|
||||
break;
|
||||
|
@ -77,6 +83,10 @@ AccessControl* AccessControl::Clone(CloneContext* ctx) const {
|
|||
|
||||
std::ostream& operator<<(std::ostream& out, AccessControl::Access access) {
|
||||
switch (access) {
|
||||
case ast::AccessControl::kInvalid: {
|
||||
out << "invalid";
|
||||
break;
|
||||
}
|
||||
case ast::AccessControl::kReadOnly: {
|
||||
out << "read_only";
|
||||
break;
|
||||
|
|
|
@ -28,8 +28,11 @@ class AccessControl : public Castable<AccessControl, Type> {
|
|||
public:
|
||||
/// The access control settings
|
||||
enum Access {
|
||||
/// Invalid
|
||||
// TODO(crbug.com/tint/805): Remove this.
|
||||
kInvalid = -1,
|
||||
/// Read only
|
||||
kReadOnly = 0,
|
||||
kReadOnly,
|
||||
/// Write only
|
||||
kWriteOnly,
|
||||
/// Read write
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/ast/intrinsic_texture_helper_test.h"
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
@ -173,7 +172,7 @@ ast::Variable* TextureOverloadCase::buildTextureVariable(
|
|||
|
||||
case ast::intrinsic::test::TextureKind::kStorage: {
|
||||
auto st = b->ty.storage_texture(texture_dimension, image_format);
|
||||
auto ac = b->ty.access(access_control, st);
|
||||
auto* ac = b->ty.access(access_control, st);
|
||||
return b->Global("texture", ac, ast::StorageClass::kNone, nullptr, decos);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ Variable::Variable(ProgramID program_id,
|
|||
const Source& source,
|
||||
const Symbol& sym,
|
||||
StorageClass declared_storage_class,
|
||||
ast::Type* type,
|
||||
const ast::Type* type,
|
||||
bool is_const,
|
||||
Expression* constructor,
|
||||
DecorationList decorations)
|
||||
|
|
|
@ -109,7 +109,7 @@ class Variable : public Castable<Variable, Node> {
|
|||
const Source& source,
|
||||
const Symbol& sym,
|
||||
StorageClass declared_storage_class,
|
||||
ast::Type* type,
|
||||
const ast::Type* type,
|
||||
bool is_const,
|
||||
Expression* constructor,
|
||||
DecorationList decorations);
|
||||
|
@ -122,7 +122,7 @@ class Variable : public Castable<Variable, Node> {
|
|||
const Symbol& symbol() const { return symbol_; }
|
||||
|
||||
/// @returns the variable type
|
||||
ast::Type* type() const { return type_; }
|
||||
ast::Type* type() const { return const_cast<ast::Type*>(type_); }
|
||||
|
||||
/// @returns the declared storage class
|
||||
StorageClass declared_storage_class() const {
|
||||
|
@ -177,7 +177,7 @@ class Variable : public Castable<Variable, Node> {
|
|||
|
||||
Symbol const symbol_;
|
||||
// The value type if a const or formal paramter, and the store type if a var
|
||||
ast::Type* const type_;
|
||||
ast::Type const* const type_;
|
||||
bool const is_const_;
|
||||
Expression* const constructor_;
|
||||
DecorationList const decorations_;
|
||||
|
|
|
@ -153,7 +153,7 @@ class BlockAllocator {
|
|||
std::is_same<T, TYPE>::value || std::is_base_of<T, TYPE>::value,
|
||||
"TYPE does not derive from T");
|
||||
auto uptr = std::make_unique<TYPE>(std::forward<ARGS>(args)...);
|
||||
auto ptr = uptr.get();
|
||||
auto* ptr = uptr.get();
|
||||
objects_.emplace_back(std::move(uptr));
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "src/ast/scalar_constructor_expression.h"
|
||||
#include "src/ast/sint_literal.h"
|
||||
#include "src/ast/uint_literal.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/array.h"
|
||||
#include "src/sem/f32_type.h"
|
||||
#include "src/sem/function.h"
|
||||
|
@ -606,12 +605,11 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
|
|||
auto* var = rsv.first;
|
||||
auto binding_info = rsv.second;
|
||||
|
||||
auto* ac_type = var->Type()->As<sem::AccessControl>();
|
||||
if (ac_type == nullptr) {
|
||||
if (var->AccessControl() == ast::AccessControl::kInvalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read_only != ac_type->IsReadOnly()) {
|
||||
if (read_only != (var->AccessControl() == ast::AccessControl::kReadOnly)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -691,12 +689,10 @@ std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
|
|||
auto* var = ref.first;
|
||||
auto binding_info = ref.second;
|
||||
|
||||
auto* ac_type = var->Type()->As<sem::AccessControl>();
|
||||
if (ac_type == nullptr) {
|
||||
continue;
|
||||
}
|
||||
auto* texture_type = var->Type()->As<sem::StorageTexture>();
|
||||
|
||||
if (read_only != ac_type->IsReadOnly()) {
|
||||
if (read_only !=
|
||||
(texture_type->access_control() == ast::AccessControl::kReadOnly)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -707,7 +703,6 @@ std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
|
|||
entry.bind_group = binding_info.group->value();
|
||||
entry.binding = binding_info.binding->value();
|
||||
|
||||
auto* texture_type = var->Type()->UnwrapAccess()->As<sem::StorageTexture>();
|
||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
||||
texture_type->dim());
|
||||
|
||||
|
|
|
@ -548,33 +548,20 @@ class InspectorHelper : public ProgramBuilder {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/// Generates appropriate types for a StorageTexture
|
||||
/// @param dim the texture dimension of the storage texture
|
||||
/// @param format the image format of the storage texture
|
||||
/// @returns the storage texture type and subtype
|
||||
std::tuple<typ::StorageTexture, typ::Type> MakeStorageTextureTypes(
|
||||
ast::TextureDimension dim,
|
||||
ast::ImageFormat format) {
|
||||
auto tex = ty.storage_texture(dim, format);
|
||||
return {tex, {tex.ast->type(), tex.sem->type()}};
|
||||
}
|
||||
|
||||
/// 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, subtype & access control type
|
||||
std::tuple<typ::StorageTexture, typ::Type, typ::AccessControl>
|
||||
MakeStorageTextureTypes(ast::TextureDimension dim,
|
||||
ast::ImageFormat format,
|
||||
bool read_only) {
|
||||
typ::StorageTexture texture_type;
|
||||
typ::Type subtype;
|
||||
std::tie(texture_type, subtype) = MakeStorageTextureTypes(dim, format);
|
||||
auto access_control = ty.access(read_only ? ast::AccessControl::kReadOnly
|
||||
: ast::AccessControl::kWriteOnly,
|
||||
texture_type);
|
||||
return {texture_type, subtype, access_control};
|
||||
typ::Type MakeStorageTextureTypes(ast::TextureDimension dim,
|
||||
ast::ImageFormat format,
|
||||
bool read_only) {
|
||||
auto ac = read_only ? ast::AccessControl::kReadOnly
|
||||
: ast::AccessControl::kWriteOnly;
|
||||
auto tex = ty.storage_texture(dim, format);
|
||||
|
||||
return {ty.access(ac, tex.ast), tex.sem};
|
||||
}
|
||||
|
||||
/// Adds a storage texture variable to the program
|
||||
|
@ -1682,20 +1669,14 @@ TEST_F(InspectorGetResourceBindingsTest, Simple) {
|
|||
MakeComparisonSamplerReferenceBodyFunction(
|
||||
"cs_func", "cs_texture", "cs_var", "cs_coords", "cs_depth", ty.f32(), {});
|
||||
|
||||
typ::StorageTexture st_type;
|
||||
typ::Type st_subtype;
|
||||
typ::AccessControl st_ac;
|
||||
std::tie(st_type, st_subtype, st_ac) = MakeStorageTextureTypes(
|
||||
ast::TextureDimension::k2d, ast::ImageFormat::kR32Uint, false);
|
||||
AddStorageTexture("st_var", st_ac, 4, 0);
|
||||
auto st_type = MakeStorageTextureTypes(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint, false);
|
||||
AddStorageTexture("st_var", st_type, 4, 0);
|
||||
MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), {});
|
||||
|
||||
typ::StorageTexture rost_type;
|
||||
typ::Type rost_subtype;
|
||||
typ::AccessControl rost_ac;
|
||||
std::tie(rost_type, rost_subtype, rost_ac) = MakeStorageTextureTypes(
|
||||
ast::TextureDimension::k2d, ast::ImageFormat::kR32Uint, true);
|
||||
AddStorageTexture("rost_var", rost_ac, 4, 1);
|
||||
auto rost_type = MakeStorageTextureTypes(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint, true);
|
||||
AddStorageTexture("rost_var", rost_type, 4, 1);
|
||||
MakeStorageTextureBodyFunction("rost_func", "rost_var", ty.vec2<i32>(), {});
|
||||
|
||||
MakeCallerBodyFunction("ep_func",
|
||||
|
@ -2797,12 +2778,8 @@ TEST_P(InspectorGetStorageTextureResourceBindingsTestWithParam, Simple) {
|
|||
ResourceBinding::SampledKind expected_kind;
|
||||
std::tie(format, expected_format, expected_kind) = format_params;
|
||||
|
||||
typ::StorageTexture st_type;
|
||||
typ::Type st_subtype;
|
||||
typ::AccessControl ac;
|
||||
std::tie(st_type, st_subtype, ac) =
|
||||
MakeStorageTextureTypes(dim, format, read_only);
|
||||
AddStorageTexture("st_var", ac, 0, 0);
|
||||
auto st_type = MakeStorageTextureTypes(dim, format, read_only);
|
||||
AddStorageTexture("st_var", st_type, 0, 0);
|
||||
|
||||
typ::Type dim_type = nullptr;
|
||||
switch (dim) {
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <utility>
|
||||
|
||||
#include "src/program_builder.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
|
@ -519,25 +518,25 @@ class StorageTextureBuilder : public Builder {
|
|||
public:
|
||||
explicit StorageTextureBuilder(
|
||||
ast::TextureDimension dimensions,
|
||||
ast::AccessControl::Access access,
|
||||
OpenNumber texel_format, // a.k.a "image format"
|
||||
OpenType channel_format) // a.k.a "storage subtype"
|
||||
: dimensions_(dimensions),
|
||||
access_(access),
|
||||
texel_format_(texel_format),
|
||||
channel_format_(channel_format) {}
|
||||
|
||||
bool Match(MatchState& state, const sem::Type* ty) const override {
|
||||
if (auto* ac = ty->As<sem::AccessControl>()) {
|
||||
// If we have an storage texture argument that's got an access control
|
||||
// type wrapped around it, accept it. Signatures that don't include an
|
||||
// access control imply any access. Example:
|
||||
// textureDimensions(t : texture_storage_1d<F>) -> i32
|
||||
ty = ac->type();
|
||||
}
|
||||
|
||||
if (auto* tex = ty->As<sem::StorageTexture>()) {
|
||||
if (MatchOpenNumber(state, texel_format_,
|
||||
static_cast<uint32_t>(tex->image_format()))) {
|
||||
if (MatchOpenType(state, channel_format_, tex->type())) {
|
||||
// AccessControl::kInvalid means match any
|
||||
if (access_ != ast::AccessControl::kInvalid &&
|
||||
access_ != tex->access_control()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tex->dim() == dimensions_;
|
||||
}
|
||||
}
|
||||
|
@ -550,17 +549,27 @@ class StorageTextureBuilder : public Builder {
|
|||
static_cast<ast::ImageFormat>(state.open_numbers.at(texel_format_));
|
||||
auto* channel_format = state.open_types.at(channel_format_);
|
||||
return state.ty_mgr.Get<sem::StorageTexture>(
|
||||
dimensions_, texel_format, const_cast<sem::Type*>(channel_format));
|
||||
dimensions_, texel_format, access_,
|
||||
const_cast<sem::Type*>(channel_format));
|
||||
}
|
||||
|
||||
std::string str() const override {
|
||||
std::stringstream ss;
|
||||
ss << "texture_storage_" << dimensions_ << "<F>";
|
||||
|
||||
ss << "texture_storage_" << dimensions_ << "<F, ";
|
||||
if (access_ == ast::AccessControl::Access::kInvalid) {
|
||||
ss << "A";
|
||||
} else {
|
||||
ss << access_;
|
||||
}
|
||||
ss << ">";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
ast::TextureDimension const dimensions_;
|
||||
ast::AccessControl::Access const access_;
|
||||
OpenNumber const texel_format_;
|
||||
OpenType const channel_format_;
|
||||
};
|
||||
|
@ -611,38 +620,6 @@ class SamplerBuilder : public Builder {
|
|||
ast::SamplerKind const kind_;
|
||||
};
|
||||
|
||||
/// AccessControlBuilder is a Matcher / Builder for AccessControl types
|
||||
class AccessControlBuilder : public Builder {
|
||||
public:
|
||||
explicit AccessControlBuilder(ast::AccessControl::Access access_control,
|
||||
Builder* type)
|
||||
: access_control_(access_control), type_(type) {}
|
||||
|
||||
bool Match(MatchState& state, const sem::Type* ty) const override {
|
||||
if (auto* ac = ty->As<sem::AccessControl>()) {
|
||||
if (ac->access_control() == access_control_) {
|
||||
return type_->Match(state, ty);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
sem::Type* Build(BuildState& state) const override {
|
||||
auto* ty = type_->Build(state);
|
||||
return state.ty_mgr.Get<sem::AccessControl>(access_control_, ty);
|
||||
}
|
||||
|
||||
std::string str() const override {
|
||||
std::stringstream ss;
|
||||
ss << "[[access(" << access_control_ << ")]] " << type_->str();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
ast::AccessControl::Access const access_control_;
|
||||
Builder* const type_;
|
||||
};
|
||||
|
||||
/// Impl is the private implementation of the IntrinsicTable interface.
|
||||
class Impl : public IntrinsicTable {
|
||||
public:
|
||||
|
@ -764,10 +741,11 @@ class Impl : public IntrinsicTable {
|
|||
/// @returns a Matcher / Builder that matches a storage texture of the given
|
||||
/// format with the given dimensions
|
||||
Builder* storage_texture(ast::TextureDimension dimensions,
|
||||
ast::AccessControl::Access access,
|
||||
OpenNumber texel_format,
|
||||
OpenType channel_format) {
|
||||
return matcher_allocator_.Create<StorageTextureBuilder>(
|
||||
dimensions, texel_format, channel_format);
|
||||
dimensions, access, texel_format, channel_format);
|
||||
}
|
||||
|
||||
/// @returns a Matcher / Builder that matches an external texture
|
||||
|
@ -780,13 +758,6 @@ class Impl : public IntrinsicTable {
|
|||
return matcher_allocator_.Create<SamplerBuilder>(kind);
|
||||
}
|
||||
|
||||
/// @returns a Matcher / Builder that matches an access control type
|
||||
Builder* access_control(ast::AccessControl::Access access_control,
|
||||
Builder* type) {
|
||||
return matcher_allocator_.Create<AccessControlBuilder>(access_control,
|
||||
type);
|
||||
}
|
||||
|
||||
/// Registers an overload with the given intrinsic type, return type Matcher /
|
||||
/// Builder, and parameter Matcher / Builders.
|
||||
/// This overload of Register does not constrain any OpenTypes.
|
||||
|
@ -1108,30 +1079,32 @@ Impl::Impl() {
|
|||
auto* tex_depth_cube = depth_texture(Dim::kCube);
|
||||
auto* tex_depth_cube_array = depth_texture(Dim::kCubeArray);
|
||||
auto* tex_external = external_texture();
|
||||
auto* tex_storage_1d_FT =
|
||||
storage_texture(Dim::k1d, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_2d_FT =
|
||||
storage_texture(Dim::k2d, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_2d_array_FT =
|
||||
storage_texture(Dim::k2dArray, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_3d_FT =
|
||||
storage_texture(Dim::k3d, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_ro_1d_FT =
|
||||
access_control(ast::AccessControl::kReadOnly, tex_storage_1d_FT);
|
||||
auto* tex_storage_ro_2d_FT =
|
||||
access_control(ast::AccessControl::kReadOnly, tex_storage_2d_FT);
|
||||
auto* tex_storage_ro_2d_array_FT =
|
||||
access_control(ast::AccessControl::kReadOnly, tex_storage_2d_array_FT);
|
||||
auto* tex_storage_ro_3d_FT =
|
||||
access_control(ast::AccessControl::kReadOnly, tex_storage_3d_FT);
|
||||
auto* tex_storage_wo_1d_FT =
|
||||
access_control(ast::AccessControl::kWriteOnly, tex_storage_1d_FT);
|
||||
auto* tex_storage_wo_2d_FT =
|
||||
access_control(ast::AccessControl::kWriteOnly, tex_storage_2d_FT);
|
||||
auto* tex_storage_1d_FT = storage_texture(
|
||||
Dim::k1d, ast::AccessControl::kInvalid, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_2d_FT = storage_texture(
|
||||
Dim::k2d, ast::AccessControl::kInvalid, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_2d_array_FT = storage_texture(
|
||||
Dim::k2dArray, ast::AccessControl::kInvalid, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_3d_FT = storage_texture(
|
||||
Dim::k3d, ast::AccessControl::kInvalid, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_ro_1d_FT = storage_texture(
|
||||
Dim::k1d, ast::AccessControl::kReadOnly, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_ro_2d_FT = storage_texture(
|
||||
Dim::k2d, ast::AccessControl::kReadOnly, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_ro_2d_array_FT = storage_texture(
|
||||
Dim::k2dArray, ast::AccessControl::kReadOnly, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_ro_3d_FT = storage_texture(
|
||||
Dim::k3d, ast::AccessControl::kReadOnly, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_wo_1d_FT = storage_texture(
|
||||
Dim::k1d, ast::AccessControl::kWriteOnly, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_wo_2d_FT = storage_texture(
|
||||
Dim::k2d, ast::AccessControl::kWriteOnly, OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_wo_2d_array_FT =
|
||||
access_control(ast::AccessControl::kWriteOnly, tex_storage_2d_array_FT);
|
||||
auto* tex_storage_wo_3d_FT =
|
||||
access_control(ast::AccessControl::kWriteOnly, tex_storage_3d_FT);
|
||||
storage_texture(Dim::k2dArray, ast::AccessControl::kWriteOnly,
|
||||
OpenNumber::F, OpenType::T);
|
||||
auto* tex_storage_wo_3d_FT = storage_texture(
|
||||
Dim::k3d, ast::AccessControl::kWriteOnly, OpenNumber::F, OpenType::T);
|
||||
|
||||
auto* sampler = this->sampler(ast::SamplerKind::kSampler);
|
||||
auto* sampler_comparison =
|
||||
this->sampler(ast::SamplerKind::kComparisonSampler);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/program_builder.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
|
@ -302,34 +301,39 @@ TEST_F(IntrinsicTableTest, MatchExternalTexture) {
|
|||
}
|
||||
|
||||
TEST_F(IntrinsicTableTest, MatchROStorageTexture) {
|
||||
auto tex = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR16Float);
|
||||
auto tex_ac = ty.access(ast::AccessControl::kReadOnly, tex);
|
||||
auto* subtype =
|
||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR16Float, Types());
|
||||
auto* tex = create<sem::StorageTexture>(
|
||||
ast::TextureDimension::k2d, ast::ImageFormat::kR16Float,
|
||||
ast::AccessControl::kReadOnly, subtype);
|
||||
|
||||
auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
|
||||
{tex_ac, ty.vec2<i32>()}, Source{});
|
||||
{tex, ty.vec2<i32>()}, Source{});
|
||||
ASSERT_NE(result.intrinsic, nullptr);
|
||||
ASSERT_EQ(result.diagnostics.str(), "");
|
||||
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
|
||||
EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
|
||||
EXPECT_THAT(
|
||||
result.intrinsic->Parameters(),
|
||||
ElementsAre(Parameter{tex_ac, Parameter::Usage::kTexture},
|
||||
ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
|
||||
Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords}));
|
||||
}
|
||||
|
||||
TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
|
||||
auto tex = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR16Float);
|
||||
auto tex_ac = ty.access(ast::AccessControl::kWriteOnly, tex);
|
||||
auto result =
|
||||
table->Lookup(*this, IntrinsicType::kTextureStore,
|
||||
{tex_ac, ty.vec2<i32>(), ty.vec4<f32>()}, Source{});
|
||||
auto* subtype =
|
||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR16Float, Types());
|
||||
auto* tex = create<sem::StorageTexture>(
|
||||
ast::TextureDimension::k2d, ast::ImageFormat::kR16Float,
|
||||
ast::AccessControl::kWriteOnly, subtype);
|
||||
|
||||
auto result = table->Lookup(*this, IntrinsicType::kTextureStore,
|
||||
{tex, ty.vec2<i32>(), ty.vec4<f32>()}, Source{});
|
||||
ASSERT_NE(result.intrinsic, nullptr);
|
||||
ASSERT_EQ(result.diagnostics.str(), "");
|
||||
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureStore);
|
||||
EXPECT_THAT(result.intrinsic->ReturnType(), ty.void_());
|
||||
EXPECT_THAT(result.intrinsic->Parameters(),
|
||||
ElementsAre(Parameter{tex_ac, Parameter::Usage::kTexture},
|
||||
ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
|
||||
Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords},
|
||||
Parameter{ty.vec4<f32>(), Parameter::Usage::kValue}));
|
||||
}
|
||||
|
@ -440,10 +444,10 @@ TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
|
|||
textureDimensions(texture : texture_depth_2d_array) -> vec2<i32>
|
||||
textureDimensions(texture : texture_depth_cube) -> vec3<i32>
|
||||
textureDimensions(texture : texture_depth_cube_array) -> vec3<i32>
|
||||
textureDimensions(texture : texture_storage_1d<F>) -> i32
|
||||
textureDimensions(texture : texture_storage_2d<F>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_2d_array<F>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_3d<F>) -> vec3<i32>
|
||||
textureDimensions(texture : texture_storage_1d<F, A>) -> i32
|
||||
textureDimensions(texture : texture_storage_2d<F, A>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_2d_array<F, A>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_3d<F, A>) -> vec3<i32>
|
||||
textureDimensions(texture : texture_external) -> vec2<i32>
|
||||
)");
|
||||
}
|
||||
|
@ -478,10 +482,10 @@ TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
|
|||
textureDimensions(texture : texture_depth_2d_array) -> vec2<i32>
|
||||
textureDimensions(texture : texture_depth_cube) -> vec3<i32>
|
||||
textureDimensions(texture : texture_depth_cube_array) -> vec3<i32>
|
||||
textureDimensions(texture : texture_storage_1d<F>) -> i32
|
||||
textureDimensions(texture : texture_storage_2d<F>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_2d_array<F>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_3d<F>) -> vec3<i32>
|
||||
textureDimensions(texture : texture_storage_1d<F, A>) -> i32
|
||||
textureDimensions(texture : texture_storage_2d<F, A>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_2d_array<F, A>) -> vec2<i32>
|
||||
textureDimensions(texture : texture_storage_3d<F, A>) -> vec3<i32>
|
||||
textureDimensions(texture : texture_external) -> vec2<i32>
|
||||
)");
|
||||
}
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
#include "src/ast/void.h"
|
||||
#include "src/program.h"
|
||||
#include "src/program_id.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/array.h"
|
||||
#include "src/sem/bool_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
|
@ -704,13 +703,10 @@ class ProgramBuilder {
|
|||
/// @param access the access control
|
||||
/// @param type the inner type
|
||||
/// @returns the access control qualifier type
|
||||
typ::AccessControl access(ast::AccessControl::Access access,
|
||||
typ::Type type) const {
|
||||
type = MaybeCreateTypename(type);
|
||||
return {type.ast ? builder->create<ast::AccessControl>(access, type)
|
||||
: nullptr,
|
||||
type.sem ? builder->create<sem::AccessControl>(access, type)
|
||||
: nullptr};
|
||||
ast::AccessControl* access(ast::AccessControl::Access access,
|
||||
const ast::Type* type) const {
|
||||
type = MaybeCreateTypename(type).ast;
|
||||
return type ? builder->create<ast::AccessControl>(access, type) : nullptr;
|
||||
}
|
||||
|
||||
/// Creates an access control qualifier type
|
||||
|
@ -718,15 +714,12 @@ class ProgramBuilder {
|
|||
/// @param access the access control
|
||||
/// @param type the inner type
|
||||
/// @returns the access control qualifier type
|
||||
typ::AccessControl access(const Source& source,
|
||||
ast::AccessControl::Access access,
|
||||
typ::Type type) const {
|
||||
type = MaybeCreateTypename(type);
|
||||
return {type.ast
|
||||
? builder->create<ast::AccessControl>(source, access, type)
|
||||
: nullptr,
|
||||
type.sem ? builder->create<sem::AccessControl>(access, type)
|
||||
: nullptr};
|
||||
ast::AccessControl* access(const Source& source,
|
||||
ast::AccessControl::Access access,
|
||||
const ast::Type* type) const {
|
||||
type = MaybeCreateTypename(type).ast;
|
||||
return type ? builder->create<ast::AccessControl>(source, access, type)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/// @param type the type of the pointer
|
||||
|
@ -855,7 +848,8 @@ class ProgramBuilder {
|
|||
auto* sem_subtype =
|
||||
sem::StorageTexture::SubtypeFor(format, builder->Types());
|
||||
return {builder->create<ast::StorageTexture>(dims, format, ast_subtype),
|
||||
builder->create<sem::StorageTexture>(dims, format, sem_subtype)};
|
||||
builder->create<sem::StorageTexture>(
|
||||
dims, format, ast::AccessControl::kInvalid, sem_subtype)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
|
@ -870,7 +864,8 @@ class ProgramBuilder {
|
|||
sem::StorageTexture::SubtypeFor(format, builder->Types());
|
||||
return {builder->create<ast::StorageTexture>(source, dims, format,
|
||||
ast_subtype),
|
||||
builder->create<sem::StorageTexture>(dims, format, sem_subtype)};
|
||||
builder->create<sem::StorageTexture>(
|
||||
dims, format, ast::AccessControl::kInvalid, sem_subtype)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
|
@ -1189,7 +1184,7 @@ class ProgramBuilder {
|
|||
/// @returns a `ast::Variable` with the given name, storage and type
|
||||
template <typename NAME>
|
||||
ast::Variable* Var(NAME&& name,
|
||||
ast::Type* type,
|
||||
const ast::Type* type,
|
||||
ast::StorageClass storage = ast::StorageClass::kNone,
|
||||
ast::Expression* constructor = nullptr,
|
||||
ast::DecorationList decorations = {}) {
|
||||
|
@ -1208,7 +1203,7 @@ class ProgramBuilder {
|
|||
template <typename NAME>
|
||||
ast::Variable* Var(const Source& source,
|
||||
NAME&& name,
|
||||
ast::Type* type,
|
||||
const ast::Type* type,
|
||||
ast::StorageClass storage = ast::StorageClass::kNone,
|
||||
ast::Expression* constructor = nullptr,
|
||||
ast::DecorationList decorations = {}) {
|
||||
|
@ -1290,7 +1285,7 @@ class ProgramBuilder {
|
|||
/// global variable with the ast::Module.
|
||||
template <typename NAME>
|
||||
ast::Variable* Global(NAME&& name,
|
||||
ast::Type* type,
|
||||
const ast::Type* type,
|
||||
ast::StorageClass storage,
|
||||
ast::Expression* constructor = nullptr,
|
||||
ast::DecorationList decorations = {}) {
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/ast/type_name.h"
|
||||
#include "src/reader/spirv/function.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
|
|
@ -35,8 +35,8 @@ TEST(SpvParserTypeTest, SameArgumentsGivesSamePointer) {
|
|||
EXPECT_EQ(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 3));
|
||||
EXPECT_EQ(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 2));
|
||||
EXPECT_EQ(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 2));
|
||||
EXPECT_EQ(ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly),
|
||||
ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly));
|
||||
EXPECT_EQ(ty.AccessControl(ty.I32(), ast::AccessControl::kReadOnly),
|
||||
ty.AccessControl(ty.I32(), ast::AccessControl::kReadOnly));
|
||||
EXPECT_EQ(ty.Alias(sym, ty.I32()), ty.Alias(sym, ty.I32()));
|
||||
EXPECT_EQ(ty.Struct(sym, {ty.I32()}), ty.Struct(sym, {ty.I32()}));
|
||||
EXPECT_EQ(ty.Sampler(ast::SamplerKind::kSampler),
|
||||
|
@ -70,10 +70,10 @@ TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
|
|||
EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.U32(), 3, 2));
|
||||
EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 2, 2));
|
||||
EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 3));
|
||||
EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly),
|
||||
ty.AccessControl(ty.U32(), ast::AccessControl::Access::kReadOnly));
|
||||
EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly),
|
||||
ty.AccessControl(ty.I32(), ast::AccessControl::Access::kWriteOnly));
|
||||
EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::kReadOnly),
|
||||
ty.AccessControl(ty.U32(), ast::AccessControl::kReadOnly));
|
||||
EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::kReadOnly),
|
||||
ty.AccessControl(ty.I32(), ast::AccessControl::kWriteOnly));
|
||||
EXPECT_NE(ty.Alias(sym_a, ty.I32()), ty.Alias(sym_b, ty.I32()));
|
||||
EXPECT_NE(ty.Struct(sym_a, {ty.I32()}), ty.Struct(sym_b, {ty.I32()}));
|
||||
EXPECT_NE(ty.Sampler(ast::SamplerKind::kSampler),
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "src/ast/vector.h"
|
||||
#include "src/ast/workgroup_decoration.h"
|
||||
#include "src/reader/wgsl/lexer.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/reader/wgsl/parser_impl_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace reader {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -260,8 +259,8 @@ TEST_F(ResolverAssignmentValidationTest, AssignFromPointer_Fail) {
|
|||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error v-000x: invalid assignment: right-hand-side is not "
|
||||
"storable: ptr<uniform_constant, [[access(read)]] "
|
||||
"texture_storage_1d<rgba8unorm>>");
|
||||
"storable: ptr<uniform_constant, texture_storage_1d<rgba8unorm, "
|
||||
"read_only>>");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -523,7 +523,7 @@ TEST_F(ResourceDecorationTest, UniformBufferMissingBinding) {
|
|||
TEST_F(ResourceDecorationTest, StorageBufferMissingBinding) {
|
||||
auto* s = Structure("S", {Member("x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{12, 34}}, "G", ac, ast::StorageClass::kStorage);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "gmock/gmock.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/struct.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -29,7 +28,7 @@ using ResolverHostShareableValidationTest = ResolverTest;
|
|||
TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -48,7 +47,7 @@ TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
|||
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -69,7 +68,7 @@ TEST_F(ResolverHostShareableValidationTest, Aliases) {
|
|||
AST().AddConstructedType(a1);
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a2 = ty.alias("a2", ac);
|
||||
AST().AddConstructedType(a2);
|
||||
Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage, nullptr,
|
||||
|
@ -94,7 +93,7 @@ TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
|
|||
|
||||
auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -136,7 +135,7 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
|
|||
|
||||
auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "src/ast/unary_op_expression.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/call.h"
|
||||
#include "src/sem/function.h"
|
||||
#include "src/sem/member_accessor_expression.h"
|
||||
|
@ -241,7 +240,7 @@ class ResolverIntrinsicTest_TextureOperation
|
|||
}
|
||||
|
||||
void add_call_param(std::string name,
|
||||
typ::Type type,
|
||||
const ast::Type* type,
|
||||
ast::ExpressionList* call_params) {
|
||||
if (type->UnwrapAll()->is_handle()) {
|
||||
Global(name, type, ast::StorageClass::kNone, nullptr,
|
||||
|
@ -276,7 +275,8 @@ TEST_P(ResolverIntrinsicTest_StorageTextureOperation, TextureLoadRo) {
|
|||
|
||||
auto coords_type = GetCoordsType(dim, ty.i32());
|
||||
auto texture_type = ty.storage_texture(dim, format);
|
||||
auto ro_texture_type = ty.access(ast::AccessControl::kReadOnly, texture_type);
|
||||
auto* ro_texture_type =
|
||||
ty.access(ast::AccessControl::kReadOnly, texture_type);
|
||||
|
||||
ast::ExpressionList call_params;
|
||||
|
||||
|
@ -769,7 +769,7 @@ TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) {
|
|||
auto* ary = ty.array<i32>();
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
Global("a", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
|
@ -79,16 +78,6 @@ TEST_F(ResolverIsHostShareable, Pointer) {
|
|||
r()->IsHostShareable(ty.pointer<i32>(ast::StorageClass::kPrivate)));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsHostShareable, AccessControlVoid) {
|
||||
EXPECT_FALSE(r()->IsHostShareable(
|
||||
ty.access(ast::AccessControl::kReadOnly, ty.void_())));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsHostShareable, AccessControlI32) {
|
||||
EXPECT_TRUE(
|
||||
r()->IsHostShareable(ty.access(ast::AccessControl::kReadOnly, ty.i32())));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsHostShareable, ArraySizedOfHostShareable) {
|
||||
auto* arr = create<sem::Array>(create<sem::I32>(), 5, 4, 20, 4, true);
|
||||
EXPECT_TRUE(r()->IsHostShareable(arr));
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
|
@ -63,16 +62,6 @@ TEST_F(ResolverIsStorableTest, Pointer) {
|
|||
EXPECT_FALSE(r()->IsStorable(ty.pointer<i32>(ast::StorageClass::kPrivate)));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, AccessControlVoid) {
|
||||
EXPECT_FALSE(r()->IsStorable(
|
||||
create<sem::AccessControl>(ast::AccessControl::kReadOnly, ty.void_())));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, AccessControlI32) {
|
||||
EXPECT_TRUE(r()->IsStorable(
|
||||
create<sem::AccessControl>(ast::AccessControl::kReadOnly, ty.i32())));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, ArraySizedOfStorable) {
|
||||
auto* arr = create<sem::Array>(create<sem::I32>(), 5, 4, 20, 4, true);
|
||||
EXPECT_TRUE(r()->IsStorable(arr));
|
||||
|
|
|
@ -81,7 +81,7 @@ TEST_F(ResolverPipelineOverridableConstantTest, WithAndWithoutIds) {
|
|||
for (auto* var : variables) {
|
||||
auto* sem = Sem().Get(var);
|
||||
ASSERT_NE(sem, nullptr);
|
||||
constant_ids.push_back(sem->ConstantId());
|
||||
constant_ids.push_back(static_cast<uint16_t>(sem->ConstantId()));
|
||||
}
|
||||
EXPECT_THAT(constant_ids, UnorderedElementsAre(0u, 3u, 2u, 4u, 5u, 1u));
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/ast/vector.h"
|
||||
#include "src/ast/workgroup_decoration.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/array.h"
|
||||
#include "src/sem/call.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
|
@ -341,12 +340,18 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
return builder_->create<sem::F32>();
|
||||
}
|
||||
if (auto* t = ty->As<ast::Alias>()) {
|
||||
auto added = name_to_ast_type_.emplace(t->name(), t->type()).second;
|
||||
// TODO(crbug.com/tint/803): Remove this.
|
||||
if (!added) {
|
||||
return nullptr;
|
||||
}
|
||||
return Type(t->type());
|
||||
}
|
||||
if (auto* t = ty->As<ast::AccessControl>()) {
|
||||
ScopedAssignment<const ast::AccessControl*> sa(curent_access_control_, t);
|
||||
|
||||
if (auto* el = Type(t->type())) {
|
||||
return builder_->create<sem::AccessControl>(t->access_control(),
|
||||
const_cast<sem::Type*>(el));
|
||||
return el;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -400,8 +405,18 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
}
|
||||
if (auto* t = ty->As<ast::StorageTexture>()) {
|
||||
if (auto* el = Type(t->type())) {
|
||||
auto ac = ast::AccessControl::kInvalid;
|
||||
if (curent_access_control_) {
|
||||
ac = curent_access_control_->access_control();
|
||||
} else {
|
||||
// TODO(amaiorano): move error about missing access control on storage
|
||||
// textures here, instead of when variables declared. That way, we'd
|
||||
// get the error on the alias line (for
|
||||
// alias<accesscontrol<storagetexture>>).
|
||||
}
|
||||
|
||||
return builder_->create<sem::StorageTexture>(
|
||||
t->dim(), t->image_format(), const_cast<sem::Type*>(el));
|
||||
t->dim(), t->image_format(), ac, const_cast<sem::Type*>(el));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -483,8 +498,30 @@ Resolver::VariableInfo* Resolver::Variable(ast::Variable* var,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto* info =
|
||||
variable_infos_.Create(var, const_cast<sem::Type*>(type), type_name);
|
||||
// TODO(crbug.com/tint/802): Temporary while ast::AccessControl exits.
|
||||
auto find_first_access_control =
|
||||
[this](ast::Type* ty) -> ast::AccessControl* {
|
||||
ast::AccessControl* ac = ty->As<ast::AccessControl>();
|
||||
if (ac) {
|
||||
return ac;
|
||||
}
|
||||
while (auto* tn = ty->As<ast::TypeName>()) {
|
||||
ty = name_to_ast_type_[tn->name()];
|
||||
ac = ty->As<ast::AccessControl>();
|
||||
if (ac) {
|
||||
return ac;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto access_control = ast::AccessControl::kInvalid;
|
||||
if (auto* ac = find_first_access_control(var->type())) {
|
||||
access_control = ac->access_control();
|
||||
}
|
||||
|
||||
auto* info = variable_infos_.Create(var, const_cast<sem::Type*>(type),
|
||||
type_name, access_control);
|
||||
variable_to_info_.emplace(var, info);
|
||||
|
||||
return info;
|
||||
|
@ -630,8 +667,10 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
|||
// Its store type must be a host-shareable structure type with block
|
||||
// attribute, satisfying the storage class constraints.
|
||||
|
||||
auto* access = info->type->As<sem::AccessControl>();
|
||||
auto* str = access ? access->type()->As<sem::Struct>() : nullptr;
|
||||
auto* str = info->access_control != ast::AccessControl::kInvalid
|
||||
? info->type->As<sem::Struct>()
|
||||
: nullptr;
|
||||
|
||||
if (!str) {
|
||||
diagnostics_.add_error(
|
||||
"variables declared in the <storage> storage class must be of an "
|
||||
|
@ -716,38 +755,36 @@ bool Resolver::ValidateVariable(const VariableInfo* info) {
|
|||
}
|
||||
}
|
||||
|
||||
if (type->As<sem::StorageTexture>()) {
|
||||
diagnostics_.add_error("Storage Textures must have access control.",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
if (auto* storage_tex = type->As<sem::StorageTexture>()) {
|
||||
if (storage_tex->access_control() == ast::AccessControl::kInvalid) {
|
||||
diagnostics_.add_error("Storage Textures must have access control.",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||
if (auto* r = ac->type()->As<sem::StorageTexture>()) {
|
||||
if (ac->IsReadWrite()) {
|
||||
diagnostics_.add_error(
|
||||
"Storage Textures only support Read-Only and Write-Only access "
|
||||
"control.",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
if (info->access_control == ast::AccessControl::kReadWrite) {
|
||||
diagnostics_.add_error(
|
||||
"Storage Textures only support Read-Only and Write-Only access "
|
||||
"control.",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsValidStorageTextureDimension(r->dim())) {
|
||||
diagnostics_.add_error(
|
||||
"Cube dimensions for storage textures are not "
|
||||
"supported.",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
if (!IsValidStorageTextureDimension(storage_tex->dim())) {
|
||||
diagnostics_.add_error(
|
||||
"Cube dimensions for storage textures are not "
|
||||
"supported.",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsValidStorageTextureImageFormat(r->image_format())) {
|
||||
diagnostics_.add_error(
|
||||
"image format must be one of the texel formats specified for "
|
||||
"storage textues in "
|
||||
"https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
if (!IsValidStorageTextureImageFormat(storage_tex->image_format())) {
|
||||
diagnostics_.add_error(
|
||||
"image format must be one of the texel formats specified for "
|
||||
"storage textues in "
|
||||
"https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
|
||||
var->source());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2289,7 +2326,7 @@ void Resolver::CreateSemanticNodes() const {
|
|||
// Create a pipeline overridable constant.
|
||||
uint16_t constant_id;
|
||||
if (override_deco->HasValue()) {
|
||||
constant_id = override_deco->value();
|
||||
constant_id = static_cast<uint16_t>(override_deco->value());
|
||||
} else {
|
||||
// No ID was specified, so allocate the next available ID.
|
||||
constant_id = next_constant_id;
|
||||
|
@ -2306,8 +2343,8 @@ void Resolver::CreateSemanticNodes() const {
|
|||
|
||||
sem_var = builder_->create<sem::Variable>(var, info->type, constant_id);
|
||||
} else {
|
||||
sem_var =
|
||||
builder_->create<sem::Variable>(var, info->type, info->storage_class);
|
||||
sem_var = builder_->create<sem::Variable>(
|
||||
var, info->type, info->storage_class, info->access_control);
|
||||
}
|
||||
|
||||
std::vector<const sem::VariableUser*> users;
|
||||
|
@ -2969,11 +3006,13 @@ void Resolver::Mark(const ast::Node* node) {
|
|||
|
||||
Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
|
||||
sem::Type* ctype,
|
||||
const std::string& tn)
|
||||
const std::string& tn,
|
||||
ast::AccessControl::Access ac)
|
||||
: declaration(decl),
|
||||
type(ctype),
|
||||
type_name(tn),
|
||||
storage_class(decl->declared_storage_class()) {
|
||||
storage_class(decl->declared_storage_class()),
|
||||
access_control(ac) {
|
||||
if (storage_class == ast::StorageClass::kNone &&
|
||||
type->UnwrapAll()->is_handle()) {
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
|
||||
|
|
|
@ -90,13 +90,15 @@ class Resolver {
|
|||
struct VariableInfo {
|
||||
VariableInfo(const ast::Variable* decl,
|
||||
sem::Type* type,
|
||||
const std::string& type_name);
|
||||
const std::string& type_name,
|
||||
ast::AccessControl::Access ac);
|
||||
~VariableInfo();
|
||||
|
||||
ast::Variable const* const declaration;
|
||||
sem::Type* type;
|
||||
std::string const type_name;
|
||||
ast::StorageClass storage_class;
|
||||
ast::AccessControl::Access const access_control;
|
||||
std::vector<ast::IdentifierExpression*> users;
|
||||
sem::BindingPoint binding_point;
|
||||
};
|
||||
|
@ -348,8 +350,11 @@ class Resolver {
|
|||
std::unordered_map<Symbol, sem::Type*> named_types_;
|
||||
std::unordered_set<const ast::Node*> marked_;
|
||||
std::unordered_map<uint32_t, const VariableInfo*> constant_ids_;
|
||||
std::unordered_map<Symbol, ast::Type*> name_to_ast_type_;
|
||||
|
||||
FunctionInfo* current_function_ = nullptr;
|
||||
sem::Statement* current_statement_ = nullptr;
|
||||
const ast::AccessControl* curent_access_control_ = nullptr;
|
||||
BlockAllocator<VariableInfo> variable_infos_;
|
||||
BlockAllocator<FunctionInfo> function_infos_;
|
||||
};
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include "src/ast/unary_op_expression.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/call.h"
|
||||
#include "src/sem/function.h"
|
||||
#include "src/sem/member_accessor_expression.h"
|
||||
|
@ -763,7 +762,7 @@ TEST_F(ResolverTest, Function_Parameters) {
|
|||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
||||
auto* s = Structure("S", {Member("m", ty.u32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
|
||||
auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
|
||||
|
@ -802,7 +801,7 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
|||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
|
||||
auto* s = Structure("S", {Member("m", ty.u32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
|
||||
auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
|
||||
|
@ -1475,7 +1474,7 @@ TEST_F(ResolverTest, StorageClass_SetForSampler) {
|
|||
|
||||
TEST_F(ResolverTest, StorageClass_SetForTexture) {
|
||||
auto t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
||||
auto ac = ty.access(ast::AccessControl::Access::kReadOnly, t);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, t);
|
||||
auto* var = Global("var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
|
|
@ -255,13 +255,6 @@ sem::Type* sem_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
|
|||
return ty.builder->create<sem::Matrix>(column_type, 4u);
|
||||
}
|
||||
|
||||
template <create_sem_type_func_ptr create_type>
|
||||
sem::Type* sem_access(const ProgramBuilder::TypesBuilder& ty) {
|
||||
auto* type = create_type(ty);
|
||||
return ty.builder->create<sem::AccessControl>(ast::AccessControl::kReadOnly,
|
||||
type);
|
||||
}
|
||||
|
||||
} // namespace resolver
|
||||
} // namespace tint
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "gmock/gmock.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/struct.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -70,7 +69,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
|
|||
// var<storage> g : [[access(read)]] array<S, 3>;
|
||||
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||
auto* a = ty.array(s, 3);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -122,7 +121,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
|
|||
// struct S { x : i32 };
|
||||
// var<storage> g : [[access(read)]] S;
|
||||
auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -142,7 +141,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
|
|||
// var<storage> g : [[access(read)]] S;
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -161,7 +160,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
|
|||
{create<ast::StructBlockDecoration>()});
|
||||
auto* a1 = ty.alias("a1", s);
|
||||
AST().AddConstructedType(a1);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, a1);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, a1);
|
||||
auto* a2 = ty.alias("a2", ac);
|
||||
AST().AddConstructedType(a2);
|
||||
Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage, nullptr,
|
||||
|
@ -211,7 +210,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
|
|||
// var<uniform> g : [[access(read)]] array<S, 3>;
|
||||
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||
auto* a = ty.array(s, 3);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
|
|
@ -172,7 +172,7 @@ TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
|
|||
TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
||||
auto* s = Structure("S", {Member("a", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global("x", s, ast::StorageClass::kUniform, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/resolver/resolver.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
|
||||
|
@ -501,11 +500,11 @@ static constexpr Params cases[] = {
|
|||
Params{ast_alias<ast_alias<ast_mat3x3<ast_alias<ast_alias<ast_f32>>>>>,
|
||||
sem_mat3x3<sem_f32>},
|
||||
|
||||
Params{ast_alias<ast_access<ast_alias<ast_bool>>>, sem_access<sem_bool>},
|
||||
Params{ast_alias<ast_access<ast_alias<ast_bool>>>, sem_bool},
|
||||
Params{ast_alias<ast_access<ast_alias<ast_vec3<ast_access<ast_f32>>>>>,
|
||||
sem_access<sem_vec3<sem_access<sem_f32>>>},
|
||||
sem_vec3<sem_f32>},
|
||||
Params{ast_alias<ast_access<ast_alias<ast_mat3x3<ast_access<ast_f32>>>>>,
|
||||
sem_access<sem_mat3x3<sem_access<sem_f32>>>},
|
||||
sem_mat3x3<sem_f32>},
|
||||
};
|
||||
|
||||
using CanonicalTest = ResolverTestWithParam<Params>;
|
||||
|
@ -633,7 +632,7 @@ TEST_P(StorageTextureDimensionTest, All) {
|
|||
auto& params = GetParam();
|
||||
|
||||
auto st = ty.storage_texture(params.dim, ast::ImageFormat::kR32Uint);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, st);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, st);
|
||||
|
||||
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
|
@ -706,7 +705,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
|||
// var d : [[access(read)]] texture_storage_3d<*>;
|
||||
|
||||
auto st_a = ty.storage_texture(ast::TextureDimension::k1d, params.format);
|
||||
auto ac_a = ty.access(ast::AccessControl::kReadOnly, st_a);
|
||||
auto* ac_a = ty.access(ast::AccessControl::kReadOnly, st_a);
|
||||
Global("a", ac_a, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -714,7 +713,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
|||
});
|
||||
|
||||
auto st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format);
|
||||
auto ac_b = ty.access(ast::AccessControl::kReadOnly, st_b);
|
||||
auto* ac_b = ty.access(ast::AccessControl::kReadOnly, st_b);
|
||||
Global("b", ac_b, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -723,7 +722,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
|||
|
||||
auto st_c =
|
||||
ty.storage_texture(ast::TextureDimension::k2dArray, params.format);
|
||||
auto ac_c = ty.access(ast::AccessControl::kReadOnly, st_c);
|
||||
auto* ac_c = ty.access(ast::AccessControl::kReadOnly, st_c);
|
||||
Global("c", ac_c, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -731,7 +730,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
|||
});
|
||||
|
||||
auto st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format);
|
||||
auto ac_d = ty.access(ast::AccessControl::kReadOnly, st_d);
|
||||
auto* ac_d = ty.access(ast::AccessControl::kReadOnly, st_d);
|
||||
Global("d", ac_d, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -772,9 +771,8 @@ TEST_F(StorageTextureAccessControlTest, RWAccessControl_Fail) {
|
|||
|
||||
auto st = ty.storage_texture(ast::TextureDimension::k1d,
|
||||
ast::ImageFormat::kR32Uint);
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, st);
|
||||
|
||||
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||
Global("a", st, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(0),
|
||||
create<ast::GroupDecoration>(0),
|
||||
|
@ -789,7 +787,7 @@ TEST_F(StorageTextureAccessControlTest, ReadOnlyAccessControl_Pass) {
|
|||
|
||||
auto st = ty.storage_texture(ast::TextureDimension::k1d,
|
||||
ast::ImageFormat::kR32Uint);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, st);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, st);
|
||||
|
||||
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
|
@ -806,7 +804,7 @@ TEST_F(StorageTextureAccessControlTest, WriteOnlyAccessControl_Pass) {
|
|||
|
||||
auto st = ty.storage_texture(ast::TextureDimension::k1d,
|
||||
ast::ImageFormat::kR32Uint);
|
||||
auto ac = ty.access(ast::AccessControl::kWriteOnly, st);
|
||||
auto* ac = ty.access(ast::AccessControl::kWriteOnly, st);
|
||||
|
||||
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "src/ast/unary_op_expression.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/call.h"
|
||||
#include "src/sem/function.h"
|
||||
#include "src/sem/member_accessor_expression.h"
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright 2020 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
|
||||
#include "src/program_builder.h"
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::sem::AccessControl);
|
||||
|
||||
namespace tint {
|
||||
namespace sem {
|
||||
|
||||
AccessControl::AccessControl(ast::AccessControl::Access access,
|
||||
const Type* subtype)
|
||||
: access_(access), subtype_(subtype) {
|
||||
TINT_ASSERT(subtype_);
|
||||
TINT_ASSERT(!subtype_->Is<AccessControl>());
|
||||
}
|
||||
|
||||
AccessControl::AccessControl(AccessControl&&) = default;
|
||||
|
||||
AccessControl::~AccessControl() = default;
|
||||
|
||||
std::string AccessControl::type_name() const {
|
||||
std::string name = "__access_control_";
|
||||
switch (access_) {
|
||||
case ast::AccessControl::kReadOnly:
|
||||
name += "read_only";
|
||||
break;
|
||||
case ast::AccessControl::kWriteOnly:
|
||||
name += "write_only";
|
||||
break;
|
||||
case ast::AccessControl::kReadWrite:
|
||||
name += "read_write";
|
||||
break;
|
||||
}
|
||||
return name + subtype_->type_name();
|
||||
}
|
||||
|
||||
std::string AccessControl::FriendlyName(const SymbolTable& symbols) const {
|
||||
std::ostringstream out;
|
||||
out << "[[access(";
|
||||
switch (access_) {
|
||||
case ast::AccessControl::kReadOnly:
|
||||
out << "read";
|
||||
break;
|
||||
case ast::AccessControl::kWriteOnly:
|
||||
out << "write";
|
||||
break;
|
||||
case ast::AccessControl::kReadWrite:
|
||||
out << "read_write";
|
||||
break;
|
||||
}
|
||||
out << ")]] " << subtype_->FriendlyName(symbols);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
} // namespace sem
|
||||
} // namespace tint
|
|
@ -1,65 +0,0 @@
|
|||
// Copyright 2020 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SRC_SEM_ACCESS_CONTROL_TYPE_H_
|
||||
#define SRC_SEM_ACCESS_CONTROL_TYPE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "src/ast/access_control.h"
|
||||
#include "src/sem/type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace sem {
|
||||
|
||||
/// An access control type. Holds an access setting and pointer to another type.
|
||||
class AccessControl : public Castable<AccessControl, Type> {
|
||||
public:
|
||||
/// Constructor
|
||||
/// @param access the access control setting
|
||||
/// @param subtype the access controlled type
|
||||
AccessControl(ast::AccessControl::Access access, const Type* subtype);
|
||||
/// Move constructor
|
||||
AccessControl(AccessControl&&);
|
||||
~AccessControl() override;
|
||||
|
||||
/// @returns true if the access control is read only
|
||||
bool IsReadOnly() const { return access_ == ast::AccessControl::kReadOnly; }
|
||||
/// @returns true if the access control is write only
|
||||
bool IsWriteOnly() const { return access_ == ast::AccessControl::kWriteOnly; }
|
||||
/// @returns true if the access control is read/write
|
||||
bool IsReadWrite() const { return access_ == ast::AccessControl::kReadWrite; }
|
||||
|
||||
/// @returns the access control value
|
||||
ast::AccessControl::Access access_control() const { return access_; }
|
||||
/// @returns the subtype type
|
||||
Type* type() const { return const_cast<Type*>(subtype_); }
|
||||
|
||||
/// @returns the name for this type
|
||||
std::string type_name() const override;
|
||||
|
||||
/// @param symbols the program's symbol table
|
||||
/// @returns the name for this type that closely resembles how it would be
|
||||
/// declared in WGSL.
|
||||
std::string FriendlyName(const SymbolTable& symbols) const override;
|
||||
|
||||
private:
|
||||
ast::AccessControl::Access const access_;
|
||||
const Type* const subtype_;
|
||||
};
|
||||
|
||||
} // namespace sem
|
||||
} // namespace tint
|
||||
|
||||
#endif // SRC_SEM_ACCESS_CONTROL_TYPE_H_
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright 2020 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace sem {
|
||||
namespace {
|
||||
|
||||
using AccessControlTest = TestHelper;
|
||||
|
||||
TEST_F(AccessControlTest, Create) {
|
||||
U32 u32;
|
||||
AccessControl a{ast::AccessControl::kReadWrite, &u32};
|
||||
EXPECT_TRUE(a.IsReadWrite());
|
||||
EXPECT_EQ(a.type(), &u32);
|
||||
}
|
||||
|
||||
TEST_F(AccessControlTest, AccessRead) {
|
||||
I32 i32;
|
||||
AccessControl at{ast::AccessControl::kReadOnly, &i32};
|
||||
EXPECT_TRUE(at.IsReadOnly());
|
||||
EXPECT_FALSE(at.IsWriteOnly());
|
||||
EXPECT_FALSE(at.IsReadWrite());
|
||||
|
||||
EXPECT_EQ(at.type_name(), "__access_control_read_only__i32");
|
||||
}
|
||||
|
||||
TEST_F(AccessControlTest, AccessWrite) {
|
||||
I32 i32;
|
||||
AccessControl at{ast::AccessControl::kWriteOnly, &i32};
|
||||
EXPECT_FALSE(at.IsReadOnly());
|
||||
EXPECT_TRUE(at.IsWriteOnly());
|
||||
EXPECT_FALSE(at.IsReadWrite());
|
||||
|
||||
EXPECT_EQ(at.type_name(), "__access_control_write_only__i32");
|
||||
}
|
||||
|
||||
TEST_F(AccessControlTest, AccessReadWrite) {
|
||||
I32 i32;
|
||||
AccessControl at{ast::AccessControl::kReadWrite, &i32};
|
||||
EXPECT_FALSE(at.IsReadOnly());
|
||||
EXPECT_FALSE(at.IsWriteOnly());
|
||||
EXPECT_TRUE(at.IsReadWrite());
|
||||
|
||||
EXPECT_EQ(at.type_name(), "__access_control_read_write__i32");
|
||||
}
|
||||
|
||||
TEST_F(AccessControlTest, FriendlyNameReadOnly) {
|
||||
AccessControl at{ast::AccessControl::kReadOnly, ty.i32()};
|
||||
EXPECT_EQ(at.FriendlyName(Symbols()), "[[access(read)]] i32");
|
||||
}
|
||||
|
||||
TEST_F(AccessControlTest, FriendlyNameWriteOnly) {
|
||||
AccessControl at{ast::AccessControl::kWriteOnly, ty.i32()};
|
||||
EXPECT_EQ(at.FriendlyName(Symbols()), "[[access(write)]] i32");
|
||||
}
|
||||
|
||||
TEST_F(AccessControlTest, FriendlyNameReadWrite) {
|
||||
AccessControl at{ast::AccessControl::kReadWrite, ty.i32()};
|
||||
EXPECT_EQ(at.FriendlyName(Symbols()), "[[access(read_write)]] i32");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace sem
|
||||
} // namespace tint
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "src/sem/test_helper.h"
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/sem/external_texture_type.h"
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/struct.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
|
|
@ -23,8 +23,12 @@ namespace sem {
|
|||
|
||||
StorageTexture::StorageTexture(ast::TextureDimension dim,
|
||||
ast::ImageFormat format,
|
||||
ast::AccessControl::Access access_control,
|
||||
sem::Type* subtype)
|
||||
: Base(dim), image_format_(format), subtype_(subtype) {}
|
||||
: Base(dim),
|
||||
image_format_(format),
|
||||
access_control_(access_control),
|
||||
subtype_(subtype) {}
|
||||
|
||||
StorageTexture::StorageTexture(StorageTexture&&) = default;
|
||||
|
||||
|
@ -32,13 +36,15 @@ StorageTexture::~StorageTexture() = default;
|
|||
|
||||
std::string StorageTexture::type_name() const {
|
||||
std::ostringstream out;
|
||||
out << "__storage_texture_" << dim() << "_" << image_format_;
|
||||
out << "__storage_texture_" << dim() << "_" << image_format_ << "_"
|
||||
<< access_control_;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string StorageTexture::FriendlyName(const SymbolTable&) const {
|
||||
std::ostringstream out;
|
||||
out << "texture_storage_" << dim() << "<" << image_format_ << ">";
|
||||
out << "texture_storage_" << dim() << "<" << image_format_ << ", "
|
||||
<< access_control_ << ">";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "src/ast/access_control.h"
|
||||
#include "src/ast/storage_texture.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
@ -31,9 +32,11 @@ class StorageTexture : public Castable<StorageTexture, Texture> {
|
|||
/// Constructor
|
||||
/// @param dim the dimensionality of the texture
|
||||
/// @param format the image format of the texture
|
||||
/// @param access_control the access control type of the texture
|
||||
/// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
|
||||
StorageTexture(ast::TextureDimension dim,
|
||||
ast::ImageFormat format,
|
||||
ast::AccessControl::Access access_control,
|
||||
sem::Type* subtype);
|
||||
|
||||
/// Move constructor
|
||||
|
@ -46,6 +49,9 @@ class StorageTexture : public Castable<StorageTexture, Texture> {
|
|||
/// @returns the image format
|
||||
ast::ImageFormat image_format() const { return image_format_; }
|
||||
|
||||
/// @returns the access control
|
||||
ast::AccessControl::Access access_control() const { return access_control_; }
|
||||
|
||||
/// @returns the name for this type
|
||||
std::string type_name() const override;
|
||||
|
||||
|
@ -61,6 +67,7 @@ class StorageTexture : public Castable<StorageTexture, Texture> {
|
|||
|
||||
private:
|
||||
ast::ImageFormat const image_format_;
|
||||
ast::AccessControl::Access const access_control_;
|
||||
Type* const subtype_;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
@ -30,7 +29,8 @@ TEST_F(StorageTextureTest, Dim) {
|
|||
auto* subtype =
|
||||
StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
|
||||
auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kRgba32Float, subtype);
|
||||
ast::ImageFormat::kRgba32Float,
|
||||
ast::AccessControl::kReadWrite, subtype);
|
||||
EXPECT_EQ(s->dim(), ast::TextureDimension::k2dArray);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@ TEST_F(StorageTextureTest, Format) {
|
|||
auto* subtype =
|
||||
StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
|
||||
auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kRgba32Float, subtype);
|
||||
ast::ImageFormat::kRgba32Float,
|
||||
ast::AccessControl::kReadWrite, subtype);
|
||||
EXPECT_EQ(s->image_format(), ast::ImageFormat::kRgba32Float);
|
||||
}
|
||||
|
||||
|
@ -46,24 +47,28 @@ TEST_F(StorageTextureTest, TypeName) {
|
|||
auto* subtype =
|
||||
StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
|
||||
auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kRgba32Float, subtype);
|
||||
EXPECT_EQ(s->type_name(), "__storage_texture_2d_array_rgba32float");
|
||||
ast::ImageFormat::kRgba32Float,
|
||||
ast::AccessControl::kReadWrite, subtype);
|
||||
EXPECT_EQ(s->type_name(),
|
||||
"__storage_texture_2d_array_rgba32float_read_write");
|
||||
}
|
||||
|
||||
TEST_F(StorageTextureTest, FriendlyName) {
|
||||
auto* subtype =
|
||||
StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
|
||||
auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kRgba32Float, subtype);
|
||||
ast::ImageFormat::kRgba32Float,
|
||||
ast::AccessControl::kReadWrite, subtype);
|
||||
EXPECT_EQ(s->FriendlyName(Symbols()),
|
||||
"texture_storage_2d_array<rgba32float>");
|
||||
"texture_storage_2d_array<rgba32float, read_write>");
|
||||
}
|
||||
|
||||
TEST_F(StorageTextureTest, F32) {
|
||||
auto* subtype =
|
||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
|
||||
Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kRgba32Float, subtype);
|
||||
ast::ImageFormat::kRgba32Float,
|
||||
ast::AccessControl::kReadWrite, subtype);
|
||||
|
||||
auto program = Build();
|
||||
|
||||
|
@ -77,7 +82,8 @@ TEST_F(StorageTextureTest, U32) {
|
|||
auto* subtype =
|
||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kRg32Uint, Types());
|
||||
Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kRg32Uint, subtype);
|
||||
ast::ImageFormat::kRg32Uint,
|
||||
ast::AccessControl::kReadWrite, subtype);
|
||||
|
||||
auto program = Build();
|
||||
|
||||
|
@ -91,7 +97,8 @@ TEST_F(StorageTextureTest, I32) {
|
|||
auto* subtype =
|
||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Sint, Types());
|
||||
Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kRgba32Sint, subtype);
|
||||
ast::ImageFormat::kRgba32Sint,
|
||||
ast::AccessControl::kReadWrite, subtype);
|
||||
|
||||
auto program = Build();
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/sem/type.h"
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/bool_type.h"
|
||||
#include "src/sem/f32_type.h"
|
||||
#include "src/sem/i32_type.h"
|
||||
|
@ -45,10 +44,8 @@ const Type* Type::UnwrapPtr() const {
|
|||
}
|
||||
|
||||
const Type* Type::UnwrapAccess() const {
|
||||
// TODO(amaiorano): Delete this function
|
||||
auto* type = this;
|
||||
while (auto* access = type->As<sem::AccessControl>()) {
|
||||
type = access->type();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -57,8 +54,6 @@ const Type* Type::UnwrapAll() const {
|
|||
while (true) {
|
||||
if (auto* ptr = type->As<sem::Pointer>()) {
|
||||
type = ptr->type();
|
||||
} else if (auto* access = type->As<sem::AccessControl>()) {
|
||||
type = access->type();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -25,10 +25,12 @@ namespace sem {
|
|||
|
||||
Variable::Variable(const ast::Variable* declaration,
|
||||
const sem::Type* type,
|
||||
ast::StorageClass storage_class)
|
||||
ast::StorageClass storage_class,
|
||||
ast::AccessControl::Access access_control)
|
||||
: declaration_(declaration),
|
||||
type_(type),
|
||||
storage_class_(storage_class),
|
||||
access_control_(access_control),
|
||||
is_pipeline_constant_(false) {}
|
||||
|
||||
Variable::Variable(const ast::Variable* declaration,
|
||||
|
@ -37,6 +39,7 @@ Variable::Variable(const ast::Variable* declaration,
|
|||
: declaration_(declaration),
|
||||
type_(type),
|
||||
storage_class_(ast::StorageClass::kNone),
|
||||
access_control_(ast::AccessControl::kInvalid),
|
||||
is_pipeline_constant_(true),
|
||||
constant_id_(constant_id) {}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "src/ast/access_control.h"
|
||||
#include "src/ast/storage_class.h"
|
||||
#include "src/sem/expression.h"
|
||||
|
||||
|
@ -41,9 +42,11 @@ class Variable : public Castable<Variable, Node> {
|
|||
/// @param declaration the AST declaration node
|
||||
/// @param type the variable type
|
||||
/// @param storage_class the variable storage class
|
||||
/// @param access_control the variable access control type
|
||||
Variable(const ast::Variable* declaration,
|
||||
const sem::Type* type,
|
||||
ast::StorageClass storage_class);
|
||||
ast::StorageClass storage_class,
|
||||
ast::AccessControl::Access access_control);
|
||||
|
||||
/// Constructor for overridable pipeline constants
|
||||
/// @param declaration the AST declaration node
|
||||
|
@ -65,6 +68,9 @@ class Variable : public Castable<Variable, Node> {
|
|||
/// @returns the storage class for the variable
|
||||
ast::StorageClass StorageClass() const { return storage_class_; }
|
||||
|
||||
/// @returns the access control for the variable
|
||||
ast::AccessControl::Access AccessControl() const { return access_control_; }
|
||||
|
||||
/// @returns the expressions that use the variable
|
||||
const std::vector<const VariableUser*>& Users() const { return users_; }
|
||||
|
||||
|
@ -81,6 +87,7 @@ class Variable : public Castable<Variable, Node> {
|
|||
const ast::Variable* const declaration_;
|
||||
const sem::Type* const type_;
|
||||
ast::StorageClass const storage_class_;
|
||||
ast::AccessControl::Access const access_control_;
|
||||
std::vector<const VariableUser*> users_;
|
||||
const bool is_pipeline_constant_;
|
||||
const uint16_t constant_id_ = 0;
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "src/ast/disable_validation_decoration.h"
|
||||
#include "src/program_builder.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/function.h"
|
||||
#include "src/sem/variable.h"
|
||||
|
||||
|
@ -115,12 +114,7 @@ Output BindingRemapper::Run(const Program* in, const DataMap& datamap) {
|
|||
if (ac_it != remappings->access_controls.end()) {
|
||||
ast::AccessControl::Access ac = ac_it->second;
|
||||
auto* ty = in->Sem().Get(var)->Type();
|
||||
ast::Type* inner_ty = nullptr;
|
||||
if (auto* old_ac = ty->As<sem::AccessControl>()) {
|
||||
inner_ty = CreateASTTypeFor(&ctx, old_ac->type());
|
||||
} else {
|
||||
inner_ty = CreateASTTypeFor(&ctx, ty);
|
||||
}
|
||||
ast::Type* inner_ty = CreateASTTypeFor(&ctx, ty);
|
||||
auto* new_ty = ctx.dst->create<ast::AccessControl>(ac, inner_ty);
|
||||
auto* new_var = ctx.dst->create<ast::Variable>(
|
||||
ctx.Clone(var->source()), ctx.Clone(var->symbol()),
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "src/ast/scalar_constructor_expression.h"
|
||||
#include "src/ast/type_name.h"
|
||||
#include "src/program_builder.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/array.h"
|
||||
#include "src/sem/call.h"
|
||||
#include "src/sem/member_accessor_expression.h"
|
||||
|
@ -338,10 +337,6 @@ const ast::NamedType* ConstructedTypeOf(const sem::Type* ty) {
|
|||
ty = ptr->type();
|
||||
continue;
|
||||
}
|
||||
if (auto* access = ty->As<sem::AccessControl>()) {
|
||||
ty = access->type();
|
||||
continue;
|
||||
}
|
||||
if (auto* str = ty->As<sem::Struct>()) {
|
||||
return str->Declaration();
|
||||
}
|
||||
|
@ -364,6 +359,17 @@ struct Store {
|
|||
StorageBufferAccess target; // The target for the write
|
||||
};
|
||||
|
||||
ast::Type* MaybeCreateASTAccessControl(CloneContext* ctx,
|
||||
const sem::VariableUser* var_user,
|
||||
ast::Type* ty) {
|
||||
if (var_user &&
|
||||
var_user->Variable()->AccessControl() != ast::AccessControl::kInvalid) {
|
||||
return ctx->dst->create<ast::AccessControl>(
|
||||
var_user->Variable()->AccessControl(), ty);
|
||||
}
|
||||
return ty;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// State holds the current transform state
|
||||
|
@ -415,13 +421,17 @@ struct DecomposeStorageAccess::State {
|
|||
/// @param insert_after the user-declared type to insert the function after
|
||||
/// @param buf_ty the storage buffer type
|
||||
/// @param el_ty the storage buffer element type
|
||||
/// @param var_user the variable user
|
||||
/// @return the name of the function that performs the load
|
||||
Symbol LoadFunc(CloneContext& ctx,
|
||||
const ast::NamedType* insert_after,
|
||||
const sem::Type* buf_ty,
|
||||
const sem::Type* el_ty) {
|
||||
const sem::Type* el_ty,
|
||||
const sem::VariableUser* var_user) {
|
||||
return utils::GetOrCreate(load_funcs, TypePair{buf_ty, el_ty}, [&] {
|
||||
auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
|
||||
buf_ast_ty = MaybeCreateASTAccessControl(&ctx, var_user, buf_ast_ty);
|
||||
|
||||
ast::VariableList params = {
|
||||
// Note: The buffer parameter requires the kStorage StorageClass in
|
||||
// order for HLSL to emit this as a ByteAddressBuffer.
|
||||
|
@ -446,7 +456,7 @@ struct DecomposeStorageAccess::State {
|
|||
ast::ExpressionList values;
|
||||
if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
|
||||
auto* vec_ty = mat_ty->ColumnType();
|
||||
Symbol load = LoadFunc(ctx, insert_after, buf_ty, vec_ty);
|
||||
Symbol load = LoadFunc(ctx, insert_after, buf_ty, vec_ty, var_user);
|
||||
for (uint32_t i = 0; i < mat_ty->columns(); i++) {
|
||||
auto* offset =
|
||||
ctx.dst->Add("offset", i * MatrixColumnStride(mat_ty));
|
||||
|
@ -456,14 +466,14 @@ struct DecomposeStorageAccess::State {
|
|||
for (auto* member : str->Members()) {
|
||||
auto* offset = ctx.dst->Add("offset", member->Offset());
|
||||
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
|
||||
member->Type()->UnwrapAll());
|
||||
member->Type()->UnwrapAll(), var_user);
|
||||
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
||||
}
|
||||
} else if (auto* arr = el_ty->As<sem::Array>()) {
|
||||
for (uint32_t i = 0; i < arr->Count(); i++) {
|
||||
auto* offset = ctx.dst->Add("offset", arr->Stride() * i);
|
||||
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
|
||||
arr->ElemType()->UnwrapAll());
|
||||
arr->ElemType()->UnwrapAll(), var_user);
|
||||
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
||||
}
|
||||
}
|
||||
|
@ -487,13 +497,16 @@ struct DecomposeStorageAccess::State {
|
|||
/// @param insert_after the user-declared type to insert the function after
|
||||
/// @param buf_ty the storage buffer type
|
||||
/// @param el_ty the storage buffer element type
|
||||
/// @param var_user the variable user
|
||||
/// @return the name of the function that performs the store
|
||||
Symbol StoreFunc(CloneContext& ctx,
|
||||
const ast::NamedType* insert_after,
|
||||
const sem::Type* buf_ty,
|
||||
const sem::Type* el_ty) {
|
||||
const sem::Type* el_ty,
|
||||
const sem::VariableUser* var_user) {
|
||||
return utils::GetOrCreate(store_funcs, TypePair{buf_ty, el_ty}, [&] {
|
||||
auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
|
||||
buf_ast_ty = MaybeCreateASTAccessControl(&ctx, var_user, buf_ast_ty);
|
||||
auto* el_ast_ty = CreateASTTypeFor(&ctx, el_ty);
|
||||
ast::VariableList params{
|
||||
// Note: The buffer parameter requires the kStorage StorageClass in
|
||||
|
@ -519,7 +532,7 @@ struct DecomposeStorageAccess::State {
|
|||
ast::StatementList body;
|
||||
if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
|
||||
auto* vec_ty = mat_ty->ColumnType();
|
||||
Symbol store = StoreFunc(ctx, insert_after, buf_ty, vec_ty);
|
||||
Symbol store = StoreFunc(ctx, insert_after, buf_ty, vec_ty, var_user);
|
||||
for (uint32_t i = 0; i < mat_ty->columns(); i++) {
|
||||
auto* offset =
|
||||
ctx.dst->Add("offset", i * MatrixColumnStride(mat_ty));
|
||||
|
@ -533,7 +546,7 @@ struct DecomposeStorageAccess::State {
|
|||
auto* access = ctx.dst->MemberAccessor(
|
||||
"value", ctx.Clone(member->Declaration()->symbol()));
|
||||
Symbol store = StoreFunc(ctx, insert_after, buf_ty,
|
||||
member->Type()->UnwrapAll());
|
||||
member->Type()->UnwrapAll(), var_user);
|
||||
auto* call = ctx.dst->Call(store, "buffer", offset, access);
|
||||
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
|
||||
}
|
||||
|
@ -542,7 +555,7 @@ struct DecomposeStorageAccess::State {
|
|||
auto* offset = ctx.dst->Add("offset", arr->Stride() * i);
|
||||
auto* access = ctx.dst->IndexAccessor("value", ctx.dst->Expr(i));
|
||||
Symbol store = StoreFunc(ctx, insert_after, buf_ty,
|
||||
arr->ElemType()->UnwrapAll());
|
||||
arr->ElemType()->UnwrapAll(), var_user);
|
||||
auto* call = ctx.dst->Call(store, "buffer", offset, access);
|
||||
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
|
||||
}
|
||||
|
@ -760,7 +773,8 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
|||
auto* buf_ty = access.var->Type()->UnwrapPtr();
|
||||
auto* el_ty = access.type->UnwrapAll();
|
||||
auto* insert_after = ConstructedTypeOf(access.var->Type());
|
||||
Symbol func = state.LoadFunc(ctx, insert_after, buf_ty, el_ty);
|
||||
Symbol func = state.LoadFunc(ctx, insert_after, buf_ty, el_ty,
|
||||
access.var->As<sem::VariableUser>());
|
||||
|
||||
auto* load = ctx.dst->Call(func, ctx.Clone(buf), offset);
|
||||
|
||||
|
@ -775,7 +789,8 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
|||
auto* el_ty = store.target.type->UnwrapAll();
|
||||
auto* value = store.assignment->rhs();
|
||||
auto* insert_after = ConstructedTypeOf(store.target.var->Type());
|
||||
Symbol func = state.StoreFunc(ctx, insert_after, buf_ty, el_ty);
|
||||
Symbol func = state.StoreFunc(ctx, insert_after, buf_ty, el_ty,
|
||||
store.target.var->As<sem::VariableUser>());
|
||||
|
||||
auto* call = ctx.dst->Call(func, ctx.Clone(buf), offset, ctx.Clone(value));
|
||||
|
||||
|
|
|
@ -103,10 +103,6 @@ ast::Type* Transform::CreateASTTypeFor(CloneContext* ctx, const sem::Type* ty) {
|
|||
}
|
||||
return ctx->dst->create<ast::Array>(el, a->Count(), std::move(decos));
|
||||
}
|
||||
if (auto* ac = ty->As<sem::AccessControl>()) {
|
||||
auto* el = CreateASTTypeFor(ctx, ac->type());
|
||||
return ctx->dst->create<ast::AccessControl>(ac->access_control(), el);
|
||||
}
|
||||
if (auto* s = ty->As<sem::Struct>()) {
|
||||
return ctx->dst->create<ast::TypeName>(
|
||||
ctx->Clone(s->Declaration()->name()));
|
||||
|
|
|
@ -102,19 +102,6 @@ TEST_F(CreateASTTypeForTest, ArrayNonImplicitStride) {
|
|||
->stride(),
|
||||
32u);
|
||||
}
|
||||
TEST_F(CreateASTTypeForTest, AccessControl) {
|
||||
auto* ac = create([](ProgramBuilder& b) {
|
||||
auto* decl = b.Structure("S", {}, {});
|
||||
auto* str =
|
||||
b.create<sem::Struct>(decl, sem::StructMemberList{}, 4 /* align */,
|
||||
4 /* size */, 4 /* size_no_padding */);
|
||||
return b.create<sem::AccessControl>(ast::AccessControl::kReadOnly, str);
|
||||
});
|
||||
ASSERT_TRUE(ac->Is<ast::AccessControl>());
|
||||
EXPECT_EQ(ac->As<ast::AccessControl>()->access_control(),
|
||||
ast::AccessControl::kReadOnly);
|
||||
EXPECT_TRUE(ac->As<ast::AccessControl>()->type()->Is<ast::TypeName>());
|
||||
}
|
||||
|
||||
TEST_F(CreateASTTypeForTest, Struct) {
|
||||
auto* str = create([](ProgramBuilder& b) {
|
||||
|
|
|
@ -214,7 +214,7 @@ struct State {
|
|||
ctx.dst->create<ast::StructBlockDecoration>(),
|
||||
});
|
||||
for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
|
||||
auto access =
|
||||
auto* access =
|
||||
ctx.dst->ty.access(ast::AccessControl::kReadOnly, struct_type);
|
||||
// The decorated variable with struct type
|
||||
ctx.dst->Global(
|
||||
|
|
|
@ -237,7 +237,6 @@ bool operator!=(std::nullptr_t, const TypePair<AST, SEM>& rhs) {
|
|||
|
||||
using Type = TypePair<ast::Type, sem::Type>;
|
||||
|
||||
using AccessControl = TypePair<ast::AccessControl, sem::AccessControl>;
|
||||
using Array = TypePair<ast::Array, sem::Array>;
|
||||
using Bool = TypePair<ast::Bool, sem::Bool>;
|
||||
using DepthTexture = TypePair<ast::DepthTexture, sem::DepthTexture>;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "src/ast/internal_decoration.h"
|
||||
#include "src/ast/override_decoration.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/array.h"
|
||||
#include "src/sem/call.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
|
@ -247,7 +246,8 @@ bool GeneratorImpl::EmitBitcast(std::ostream& pre,
|
|||
}
|
||||
|
||||
out << "as";
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone, "")) {
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "")) {
|
||||
return false;
|
||||
}
|
||||
out << "(";
|
||||
|
@ -1313,7 +1313,8 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
|||
if (brackets) {
|
||||
out << "{";
|
||||
} else {
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone, "")) {
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "")) {
|
||||
return false;
|
||||
}
|
||||
out << "(";
|
||||
|
@ -1571,7 +1572,8 @@ bool GeneratorImpl::EmitFunctionInternal(std::ostream& out,
|
|||
Symbol ep_sym) {
|
||||
auto* func = builder_.Sem().Get(func_ast);
|
||||
|
||||
if (!EmitType(out, func->ReturnType(), ast::StorageClass::kNone, "")) {
|
||||
if (!EmitType(out, func->ReturnType(), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1629,7 +1631,7 @@ bool GeneratorImpl::EmitFunctionInternal(std::ostream& out,
|
|||
// buffers. These functions have a storage buffer parameter with
|
||||
// StorageClass::kStorage. This is required to correctly translate the
|
||||
// parameter to [RW]ByteAddressBuffer.
|
||||
if (!EmitType(out, type, v->StorageClass(),
|
||||
if (!EmitType(out, type, v->StorageClass(), v->AccessControl(),
|
||||
builder_.Symbols().NameFor(v->Declaration()->symbol()))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1716,7 +1718,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
|
||||
increment_indent();
|
||||
make_indent(out);
|
||||
if (!EmitType(out, type, var->StorageClass(), "")) {
|
||||
if (!EmitType(out, type, var->StorageClass(), var->AccessControl(), "")) {
|
||||
return false;
|
||||
}
|
||||
out << " " << builder_.Symbols().NameFor(decl->symbol()) << ";"
|
||||
|
@ -1741,18 +1743,21 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
continue; // Global already emitted
|
||||
}
|
||||
|
||||
auto* access = var->Type()->As<sem::AccessControl>();
|
||||
if (access == nullptr) {
|
||||
if (var->AccessControl() == ast::AccessControl::kInvalid) {
|
||||
diagnostics_.add_error("access control type required for storage buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EmitType(out, var->Type(), ast::StorageClass::kStorage, "")) {
|
||||
if (!EmitType(out, var->Type(), ast::StorageClass::kStorage,
|
||||
var->AccessControl(), "")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out << " " << builder_.Symbols().NameFor(decl->symbol())
|
||||
<< RegisterAndSpace(access->IsReadOnly() ? 't' : 'u', binding_point)
|
||||
<< RegisterAndSpace(
|
||||
var->AccessControl() == ast::AccessControl::kReadOnly ? 't'
|
||||
: 'u',
|
||||
binding_point)
|
||||
<< ";" << std::endl;
|
||||
emitted_storagebuffer = true;
|
||||
}
|
||||
|
@ -1779,7 +1784,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
auto* type = sem->Type();
|
||||
|
||||
make_indent(out);
|
||||
if (!EmitType(out, type, sem->StorageClass(),
|
||||
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
|
||||
builder_.Symbols().NameFor(var->symbol()))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1830,7 +1835,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
auto* type = sem->Type();
|
||||
|
||||
make_indent(out);
|
||||
if (!EmitType(out, type, sem->StorageClass(),
|
||||
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
|
||||
builder_.Symbols().NameFor(var->symbol()))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1898,7 +1903,8 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
}
|
||||
|
||||
auto name = builder_.Symbols().NameFor(decl->symbol());
|
||||
if (!EmitType(out, var->Type(), var->StorageClass(), name)) {
|
||||
if (!EmitType(out, var->Type(), var->StorageClass(), var->AccessControl(),
|
||||
name)) {
|
||||
return false;
|
||||
}
|
||||
if (!var->Type()->Is<sem::Array>()) {
|
||||
|
@ -1909,11 +1915,9 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
|
||||
if (unwrapped_type->Is<sem::Texture>()) {
|
||||
register_space = "t";
|
||||
if (unwrapped_type->Is<sem::StorageTexture>()) {
|
||||
if (auto* ac = var->Type()->As<sem::AccessControl>()) {
|
||||
if (!ac->IsReadOnly()) {
|
||||
register_space = "u";
|
||||
}
|
||||
if (auto* storage_tex = unwrapped_type->As<sem::StorageTexture>()) {
|
||||
if (storage_tex->access_control() != ast::AccessControl::kReadOnly) {
|
||||
register_space = "u";
|
||||
}
|
||||
}
|
||||
} else if (unwrapped_type->Is<sem::Sampler>()) {
|
||||
|
@ -2030,7 +2034,7 @@ bool GeneratorImpl::EmitEntryPointFunction(std::ostream& out,
|
|||
}
|
||||
first = false;
|
||||
|
||||
if (!EmitType(out, type, sem->StorageClass(), "")) {
|
||||
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(), "")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2098,7 +2102,8 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, sem::Type* type) {
|
|||
} else if (type->Is<sem::U32>()) {
|
||||
out << "0u";
|
||||
} else if (auto* vec = type->As<sem::Vector>()) {
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone, "")) {
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "")) {
|
||||
return false;
|
||||
}
|
||||
ScopedParen sp(out);
|
||||
|
@ -2111,7 +2116,8 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, sem::Type* type) {
|
|||
}
|
||||
}
|
||||
} else if (auto* mat = type->As<sem::Matrix>()) {
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone, "")) {
|
||||
if (!EmitType(out, type, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "")) {
|
||||
return false;
|
||||
}
|
||||
ScopedParen sp(out);
|
||||
|
@ -2368,19 +2374,10 @@ bool GeneratorImpl::EmitSwitch(std::ostream& out, ast::SwitchStatement* stmt) {
|
|||
bool GeneratorImpl::EmitType(std::ostream& out,
|
||||
const sem::Type* type,
|
||||
ast::StorageClass storage_class,
|
||||
ast::AccessControl::Access access_control,
|
||||
const std::string& name) {
|
||||
auto* access = type->As<sem::AccessControl>();
|
||||
if (access) {
|
||||
type = access->type();
|
||||
}
|
||||
|
||||
if (storage_class == ast::StorageClass::kStorage) {
|
||||
if (access == nullptr) {
|
||||
diagnostics_.add_error("access control type required for storage buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!access->IsReadOnly()) {
|
||||
if (access_control != ast::AccessControl::kReadOnly) {
|
||||
out << "RW";
|
||||
}
|
||||
out << "ByteAddressBuffer";
|
||||
|
@ -2400,7 +2397,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
|||
sizes.push_back(arr->Count());
|
||||
base_type = arr->ElemType();
|
||||
}
|
||||
if (!EmitType(out, base_type, storage_class, "")) {
|
||||
if (!EmitType(out, base_type, storage_class, access_control, "")) {
|
||||
return false;
|
||||
}
|
||||
if (!name.empty()) {
|
||||
|
@ -2416,7 +2413,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
|||
} else if (type->Is<sem::I32>()) {
|
||||
out << "int";
|
||||
} else if (auto* mat = type->As<sem::Matrix>()) {
|
||||
if (!EmitType(out, mat->type(), storage_class, "")) {
|
||||
if (!EmitType(out, mat->type(), storage_class, access_control, "")) {
|
||||
return false;
|
||||
}
|
||||
// Note: HLSL's matrices are declared as <type>NxM, where N is the number of
|
||||
|
@ -2446,7 +2443,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
|||
auto* sampled = tex->As<sem::SampledTexture>();
|
||||
|
||||
if (storage) {
|
||||
if (access && !access->IsReadOnly()) {
|
||||
if (access_control != ast::AccessControl::kReadOnly) {
|
||||
out << "RW";
|
||||
}
|
||||
}
|
||||
|
@ -2512,7 +2509,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
|||
out << "uint" << size;
|
||||
} else {
|
||||
out << "vector<";
|
||||
if (!EmitType(out, vec->type(), storage_class, "")) {
|
||||
if (!EmitType(out, vec->type(), storage_class, access_control, "")) {
|
||||
return false;
|
||||
}
|
||||
out << ", " << size << ">";
|
||||
|
@ -2548,7 +2545,8 @@ bool GeneratorImpl::EmitStructType(std::ostream& out,
|
|||
// https://bugs.chromium.org/p/tint/issues/detail?id=184
|
||||
|
||||
auto mem_name = builder_.Symbols().NameFor(mem->Declaration()->symbol());
|
||||
if (!EmitType(out, mem->Type(), ast::StorageClass::kNone, mem_name)) {
|
||||
if (!EmitType(out, mem->Type(), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, mem_name)) {
|
||||
return false;
|
||||
}
|
||||
// Array member name will be output with the type
|
||||
|
@ -2650,7 +2648,7 @@ bool GeneratorImpl::EmitVariable(std::ostream& out,
|
|||
}
|
||||
auto* sem = builder_.Sem().Get(var);
|
||||
auto* type = sem->Type();
|
||||
if (!EmitType(out, type, sem->StorageClass(),
|
||||
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
|
||||
builder_.Symbols().NameFor(var->symbol()))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2703,7 +2701,7 @@ bool GeneratorImpl::EmitProgramConstVariable(std::ostream& out,
|
|||
}
|
||||
out << "#endif" << std::endl;
|
||||
out << "static const ";
|
||||
if (!EmitType(out, type, sem->StorageClass(),
|
||||
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
|
||||
builder_.Symbols().NameFor(var->symbol()))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2712,7 +2710,7 @@ bool GeneratorImpl::EmitProgramConstVariable(std::ostream& out,
|
|||
out << "#undef WGSL_SPEC_CONSTANT_" << const_id << std::endl;
|
||||
} else {
|
||||
out << "static const ";
|
||||
if (!EmitType(out, type, sem->StorageClass(),
|
||||
if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
|
||||
builder_.Symbols().NameFor(var->symbol()))) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -287,11 +287,13 @@ class GeneratorImpl : public TextGenerator {
|
|||
/// @param out the output stream
|
||||
/// @param type the type to generate
|
||||
/// @param storage_class the storage class of the variable
|
||||
/// @param access_control the access control type of the variable
|
||||
/// @param name the name of the variable, only used for array emission
|
||||
/// @returns true if the type is emitted
|
||||
bool EmitType(std::ostream& out,
|
||||
const sem::Type* type,
|
||||
ast::StorageClass storage_class,
|
||||
ast::AccessControl::Access access_control,
|
||||
const std::string& name);
|
||||
/// Handles generating a structure declaration
|
||||
/// @param out the output stream
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/ast/workgroup_decoration.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/writer/hlsl/test_helper.h"
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
@ -408,7 +407,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
@ -454,7 +453,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
@ -500,7 +499,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kWriteOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kWriteOnly, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
@ -543,7 +542,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
@ -794,7 +793,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) {
|
||||
auto* s = Structure("S", {Member("x", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -984,7 +983,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("data", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "gmock/gmock.h"
|
||||
#include "src/ast/stage_decoration.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/writer/hlsl/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -99,7 +98,7 @@ class HlslGeneratorImplTest_MemberAccessorBase : public BASE {
|
|||
auto* s =
|
||||
b.Structure("Data", members, {b.create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
b.Global("data", ac_ty, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "src/ast/stage_decoration.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/writer/hlsl/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -34,7 +33,7 @@ TEST_F(HlslSanitizerTest, ArrayLength) {
|
|||
{
|
||||
create<ast::StructBlockDecoration>(),
|
||||
});
|
||||
auto ac_ty = ty.access(ast::AccessControl::kReadOnly, sb_ty);
|
||||
auto* ac_ty = ty.access(ast::AccessControl::kReadOnly, sb_ty);
|
||||
|
||||
Global("sb", ac_ty, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "src/ast/call_statement.h"
|
||||
#include "src/ast/stage_decoration.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
@ -38,8 +37,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Array) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(
|
||||
gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone, "ary"))
|
||||
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "ary"))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "bool ary[4]");
|
||||
}
|
||||
|
@ -50,8 +49,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(
|
||||
gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone, "ary"))
|
||||
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "ary"))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "bool ary[5][4]");
|
||||
}
|
||||
|
@ -64,8 +63,8 @@ TEST_F(HlslGeneratorImplTest_Type,
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(
|
||||
gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone, "ary"))
|
||||
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "ary"))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "bool ary[5][4][1]");
|
||||
}
|
||||
|
@ -76,8 +75,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(
|
||||
gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone, "ary"))
|
||||
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "ary"))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "bool ary[6][5][4]");
|
||||
}
|
||||
|
@ -88,8 +87,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(
|
||||
gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "bool[4]");
|
||||
}
|
||||
|
@ -100,8 +99,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_RuntimeArray) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(
|
||||
gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone, "ary"))
|
||||
ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, "ary"))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "bool ary[]");
|
||||
}
|
||||
|
@ -111,7 +110,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Bool) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, bool_, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, bool_, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "bool");
|
||||
}
|
||||
|
@ -121,7 +121,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_F32) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, f32, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, f32, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "float");
|
||||
}
|
||||
|
@ -131,7 +132,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_I32) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, i32, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, i32, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "int");
|
||||
}
|
||||
|
@ -141,7 +143,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "float2x3");
|
||||
}
|
||||
|
@ -152,7 +155,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Pointer) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, &p, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, &p, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "float*");
|
||||
}
|
||||
|
@ -206,7 +210,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
|
|||
GeneratorImpl& gen = Build();
|
||||
|
||||
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "S");
|
||||
}
|
||||
|
@ -225,7 +230,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
|||
GeneratorImpl& gen = Build();
|
||||
|
||||
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(gen.result(), R"(struct S {
|
||||
int a;
|
||||
|
@ -280,7 +286,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_U32) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, u32, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, u32, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "uint");
|
||||
}
|
||||
|
@ -290,7 +297,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Vector) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "float3");
|
||||
}
|
||||
|
@ -300,7 +308,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Void) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, void_, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, void_, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "void");
|
||||
}
|
||||
|
@ -310,7 +319,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitSampler) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, &sampler, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, &sampler, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "SamplerState");
|
||||
}
|
||||
|
@ -320,7 +330,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitSamplerComparison) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, &sampler, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, &sampler, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "SamplerComparisonState");
|
||||
}
|
||||
|
@ -515,7 +526,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitMultisampledTexture) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(out, &s, ast::StorageClass::kNone, ""))
|
||||
ASSERT_TRUE(gen.EmitType(out, &s, ast::StorageClass::kNone,
|
||||
ast::AccessControl::kInvalid, ""))
|
||||
<< gen.error();
|
||||
EXPECT_EQ(result(), "Texture2DMS<float4>");
|
||||
}
|
||||
|
@ -536,9 +548,9 @@ TEST_P(HlslStorageTexturesTest, Emit) {
|
|||
auto params = GetParam();
|
||||
|
||||
auto t = ty.storage_texture(params.dim, params.imgfmt);
|
||||
auto ac = ty.access(params.ro ? ast::AccessControl::kReadOnly
|
||||
: ast::AccessControl::kWriteOnly,
|
||||
t);
|
||||
auto* ac = ty.access(params.ro ? ast::AccessControl::kReadOnly
|
||||
: ast::AccessControl::kWriteOnly,
|
||||
t);
|
||||
|
||||
Global("tex", ac, ast::StorageClass::kNone, nullptr,
|
||||
ast::DecorationList{
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "src/ast/uint_literal.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/ast/void.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/array.h"
|
||||
#include "src/sem/bool_type.h"
|
||||
#include "src/sem/call.h"
|
||||
|
@ -1296,18 +1295,12 @@ bool GeneratorImpl::EmitFunctionInternal(ast::Function* func,
|
|||
}
|
||||
first = false;
|
||||
|
||||
auto* ac = var->Type()->As<sem::AccessControl>();
|
||||
if (ac == nullptr) {
|
||||
diagnostics_.add_error(
|
||||
"invalid type for storage buffer, expected access control");
|
||||
return false;
|
||||
}
|
||||
if (ac->IsReadOnly()) {
|
||||
if (var->AccessControl() == ast::AccessControl::kReadOnly) {
|
||||
out_ << "const ";
|
||||
}
|
||||
|
||||
out_ << "device ";
|
||||
if (!EmitType(ac->type(), "")) {
|
||||
if (!EmitType(var->Type(), "")) {
|
||||
return false;
|
||||
}
|
||||
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
|
||||
|
@ -1524,18 +1517,12 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
|||
auto* binding = data.second.binding;
|
||||
// auto* set = data.second.set;
|
||||
|
||||
auto* ac = var->Type()->As<sem::AccessControl>();
|
||||
if (ac == nullptr) {
|
||||
diagnostics_.add_error(
|
||||
"invalid type for storage buffer, expected access control");
|
||||
return false;
|
||||
}
|
||||
if (ac->IsReadOnly()) {
|
||||
if (var->AccessControl() == ast::AccessControl::kReadOnly) {
|
||||
out_ << "const ";
|
||||
}
|
||||
|
||||
out_ << "device ";
|
||||
if (!EmitType(ac->type(), "")) {
|
||||
if (!EmitType(var->Type(), "")) {
|
||||
return false;
|
||||
}
|
||||
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol())
|
||||
|
@ -1892,20 +1879,6 @@ bool GeneratorImpl::EmitSwitch(ast::SwitchStatement* stmt) {
|
|||
}
|
||||
|
||||
bool GeneratorImpl::EmitType(const sem::Type* type, const std::string& name) {
|
||||
std::string access_str = "";
|
||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||
if (ac->access_control() == ast::AccessControl::kReadOnly) {
|
||||
access_str = "read";
|
||||
} else if (ac->access_control() == ast::AccessControl::kWriteOnly) {
|
||||
access_str = "write";
|
||||
} else {
|
||||
diagnostics_.add_error("Invalid access control for storage texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
type = ac->type();
|
||||
}
|
||||
|
||||
if (auto* ary = type->As<sem::Array>()) {
|
||||
const sem::Type* base_type = ary;
|
||||
std::vector<uint32_t> sizes;
|
||||
|
@ -1989,7 +1962,16 @@ bool GeneratorImpl::EmitType(const sem::Type* type, const std::string& name) {
|
|||
if (!EmitType(storage->type(), "")) {
|
||||
return false;
|
||||
}
|
||||
out_ << ", access::" << access_str;
|
||||
|
||||
std::string access_str;
|
||||
if (storage->access_control() == ast::AccessControl::kReadOnly) {
|
||||
out_ << ", access::read";
|
||||
} else if (storage->access_control() == ast::AccessControl::kWriteOnly) {
|
||||
out_ << ", access::write";
|
||||
} else {
|
||||
diagnostics_.add_error("Invalid access control for storage texture");
|
||||
return false;
|
||||
}
|
||||
} else if (auto* ms = tex->As<sem::MultisampledTexture>()) {
|
||||
if (!EmitType(ms->type(), "")) {
|
||||
return false;
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "src/ast/stage_decoration.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/writer/msl/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -307,7 +306,7 @@ TEST_F(MslGeneratorImplTest,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
|
||||
|
@ -352,7 +351,7 @@ TEST_F(MslGeneratorImplTest,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
|
||||
|
@ -608,7 +607,7 @@ TEST_F(MslGeneratorImplTest,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
|
||||
|
@ -664,7 +663,7 @@ TEST_F(MslGeneratorImplTest,
|
|||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
|
||||
|
@ -799,7 +798,7 @@ TEST_F(MslGeneratorImplTest,
|
|||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("data", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(0)});
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <array>
|
||||
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
@ -762,9 +761,9 @@ TEST_P(MslStorageTexturesTest, Emit) {
|
|||
auto params = GetParam();
|
||||
|
||||
auto s = ty.storage_texture(params.dim, ast::ImageFormat::kR32Float);
|
||||
auto ac = ty.access(params.ro ? ast::AccessControl::kReadOnly
|
||||
: ast::AccessControl::kWriteOnly,
|
||||
s);
|
||||
auto* ac = ty.access(params.ro ? ast::AccessControl::kReadOnly
|
||||
: ast::AccessControl::kWriteOnly,
|
||||
s);
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -773,7 +772,7 @@ TEST_P(MslStorageTexturesTest, Emit) {
|
|||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
ASSERT_TRUE(gen.EmitType(ac, "")) << gen.error();
|
||||
ASSERT_TRUE(gen.EmitType(program->TypeOf(ac), "")) << gen.error();
|
||||
EXPECT_EQ(gen.result(), params.result);
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
|
|
|
@ -728,34 +728,35 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
|||
OperandList ops = {Operand::Int(type_id), result,
|
||||
Operand::Int(ConvertStorageClass(sc))};
|
||||
|
||||
// Unwrap after emitting the access control as unwrap all removes access
|
||||
// control types.
|
||||
auto* type_no_ac = sem->Type()->UnwrapAll();
|
||||
auto* type = sem->Type();
|
||||
|
||||
if (var->has_constructor()) {
|
||||
ops.push_back(Operand::Int(init_id));
|
||||
} else if (type_no_ac->Is<sem::Texture>()) {
|
||||
if (auto* ac = sem->Type()->As<sem::AccessControl>()) {
|
||||
switch (ac->access_control()) {
|
||||
case ast::AccessControl::kWriteOnly:
|
||||
push_annot(
|
||||
spv::Op::OpDecorate,
|
||||
{Operand::Int(var_id), Operand::Int(SpvDecorationNonReadable)});
|
||||
break;
|
||||
case ast::AccessControl::kReadOnly:
|
||||
push_annot(
|
||||
spv::Op::OpDecorate,
|
||||
{Operand::Int(var_id), Operand::Int(SpvDecorationNonWritable)});
|
||||
break;
|
||||
case ast::AccessControl::kReadWrite:
|
||||
break;
|
||||
}
|
||||
} else if (sem->AccessControl() != ast::AccessControl::kInvalid) {
|
||||
// type is a sem::Struct or a sem::StorageTexture
|
||||
switch (sem->AccessControl()) {
|
||||
case ast::AccessControl::kInvalid:
|
||||
TINT_ICE(builder_.Diagnostics()) << "missing access control";
|
||||
break;
|
||||
case ast::AccessControl::kWriteOnly:
|
||||
push_annot(
|
||||
spv::Op::OpDecorate,
|
||||
{Operand::Int(var_id), Operand::Int(SpvDecorationNonReadable)});
|
||||
break;
|
||||
case ast::AccessControl::kReadOnly:
|
||||
push_annot(
|
||||
spv::Op::OpDecorate,
|
||||
{Operand::Int(var_id), Operand::Int(SpvDecorationNonWritable)});
|
||||
break;
|
||||
case ast::AccessControl::kReadWrite:
|
||||
break;
|
||||
}
|
||||
} else if (!type_no_ac->Is<sem::Sampler>()) {
|
||||
} else if (!type->Is<sem::Sampler>()) {
|
||||
// If we don't have a constructor and we're an Output or Private variable,
|
||||
// then WGSL requires that we zero-initialize.
|
||||
if (sem->StorageClass() == ast::StorageClass::kPrivate ||
|
||||
sem->StorageClass() == ast::StorageClass::kOutput) {
|
||||
init_id = GenerateConstantNullIfNeeded(type_no_ac);
|
||||
init_id = GenerateConstantNullIfNeeded(type);
|
||||
if (init_id == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -2931,12 +2932,6 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||
if (!ac->type()->UnwrapAccess()->Is<sem::Struct>()) {
|
||||
return GenerateTypeIfNeeded(ac->type());
|
||||
}
|
||||
}
|
||||
|
||||
auto val = type_name_to_id_.find(type->type_name());
|
||||
if (val != type_name_to_id_.end()) {
|
||||
return val->second;
|
||||
|
@ -2944,14 +2939,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
|
||||
auto result = result_op();
|
||||
auto id = result.to_i();
|
||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||
// The non-struct case was handled above.
|
||||
auto* subtype = ac->UnwrapAccess();
|
||||
if (!GenerateStructType(subtype->As<sem::Struct>(), ac->access_control(),
|
||||
result)) {
|
||||
return 0;
|
||||
}
|
||||
} else if (auto* arr = type->As<sem::Array>()) {
|
||||
if (auto* arr = type->As<sem::Array>()) {
|
||||
if (!GenerateArrayType(arr, result)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -2970,7 +2958,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
return 0;
|
||||
}
|
||||
} else if (auto* str = type->As<sem::Struct>()) {
|
||||
if (!GenerateStructType(str, ast::AccessControl::kReadWrite, result)) {
|
||||
if (!GenerateStructType(str, result)) {
|
||||
return 0;
|
||||
}
|
||||
} else if (type->Is<sem::U32>()) {
|
||||
|
@ -2985,6 +2973,28 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
if (!GenerateTextureType(tex, result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (auto* st = tex->As<sem::StorageTexture>()) {
|
||||
// Register all three access types of StorageTexture names. In SPIR-V, we
|
||||
// must output a single type, while the variable is annotated with the
|
||||
// access type. Doing this ensures we de-dupe.
|
||||
type_name_to_id_[builder_
|
||||
.create<sem::StorageTexture>(
|
||||
st->dim(), st->image_format(),
|
||||
ast::AccessControl::kReadOnly, st->type())
|
||||
->type_name()] = id;
|
||||
type_name_to_id_[builder_
|
||||
.create<sem::StorageTexture>(
|
||||
st->dim(), st->image_format(),
|
||||
ast::AccessControl::kWriteOnly, st->type())
|
||||
->type_name()] = id;
|
||||
type_name_to_id_[builder_
|
||||
.create<sem::StorageTexture>(
|
||||
st->dim(), st->image_format(),
|
||||
ast::AccessControl::kReadWrite, st->type())
|
||||
->type_name()] = id;
|
||||
}
|
||||
|
||||
} else if (type->Is<sem::Sampler>()) {
|
||||
push_type(spv::Op::OpTypeSampler, {result});
|
||||
|
||||
|
@ -3139,7 +3149,6 @@ bool Builder::GeneratePointerType(const sem::Pointer* ptr,
|
|||
}
|
||||
|
||||
bool Builder::GenerateStructType(const sem::Struct* struct_type,
|
||||
ast::AccessControl::Access access_control,
|
||||
const Operand& result) {
|
||||
auto struct_id = result.to_i();
|
||||
auto* impl = struct_type->Declaration();
|
||||
|
@ -3165,19 +3174,6 @@ bool Builder::GenerateStructType(const sem::Struct* struct_type,
|
|||
return false;
|
||||
}
|
||||
|
||||
// We're attaching the access control to the members of the struct instead
|
||||
// of to the variable. The reason we do this is that WGSL models the
|
||||
// access as part of the type. If we attach to the variable, it's no
|
||||
// longer part of the type in the SPIR-V backend, but part of the
|
||||
// variable. This differs from the modeling and other backends. Attaching
|
||||
// to the struct members means the access control stays part of the type
|
||||
// where it logically makes the most sense.
|
||||
if (access_control == ast::AccessControl::kReadOnly) {
|
||||
push_annot(spv::Op::OpMemberDecorate,
|
||||
{Operand::Int(struct_id), Operand::Int(i),
|
||||
Operand::Int(SpvDecorationNonWritable)});
|
||||
}
|
||||
|
||||
ops.push_back(Operand::Int(mem_id));
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/program_builder.h"
|
||||
#include "src/scope_stack.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
#include "src/writer/spirv/function.h"
|
||||
#include "src/writer/spirv/scalar_constant.h"
|
||||
|
@ -446,11 +445,9 @@ class Builder {
|
|||
bool GeneratePointerType(const sem::Pointer* ptr, const Operand& result);
|
||||
/// Generates a vector type declaration
|
||||
/// @param struct_type the vector to generate
|
||||
/// @param access_control the access controls to assign to the struct
|
||||
/// @param result the result operand
|
||||
/// @returns true if the vector was successfully generated
|
||||
bool GenerateStructType(const sem::Struct* struct_type,
|
||||
ast::AccessControl::Access access_control,
|
||||
const Operand& result);
|
||||
/// Generates a struct member
|
||||
/// @param struct_id the id of the parent structure
|
||||
|
|
|
@ -204,7 +204,7 @@ TEST_F(BuilderTest, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
|
|||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("data", ac, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
|
|
|
@ -408,7 +408,7 @@ TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
|
|||
Member("b", ty.i32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
|
||||
auto* var = Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
@ -422,9 +422,8 @@ TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
|
|||
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
|
||||
OpMemberDecorate %3 0 Offset 0
|
||||
OpMemberDecorate %3 0 NonWritable
|
||||
OpMemberDecorate %3 1 Offset 4
|
||||
OpMemberDecorate %3 1 NonWritable
|
||||
OpDecorate %1 NonWritable
|
||||
OpDecorate %1 Binding 0
|
||||
OpDecorate %1 DescriptorSet 0
|
||||
)");
|
||||
|
@ -451,7 +450,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
|
|||
{create<ast::StructBlockDecoration>()});
|
||||
auto* B = ty.alias("B", A);
|
||||
AST().AddConstructedType(B);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, B);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, B);
|
||||
auto* var = Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -464,7 +463,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
|
|||
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
|
||||
OpMemberDecorate %3 0 Offset 0
|
||||
OpMemberDecorate %3 0 NonWritable
|
||||
OpDecorate %1 NonWritable
|
||||
OpDecorate %1 Binding 0
|
||||
OpDecorate %1 DescriptorSet 0
|
||||
)");
|
||||
|
@ -488,7 +487,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
|
|||
|
||||
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
auto* B = ty.alias("B", ac);
|
||||
AST().AddConstructedType(B);
|
||||
auto* var = Global("b", B, ast::StorageClass::kStorage, nullptr,
|
||||
|
@ -503,7 +502,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
|
|||
|
||||
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
|
||||
OpMemberDecorate %3 0 Offset 0
|
||||
OpMemberDecorate %3 0 NonWritable
|
||||
OpDecorate %1 NonWritable
|
||||
OpDecorate %1 Binding 0
|
||||
OpDecorate %1 DescriptorSet 0
|
||||
)");
|
||||
|
@ -527,8 +526,8 @@ TEST_F(BuilderTest, GlobalVar_TwoVarDeclReadOnly) {
|
|||
|
||||
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto read = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
auto rw = ty.access(ast::AccessControl::kReadWrite, A);
|
||||
auto* read = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
auto* rw = ty.access(ast::AccessControl::kReadWrite, A);
|
||||
|
||||
auto* var_b = Global("b", read, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
@ -549,28 +548,22 @@ TEST_F(BuilderTest, GlobalVar_TwoVarDeclReadOnly) {
|
|||
EXPECT_EQ(DumpInstructions(b.annots()),
|
||||
R"(OpDecorate %3 Block
|
||||
OpMemberDecorate %3 0 Offset 0
|
||||
OpMemberDecorate %3 0 NonWritable
|
||||
OpDecorate %1 NonWritable
|
||||
OpDecorate %1 DescriptorSet 0
|
||||
OpDecorate %1 Binding 0
|
||||
OpDecorate %7 Block
|
||||
OpMemberDecorate %7 0 Offset 0
|
||||
OpDecorate %5 DescriptorSet 1
|
||||
OpDecorate %5 Binding 0
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
|
||||
OpMemberName %3 0 "a"
|
||||
OpName %1 "b"
|
||||
OpName %7 "A"
|
||||
OpMemberName %7 0 "a"
|
||||
OpName %5 "c"
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
|
||||
%3 = OpTypeStruct %4
|
||||
%2 = OpTypePointer StorageBuffer %3
|
||||
%1 = OpVariable %2 StorageBuffer
|
||||
%7 = OpTypeStruct %4
|
||||
%6 = OpTypePointer StorageBuffer %7
|
||||
%5 = OpVariable %6 StorageBuffer
|
||||
%5 = OpVariable %2 StorageBuffer
|
||||
)");
|
||||
}
|
||||
|
||||
|
@ -580,7 +573,7 @@ TEST_F(BuilderTest, GlobalVar_TextureStorageReadOnly) {
|
|||
auto type = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint);
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, type);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, type);
|
||||
|
||||
auto* var_a = Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -609,7 +602,7 @@ TEST_F(BuilderTest, GlobalVar_TextureStorageWriteOnly) {
|
|||
auto type = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint);
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kWriteOnly, type);
|
||||
auto* ac = ty.access(ast::AccessControl::kWriteOnly, type);
|
||||
|
||||
auto* var_a = Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -638,18 +631,18 @@ TEST_F(BuilderTest, GlobalVar_TextureStorageWithDifferentAccess) {
|
|||
// var<uniform_constant> a : [[access(read)]] texture_storage_2d<r32uint>;
|
||||
// var<uniform_constant> b : [[access(write)]] texture_storage_2d<r32uint>;
|
||||
|
||||
auto type_a = ty.access(ast::AccessControl::kReadOnly,
|
||||
ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint));
|
||||
auto* type_a = ty.access(ast::AccessControl::kReadOnly,
|
||||
ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint));
|
||||
auto* var_a = Global("a", type_a, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
create<ast::GroupDecoration>(0),
|
||||
});
|
||||
|
||||
auto type_b = ty.access(ast::AccessControl::kWriteOnly,
|
||||
ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint));
|
||||
auto* type_b = ty.access(ast::AccessControl::kWriteOnly,
|
||||
ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint));
|
||||
auto* var_b = Global("b", type_b, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(1),
|
||||
|
|
|
@ -1389,7 +1389,7 @@ OpFunctionEnd
|
|||
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
||||
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(1),
|
||||
|
@ -1439,7 +1439,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
|||
Member(4, "a", ty.array<f32>(4)),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(1),
|
||||
|
|
|
@ -30,7 +30,7 @@ TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
|||
auto* ary = ty.array(ty.i32(), 0);
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
Global("a", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -52,7 +52,7 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
|
|||
auto* ary = ty.array(ty.i32(), 0);
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
Global("a", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -822,7 +822,7 @@ TEST_F(BuilderTest_Type, SampledTexture_Generate_CubeArray) {
|
|||
TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
|
||||
auto s = ty.storage_texture(ast::TextureDimension::k1d,
|
||||
ast::ImageFormat::kR32Float);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -842,7 +842,7 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
|
|||
TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
|
||||
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Float);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -862,7 +862,7 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
|
|||
TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
|
||||
auto s = ty.storage_texture(ast::TextureDimension::k2dArray,
|
||||
ast::ImageFormat::kR32Float);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -882,7 +882,7 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
|
|||
TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
|
||||
auto s = ty.storage_texture(ast::TextureDimension::k3d,
|
||||
ast::ImageFormat::kR32Float);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -903,7 +903,7 @@ TEST_F(BuilderTest_Type,
|
|||
StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
|
||||
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Float);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -924,7 +924,7 @@ TEST_F(BuilderTest_Type,
|
|||
StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
|
||||
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Sint);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
@ -945,7 +945,7 @@ TEST_F(BuilderTest_Type,
|
|||
StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
|
||||
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Uint);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
Global("test_var", ac, ast::StorageClass::kNone, nullptr,
|
||||
{
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/ast/workgroup_decoration.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/writer/wgsl/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -204,7 +203,7 @@ TEST_F(WgslGeneratorImplTest,
|
|||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
Global("data", ac, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "src/ast/stage_decoration.h"
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
#include "src/writer/wgsl/test_helper.h"
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/multisampled_texture_type.h"
|
||||
#include "src/sem/sampled_texture_type.h"
|
||||
|
@ -50,7 +49,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
|
|||
auto* s = Structure("S", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
AST().AddConstructedType(ty.alias("make_type_reachable", a));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
@ -63,7 +62,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_ReadWrite) {
|
|||
auto* s = Structure("S", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto a = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
auto* a = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
AST().AddConstructedType(ty.alias("make_type_reachable", a));
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
@ -430,7 +429,7 @@ TEST_P(WgslGenerator_StorageTextureTest, EmitType_StorageTexture) {
|
|||
auto param = GetParam();
|
||||
|
||||
auto t = ty.storage_texture(param.dim, param.fmt);
|
||||
auto ac = ty.access(param.access, t);
|
||||
auto* ac = ty.access(param.access, t);
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
|
|
|
@ -269,7 +269,6 @@ tint_unittests_source_set("tint_unittests_core_src") {
|
|||
"../src/resolver/type_validation_test.cc",
|
||||
"../src/resolver/validation_test.cc",
|
||||
"../src/scope_stack_test.cc",
|
||||
"../src/sem/access_control_type_test.cc",
|
||||
"../src/sem/bool_type_test.cc",
|
||||
"../src/sem/depth_texture_type_test.cc",
|
||||
"../src/sem/external_texture_type_test.cc",
|
||||
|
@ -349,8 +348,8 @@ tint_unittests_source_set("tint_unittests_spv_reader_src") {
|
|||
"../src/reader/spirv/parser_impl_test_helper.cc",
|
||||
"../src/reader/spirv/parser_impl_test_helper.h",
|
||||
"../src/reader/spirv/parser_impl_user_name_test.cc",
|
||||
"../src/reader/spirv/parser_type_test.cc",
|
||||
"../src/reader/spirv/parser_test.cc",
|
||||
"../src/reader/spirv/parser_type_test.cc",
|
||||
"../src/reader/spirv/spirv_tools_helpers_test.cc",
|
||||
"../src/reader/spirv/spirv_tools_helpers_test.h",
|
||||
"../src/reader/spirv/usage_test.cc",
|
||||
|
|
Loading…
Reference in New Issue