Implement Default Struct Layout

Implements https://github.com/gpuweb/gpuweb/pull/1447

SPIR-V Reader is still TODO, but continues to function as the offset
decoration is still supported.

Bug: tint:626
Bug: tint:629
Change-Id: Id574eb3a5c6729559382812de37b23f0c68fd406
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/43640
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
Ben Clayton
2021-03-15 10:43:11 +00:00
committed by Commit Bot service account
parent 717fbbf183
commit d614dd5d12
107 changed files with 2401 additions and 2038 deletions

View File

@@ -65,14 +65,6 @@ std::string AccessControl::FriendlyName(const SymbolTable& symbols) const {
return out.str();
}
uint64_t AccessControl::MinBufferBindingSize(MemoryLayout mem_layout) const {
return subtype_->MinBufferBindingSize(mem_layout);
}
uint64_t AccessControl::BaseAlignment(MemoryLayout mem_layout) const {
return subtype_->BaseAlignment(mem_layout);
}
AccessControl* AccessControl::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto* ty = ctx->Clone(type());

View File

@@ -54,16 +54,6 @@ class AccessControl : public Castable<AccessControl, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -95,70 +95,6 @@ TEST_F(AccessControlTest, FriendlyNameReadWrite) {
EXPECT_EQ(at.FriendlyName(Symbols()), "[[access(read_write)]] i32");
}
TEST_F(AccessControlTest, MinBufferBindingSizeU32) {
U32 u32;
AccessControl at{ast::AccessControl::kReadOnly, &u32};
EXPECT_EQ(4u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTest, MinBufferBindingSizeArray) {
U32 u32;
Array array(&u32, 4, ast::DecorationList{create<ast::StrideDecoration>(4)});
AccessControl at{ast::AccessControl::kReadOnly, &array};
EXPECT_EQ(16u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTest, MinBufferBindingSizeRuntimeArray) {
U32 u32;
Array array(&u32, 0, ast::DecorationList{create<ast::StrideDecoration>(4)});
AccessControl at{ast::AccessControl::kReadOnly, &array};
EXPECT_EQ(4u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTest, MinBufferBindingSizeStruct) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)})},
ast::DecorationList{});
auto* struct_type = ty.struct_("struct_type", str);
AccessControl at{ast::AccessControl::kReadOnly, struct_type};
EXPECT_EQ(16u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, at.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(AccessControlTest, BaseAlignmentU32) {
U32 u32;
AccessControl at{ast::AccessControl::kReadOnly, &u32};
EXPECT_EQ(4u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTest, BaseAlignmentArray) {
U32 u32;
Array array(&u32, 4, ast::DecorationList{create<ast::StrideDecoration>(4)});
AccessControl at{ast::AccessControl::kReadOnly, &array};
EXPECT_EQ(16u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTest, BaseAlignmentRuntimeArray) {
U32 u32;
Array array(&u32, 0, ast::DecorationList{create<ast::StrideDecoration>(4)});
AccessControl at{ast::AccessControl::kReadOnly, &array};
EXPECT_EQ(16u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTest, BaseAlignmentStruct) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)})},
ast::DecorationList{});
auto* struct_type = ty.struct_("struct_type", str);
AccessControl at{ast::AccessControl::kReadOnly, struct_type};
EXPECT_EQ(16u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, at.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -38,14 +38,6 @@ std::string Alias::FriendlyName(const SymbolTable& symbols) const {
return symbols.NameFor(symbol_);
}
uint64_t Alias::MinBufferBindingSize(MemoryLayout mem_layout) const {
return subtype_->MinBufferBindingSize(mem_layout);
}
uint64_t Alias::BaseAlignment(MemoryLayout mem_layout) const {
return subtype_->BaseAlignment(mem_layout);
}
Alias* Alias::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto sym = ctx->Clone(symbol());

View File

@@ -47,16 +47,6 @@ class Alias : public Castable<Alias, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -137,76 +137,6 @@ TEST_F(AliasTest, UnwrapAll_PointerAccessControl) {
EXPECT_EQ(a.UnwrapAll(), ty.u32());
}
TEST_F(AliasTest, MinBufferBindingSizeU32) {
auto* alias = ty.alias("alias", ty.u32());
EXPECT_EQ(4u, alias->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTest, MinBufferBindingSizeArray) {
Array array(ty.u32(), 4,
ast::DecorationList{
create<ast::StrideDecoration>(4),
});
auto* alias = ty.alias("alias", &array);
EXPECT_EQ(16u, alias->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTest, MinBufferBindingSizeRuntimeArray) {
Array array(ty.u32(), 0,
ast::DecorationList{
create<ast::StrideDecoration>(4),
});
auto* alias = ty.alias("alias", &array);
EXPECT_EQ(4u, alias->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTest, MinBufferBindingSizeStruct) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)})},
ast::DecorationList{});
auto* struct_type = ty.struct_("struct_type", str);
auto* alias = ty.alias("alias", struct_type);
EXPECT_EQ(16u, alias->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, alias->MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(AliasTest, BaseAlignmentU32) {
auto* alias = ty.alias("alias", ty.u32());
EXPECT_EQ(4u, alias->BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTest, BaseAlignmentArray) {
Array array(ty.u32(), 4,
ast::DecorationList{
create<ast::StrideDecoration>(4),
});
auto* alias = ty.alias("alias", &array);
EXPECT_EQ(16u, alias->BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTest, BaseAlignmentRuntimeArray) {
Array array(ty.u32(), 0,
ast::DecorationList{
create<ast::StrideDecoration>(4),
});
auto* alias = ty.alias("alias", &array);
EXPECT_EQ(16u, alias->BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTest, BaseAlignmentStruct) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)})},
ast::DecorationList{});
auto* struct_type = ty.struct_("struct_type", str);
auto* alias = ty.alias("alias", struct_type);
EXPECT_EQ(16u, alias->BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, alias->BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(AliasTest, UnwrapAliasIfNeeded) {
auto* alias1 = ty.alias("alias1", ty.f32());
auto* alias2 = ty.alias("alias2", alias1);

View File

@@ -30,71 +30,28 @@ Array::Array(Array&&) = default;
Array::~Array() = default;
uint64_t Array::MinBufferBindingSize(MemoryLayout mem_layout) const {
if (!has_array_stride()) {
// Arrays in buffers are required to have a stride.
return 0;
}
if (IsRuntimeArray()) {
// WebGPU spec 10.1.2:
// If the last field of the corresponding structure defined in the shader
// has an unbounded array type, then the value of minBufferBindingSize must
// be greater than or equal to the byte offset of that field plus the stride
// of the unbounded array
return array_stride();
} else {
// Not including the padding for the last element
return (size_ - 1) * array_stride() +
subtype_->MinBufferBindingSize(mem_layout);
}
}
uint64_t Array::BaseAlignment(MemoryLayout mem_layout) const {
if (mem_layout == MemoryLayout::kUniformBuffer) {
float aligment = 16; // for a vec4
float unaligned = static_cast<float>(subtype_->BaseAlignment(mem_layout));
return static_cast<uint64_t>(aligment * std::ceil(unaligned / aligment));
} else if (mem_layout == MemoryLayout::kStorageBuffer) {
return subtype_->BaseAlignment(mem_layout);
}
return 0;
}
uint32_t Array::array_stride() const {
for (auto* deco : decos_) {
if (auto* stride = deco->As<ast::StrideDecoration>()) {
return stride->stride();
}
}
return 0;
}
bool Array::has_array_stride() const {
for (auto* deco : decos_) {
if (deco->Is<ast::StrideDecoration>()) {
return true;
}
}
return false;
}
std::string Array::type_name() const {
assert(subtype_);
std::string type_name = "__array" + subtype_->type_name();
if (!IsRuntimeArray())
if (!IsRuntimeArray()) {
type_name += "_" + std::to_string(size_);
if (has_array_stride())
type_name += "_stride_" + std::to_string(array_stride());
}
for (auto* deco : decos_) {
if (auto* stride = deco->As<ast::StrideDecoration>()) {
type_name += "_stride_" + std::to_string(stride->stride());
}
}
return type_name;
}
std::string Array::FriendlyName(const SymbolTable& symbols) const {
std::ostringstream out;
if (has_array_stride()) {
out << "[[stride(" << array_stride() << ")]] ";
for (auto* deco : decos_) {
if (auto* stride = deco->As<ast::StrideDecoration>()) {
out << "[[stride(" << stride->stride() << ")]] ";
}
}
out << "array<" << subtype_->FriendlyName(symbols);
if (!IsRuntimeArray()) {

View File

@@ -40,24 +40,9 @@ class Array : public Castable<Array, Type> {
/// i.e. the size is determined at runtime
bool IsRuntimeArray() const { return size_ == 0; }
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// @returns the array decorations
const ast::DecorationList& decorations() const { return decos_; }
/// @returns the array stride or 0 if none set.
uint32_t array_stride() const;
/// @returns true if the array has a stride set
bool has_array_stride() const;
/// @returns the array type
Type* type() const { return subtype_; }
/// @returns the array size. Size is 0 for a runtime array

View File

@@ -94,38 +94,6 @@ TEST_F(ArrayTest, TypeName_WithStride) {
EXPECT_EQ(arr.type_name(), "__array__i32_3_stride_16");
}
TEST_F(ArrayTest, MinBufferBindingSizeNoStride) {
U32 u32;
Array arr(&u32, 4, ast::DecorationList{});
EXPECT_EQ(0u, arr.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(ArrayTest, MinBufferBindingSizeArray) {
U32 u32;
Array arr(&u32, 4, ast::DecorationList{create<ast::StrideDecoration>(4)});
EXPECT_EQ(16u, arr.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(ArrayTest, MinBufferBindingSizeRuntimeArray) {
U32 u32;
Array arr(&u32, 0, ast::DecorationList{create<ast::StrideDecoration>(4)});
EXPECT_EQ(4u, arr.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(ArrayTest, BaseAlignmentArray) {
U32 u32;
Array arr(&u32, 4, ast::DecorationList{create<ast::StrideDecoration>(4)});
EXPECT_EQ(16u, arr.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, arr.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(ArrayTest, BaseAlignmentRuntimeArray) {
U32 u32;
Array arr(&u32, 0, ast::DecorationList{create<ast::StrideDecoration>(4)});
EXPECT_EQ(16u, arr.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, arr.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -50,11 +50,6 @@ TEST_F(BoolTest, FriendlyName) {
EXPECT_EQ(b.FriendlyName(Symbols()), "bool");
}
TEST_F(BoolTest, MinBufferBindingSize) {
Bool b;
EXPECT_EQ(0u, b.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -67,11 +67,6 @@ TEST_F(DepthTextureTest, FriendlyName) {
EXPECT_EQ(d.FriendlyName(Symbols()), "texture_depth_cube");
}
TEST_F(DepthTextureTest, MinBufferBindingSize) {
DepthTexture d(TextureDimension::kCube);
EXPECT_EQ(0u, d.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -35,14 +35,6 @@ std::string F32::FriendlyName(const SymbolTable&) const {
return "f32";
}
uint64_t F32::MinBufferBindingSize(MemoryLayout) const {
return 4;
}
uint64_t F32::BaseAlignment(MemoryLayout) const {
return 4;
}
F32* F32::Clone(CloneContext* ctx) const {
return ctx->dst->create<F32>();
}

View File

@@ -39,16 +39,6 @@ class F32 : public Castable<F32, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -50,16 +50,6 @@ TEST_F(F32Test, FriendlyName) {
EXPECT_EQ(f.FriendlyName(Symbols()), "f32");
}
TEST_F(F32Test, MinBufferBindingSize) {
F32 f;
EXPECT_EQ(4u, f.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(F32Test, BaseAlignment) {
F32 f;
EXPECT_EQ(4u, f.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -35,14 +35,6 @@ std::string I32::FriendlyName(const SymbolTable&) const {
return "i32";
}
uint64_t I32::MinBufferBindingSize(MemoryLayout) const {
return 4;
}
uint64_t I32::BaseAlignment(MemoryLayout) const {
return 4;
}
I32* I32::Clone(CloneContext* ctx) const {
return ctx->dst->create<I32>();
}

View File

@@ -39,16 +39,6 @@ class I32 : public Castable<I32, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -50,16 +50,6 @@ TEST_F(I32Test, FriendlyName) {
EXPECT_EQ(i.FriendlyName(Symbols()), "i32");
}
TEST_F(I32Test, MinBufferBindingSize) {
I32 i;
EXPECT_EQ(4u, i.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(I32Test, BaseAlignment) {
I32 i;
EXPECT_EQ(4u, i.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -45,18 +45,6 @@ std::string Matrix::FriendlyName(const SymbolTable& symbols) const {
return out.str();
}
uint64_t Matrix::MinBufferBindingSize(MemoryLayout mem_layout) const {
Vector vec(subtype_, rows_);
return (columns_ - 1) * vec.BaseAlignment(mem_layout) +
vec.MinBufferBindingSize(mem_layout);
}
uint64_t Matrix::BaseAlignment(MemoryLayout mem_layout) const {
Vector vec(subtype_, rows_);
Array arr(&vec, columns_, ast::DecorationList{});
return arr.BaseAlignment(mem_layout);
}
Matrix* Matrix::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto* ty = ctx->Clone(type());

View File

@@ -49,16 +49,6 @@ class Matrix : public Castable<Matrix, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -60,62 +60,6 @@ TEST_F(MatrixTest, FriendlyName) {
EXPECT_EQ(m.FriendlyName(Symbols()), "mat2x3<i32>");
}
TEST_F(MatrixTest, MinBufferBindingSize4x2) {
I32 i32;
Matrix m{&i32, 4, 2};
EXPECT_EQ(32u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(32u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTest, MinBufferBindingSize3x2) {
I32 i32;
Matrix m{&i32, 3, 2};
EXPECT_EQ(28u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(28u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTest, MinBufferBindingSize2x3) {
I32 i32;
Matrix m{&i32, 2, 3};
EXPECT_EQ(24u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(24u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTest, MinBufferBindingSize2x2) {
I32 i32;
Matrix m{&i32, 2, 2};
EXPECT_EQ(16u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTest, BaseAlignment4x2) {
I32 i32;
Matrix m{&i32, 4, 2};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTest, BaseAlignment3x2) {
I32 i32;
Matrix m{&i32, 3, 2};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTest, BaseAlignment2x3) {
I32 i32;
Matrix m{&i32, 2, 3};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTest, BaseAlignment2x2) {
I32 i32;
Matrix m{&i32, 2, 2};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -78,12 +78,6 @@ TEST_F(MultisampledTextureTest, FriendlyName) {
EXPECT_EQ(s.FriendlyName(Symbols()), "texture_multisampled_3d<f32>");
}
TEST_F(MultisampledTextureTest, MinBufferBindingSize) {
F32 f32;
MultisampledTexture s(TextureDimension::k3d, &f32);
EXPECT_EQ(0u, s.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -76,12 +76,6 @@ TEST_F(SampledTextureTest, FriendlyName) {
EXPECT_EQ(s.FriendlyName(Symbols()), "texture_3d<f32>");
}
TEST_F(SampledTextureTest, MinBufferBindingSize) {
F32 f32;
SampledTexture s(TextureDimension::kCube, &f32);
EXPECT_EQ(0u, s.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -71,11 +71,6 @@ TEST_F(SamplerTest, FriendlyNameComparisonSampler) {
EXPECT_EQ(s.FriendlyName(Symbols()), "sampler_comparison");
}
TEST_F(SamplerTest, MinBufferBindingSize) {
Sampler s{SamplerKind::kSampler};
EXPECT_EQ(0u, s.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -132,13 +132,6 @@ TEST_F(StorageTextureTest, I32) {
EXPECT_TRUE(s->As<StorageTexture>()->type()->Is<I32>());
}
TEST_F(StorageTextureTest, MinBufferBindingSize) {
auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Sint, Types());
auto* s = create<StorageTexture>(TextureDimension::k2dArray,
ImageFormat::kRgba32Sint, subtype);
EXPECT_EQ(0u, s->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -38,48 +38,6 @@ std::string Struct::FriendlyName(const SymbolTable& symbols) const {
return symbols.NameFor(symbol_);
}
uint64_t Struct::MinBufferBindingSize(MemoryLayout mem_layout) const {
if (!struct_->members().size()) {
return 0;
}
auto* last_member = struct_->members().back();
// If there is no offset, then this is not a host-shareable struct, returning
// 0 indicates this to the caller.
if (!last_member->has_offset_decoration()) {
return 0;
}
uint64_t size = last_member->type()->MinBufferBindingSize(mem_layout);
if (!size) {
return 0;
}
float unaligned = static_cast<float>(last_member->offset() + size);
float alignment = static_cast<float>(BaseAlignment(mem_layout));
return static_cast<uint64_t>(alignment * std::ceil(unaligned / alignment));
}
uint64_t Struct::BaseAlignment(MemoryLayout mem_layout) const {
uint64_t max = 0;
for (auto* member : struct_->members()) {
if (member->type()->BaseAlignment(mem_layout) > max) {
max = member->type()->BaseAlignment(mem_layout);
}
}
if (mem_layout == MemoryLayout::kUniformBuffer) {
// Round up to a vec4.
return static_cast<uint64_t>(16 *
std::ceil(static_cast<float>(max) / 16.0f));
} else if (mem_layout == MemoryLayout::kStorageBuffer) {
return max;
}
return 0;
}
Struct* Struct::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto sym = ctx->Clone(symbol());

View File

@@ -51,16 +51,6 @@ class Struct : public Castable<Struct, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -64,140 +64,6 @@ TEST_F(StructTypeTest, FriendlyName) {
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
}
TEST_F(StructTypeTest, MinBufferBindingSize) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, s_ty->MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeArray) {
Array arr(ty.u32(), 4, ast::DecorationList{create<ast::StrideDecoration>(4)});
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)}),
Member("bar", &arr, {MemberOffset(8)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(32u, s_ty->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(24u, s_ty->MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeRuntimeArray) {
Array arr(ty.u32(), 0, ast::DecorationList{create<ast::StrideDecoration>(4)});
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)}),
Member("bar", ty.u32(), {MemberOffset(8)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(12u, s_ty->MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeVec2) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.vec2<u32>(), {MemberOffset(0)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, s_ty->MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeVec3) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.vec3<u32>(), {MemberOffset(0)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, s_ty->MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeVec4) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.vec4<u32>(), {MemberOffset(0)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, s_ty->MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignment) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(8)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, s_ty->BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentArray) {
Array arr(ty.u32(), 4, ast::DecorationList{create<ast::StrideDecoration>(4)});
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)}),
Member("bar", &arr, {MemberOffset(8)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, s_ty->BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentRuntimeArray) {
Array arr(ty.u32(), 0, ast::DecorationList{create<ast::StrideDecoration>(4)});
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.u32(), {MemberOffset(0)}),
Member("bar", ty.u32(), {MemberOffset(4)}),
Member("bar", ty.u32(), {MemberOffset(8)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(4u, s_ty->BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentVec2) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.vec2<u32>(), {MemberOffset(0)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, s_ty->BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentVec3) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.vec3<u32>(), {MemberOffset(0)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, s_ty->BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentVec4) {
auto* str = create<ast::Struct>(
ast::StructMemberList{Member("foo", ty.vec4<u32>(), {MemberOffset(0)})},
ast::DecorationList{});
auto* s_ty = ty.struct_("s_ty", str);
EXPECT_EQ(16u, s_ty->BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, s_ty->BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -70,14 +70,6 @@ Type* Type::UnwrapAll() {
return UnwrapIfNeeded()->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
}
uint64_t Type::MinBufferBindingSize(MemoryLayout) const {
return 0;
}
uint64_t Type::BaseAlignment(MemoryLayout) const {
return 0;
}
bool Type::is_scalar() const {
return is_float_scalar() || is_integer_scalar() || Is<Bool>();
}

View File

@@ -45,16 +45,6 @@ class Type : public Castable<Type, Cloneable> {
/// declared in WGSL.
virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
virtual uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
virtual uint64_t BaseAlignment(MemoryLayout mem_layout) const;
/// @returns the pointee type if this is a pointer, `this` otherwise
Type* UnwrapPtrIfNeeded();

View File

@@ -35,14 +35,6 @@ std::string U32::FriendlyName(const SymbolTable&) const {
return "u32";
}
uint64_t U32::MinBufferBindingSize(MemoryLayout) const {
return 4;
}
uint64_t U32::BaseAlignment(MemoryLayout) const {
return 4;
}
U32* U32::Clone(CloneContext* ctx) const {
return ctx->dst->create<U32>();
}

View File

@@ -39,16 +39,6 @@ class U32 : public Castable<U32, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -50,16 +50,6 @@ TEST_F(U32Test, FriendlyName) {
EXPECT_EQ(u.FriendlyName(Symbols()), "u32");
}
TEST_F(U32Test, MinBufferBindingSize) {
U32 u;
EXPECT_EQ(4u, u.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(U32Test, BaseAlignment) {
U32 u;
EXPECT_EQ(4u, u.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint

View File

@@ -40,20 +40,6 @@ std::string Vector::FriendlyName(const SymbolTable& symbols) const {
return out.str();
}
uint64_t Vector::MinBufferBindingSize(MemoryLayout mem_layout) const {
return size_ * subtype_->MinBufferBindingSize(mem_layout);
}
uint64_t Vector::BaseAlignment(MemoryLayout mem_layout) const {
if (size_ == 2) {
return 2 * subtype_->BaseAlignment(mem_layout);
} else if (size_ == 3 || size_ == 4) {
return 4 * subtype_->BaseAlignment(mem_layout);
}
return 0; // vectors are only supposed to have 2, 3, or 4 elements.
}
Vector* Vector::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto* ty = ctx->Clone(type());

View File

@@ -46,16 +46,6 @@ class Vector : public Castable<Vector, Type> {
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize(MemoryLayout mem_layout) const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns base alignment for the type, in bytes.
/// 0 for non-host shareable types.
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type

View File

@@ -59,42 +59,6 @@ TEST_F(VectorTest, FriendlyName) {
EXPECT_EQ(v->FriendlyName(Symbols()), "vec3<f32>");
}
TEST_F(VectorTest, MinBufferBindingSizeVec2) {
I32 i32;
Vector v{&i32, 2};
EXPECT_EQ(8u, v.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTest, MinBufferBindingSizeVec3) {
I32 i32;
Vector v{&i32, 3};
EXPECT_EQ(12u, v.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTest, MinBufferBindingSizeVec4) {
I32 i32;
Vector v{&i32, 4};
EXPECT_EQ(16u, v.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTest, BaseAlignmentVec2) {
I32 i32;
Vector v{&i32, 2};
EXPECT_EQ(8u, v.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTest, BaseAlignmentVec3) {
I32 i32;
Vector v{&i32, 3};
EXPECT_EQ(16u, v.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTest, BaseAlignmentVec4) {
I32 i32;
Vector v{&i32, 4};
EXPECT_EQ(16u, v.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace
} // namespace type
} // namespace tint