Add tests for MinBufferBindingSize

BUG=tint:283

Change-Id: Id198175d232680ca89e04561b8b7510f41d982f7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31106
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ryan Harrison 2020-11-03 16:53:59 +00:00 committed by Commit Bot service account
parent d5fd7e02ba
commit a28d19b18d
39 changed files with 966 additions and 49 deletions

View File

@ -48,8 +48,13 @@ std::string AccessControlType::type_name() const {
return name + subtype_->type_name(); return name + subtype_->type_name();
} }
uint64_t AccessControlType::MinBufferBindingSize() const { uint64_t AccessControlType::MinBufferBindingSize(
return subtype_->MinBufferBindingSize(); MemoryLayout mem_layout) const {
return subtype_->MinBufferBindingSize(mem_layout);
}
uint64_t AccessControlType::BaseAlignment(MemoryLayout mem_layout) const {
return subtype_->BaseAlignment(mem_layout);
} }
} // namespace type } // namespace type

View File

@ -53,9 +53,15 @@ class AccessControlType : public Type {
/// @returns the name for this type /// @returns the name for this type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
private: private:
AccessControl access_ = AccessControl::kReadOnly; AccessControl access_ = AccessControl::kReadOnly;

View File

@ -16,8 +16,14 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/storage_class.h" #include "src/ast/storage_class.h"
#include "src/ast/stride_decoration.h"
#include "src/ast/struct_member.h"
#include "src/ast/struct_member_decoration.h"
#include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/i32_type.h" #include "src/ast/type/i32_type.h"
#include "src/ast/type/pointer_type.h" #include "src/ast/type/pointer_type.h"
#include "src/ast/type/struct_type.h"
#include "src/ast/type/u32_type.h" #include "src/ast/type/u32_type.h"
namespace tint { namespace tint {
@ -83,6 +89,108 @@ TEST_F(AccessControlTypeTest, AccessReadWrite) {
EXPECT_EQ(at.type_name(), "__access_control_read_write__i32"); EXPECT_EQ(at.type_name(), "__access_control_read_write__i32");
} }
TEST_F(AccessControlTypeTest, MinBufferBindingSizeU32) {
U32Type u32;
AccessControlType at{AccessControl::kReadOnly, &u32};
EXPECT_EQ(4u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTypeTest, MinBufferBindingSizeArray) {
U32Type u32;
ArrayType array(&u32, 4);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AccessControlType at{AccessControl::kReadOnly, &array};
EXPECT_EQ(16u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTypeTest, MinBufferBindingSizeRuntimeArray) {
U32Type u32;
ArrayType array(&u32);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AccessControlType at{AccessControl::kReadOnly, &array};
EXPECT_EQ(4u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTypeTest, MinBufferBindingSizeStruct) {
U32Type u32;
StructMemberList members;
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
deco = StructMemberDecorationList();
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
AccessControlType at{AccessControl::kReadOnly, &struct_type};
EXPECT_EQ(16u, at.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, at.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(AccessControlTypeTest, BaseAlignmentU32) {
U32Type u32;
AccessControlType at{AccessControl::kReadOnly, &u32};
EXPECT_EQ(4u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTypeTest, BaseAlignmentArray) {
U32Type u32;
ArrayType array(&u32, 4);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AccessControlType at{AccessControl::kReadOnly, &array};
EXPECT_EQ(16u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTypeTest, BaseAlignmentRuntimeArray) {
U32Type u32;
ArrayType array(&u32);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AccessControlType at{AccessControl::kReadOnly, &array};
EXPECT_EQ(16u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AccessControlTypeTest, BaseAlignmentStruct) {
U32Type u32;
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
AccessControlType at{AccessControl::kReadOnly, &struct_type};
EXPECT_EQ(16u, at.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, at.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -35,8 +35,12 @@ std::string AliasType::type_name() const {
return "__alias_" + name_ + subtype_->type_name(); return "__alias_" + name_ + subtype_->type_name();
} }
uint64_t AliasType::MinBufferBindingSize() const { uint64_t AliasType::MinBufferBindingSize(MemoryLayout mem_layout) const {
return subtype_->MinBufferBindingSize(); return subtype_->MinBufferBindingSize(mem_layout);
}
uint64_t AliasType::BaseAlignment(MemoryLayout mem_layout) const {
return subtype_->BaseAlignment(mem_layout);
} }
} // namespace type } // namespace type

View File

@ -45,9 +45,15 @@ class AliasType : public Type {
/// @returns the name for this type /// @returns the name for this type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
private: private:
std::string name_; std::string name_;

View File

@ -16,9 +16,15 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/storage_class.h" #include "src/ast/storage_class.h"
#include "src/ast/stride_decoration.h"
#include "src/ast/struct_member.h"
#include "src/ast/struct_member_decoration.h"
#include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/type/access_control_type.h" #include "src/ast/type/access_control_type.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/i32_type.h" #include "src/ast/type/i32_type.h"
#include "src/ast/type/pointer_type.h" #include "src/ast/type/pointer_type.h"
#include "src/ast/type/struct_type.h"
#include "src/ast/type/u32_type.h" #include "src/ast/type/u32_type.h"
namespace tint { namespace tint {
@ -146,6 +152,110 @@ TEST_F(AliasTypeTest, UnwrapAll_PointerAccessControl) {
EXPECT_EQ(u32.UnwrapAll(), &u32); EXPECT_EQ(u32.UnwrapAll(), &u32);
} }
TEST_F(AliasTypeTest, MinBufferBindingSizeU32) {
U32Type u32;
AliasType alias{"alias", &u32};
EXPECT_EQ(4u, alias.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTypeTest, MinBufferBindingSizeArray) {
U32Type u32;
ArrayType array(&u32, 4);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AliasType alias{"alias", &array};
EXPECT_EQ(16u, alias.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTypeTest, MinBufferBindingSizeRuntimeArray) {
U32Type u32;
ArrayType array(&u32);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AliasType alias{"alias", &array};
EXPECT_EQ(4u, alias.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTypeTest, MinBufferBindingSizeStruct) {
U32Type u32;
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
AliasType alias{"alias", &struct_type};
EXPECT_EQ(16u, alias.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, alias.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(AliasTypeTest, BaseAlignmentU32) {
U32Type u32;
AliasType alias{"alias", &u32};
EXPECT_EQ(4u, alias.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTypeTest, BaseAlignmentArray) {
U32Type u32;
ArrayType array(&u32, 4);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AliasType alias{"alias", &array};
EXPECT_EQ(16u, alias.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTypeTest, BaseAlignmentRuntimeArray) {
U32Type u32;
ArrayType array(&u32);
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
array.set_decorations(std::move(decos));
AliasType alias{"alias", &array};
EXPECT_EQ(16u, alias.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(AliasTypeTest, BaseAlignmentStruct) {
U32Type u32;
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
AliasType alias{"alias", &struct_type};
EXPECT_EQ(16u, alias.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, alias.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -14,7 +14,10 @@
#include "src/ast/type/array_type.h" #include "src/ast/type/array_type.h"
#include <cmath>
#include "src/ast/stride_decoration.h" #include "src/ast/stride_decoration.h"
#include "src/ast/type/vector_type.h"
namespace tint { namespace tint {
namespace ast { namespace ast {
@ -33,16 +36,35 @@ bool ArrayType::IsArray() const {
return true; return true;
} }
uint64_t ArrayType::MinBufferBindingSize() const { uint64_t ArrayType::MinBufferBindingSize(MemoryLayout mem_layout) const {
// RTAs have a size_ = 0, but the value that is wanted from this call is the if (!has_array_stride()) {
// minimum size, so assuming atleast 1 element in the RTA. // Arrays in buffers are required to have a stride.
uint32_t size = IsRuntimeArray() ? 1 : size_; return 0;
if (has_array_stride()) {
return size * array_stride();
} }
return size * type()->MinBufferBindingSize(); 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 ArrayType::BaseAlignment(MemoryLayout mem_layout) const {
if (mem_layout == MemoryLayout::kUniformBuffer) {
float aligment = 16; // for a vec4
float unaligned = subtype_->BaseAlignment(mem_layout);
return aligment * std::ceil(unaligned / aligment);
} else if (mem_layout == MemoryLayout::kStorageBuffer) {
return subtype_->BaseAlignment(mem_layout);
}
return 0;
} }
uint32_t ArrayType::array_stride() const { uint32_t ArrayType::array_stride() const {

View File

@ -47,9 +47,15 @@ class ArrayType : public Type {
/// i.e. the size is determined at runtime /// i.e. the size is determined at runtime
bool IsRuntimeArray() const { return size_ == 0; } 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. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
/// Sets the array decorations /// Sets the array decorations
/// @param decos the decorations to set /// @param decos the decorations to set

View File

@ -88,6 +88,54 @@ TEST_F(ArrayTypeTest, TypeName_WithStride) {
EXPECT_EQ(arr.type_name(), "__array__i32_3_stride_16"); EXPECT_EQ(arr.type_name(), "__array__i32_3_stride_16");
} }
TEST_F(ArrayTypeTest, MinBufferBindingSizeNoStride) {
U32Type u32;
ArrayType arr(&u32, 4);
EXPECT_EQ(0u, arr.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(ArrayTypeTest, MinBufferBindingSizeArray) {
U32Type u32;
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
ArrayType arr(&u32, 4);
arr.set_decorations(std::move(decos));
EXPECT_EQ(16u, arr.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(ArrayTypeTest, MinBufferBindingSizeRuntimeArray) {
U32Type u32;
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
ArrayType arr(&u32);
arr.set_decorations(std::move(decos));
EXPECT_EQ(4u, arr.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(ArrayTypeTest, BaseAlignmentArray) {
U32Type u32;
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
ArrayType arr(&u32, 4);
arr.set_decorations(std::move(decos));
EXPECT_EQ(16u, arr.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, arr.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(ArrayTypeTest, BaseAlignmentRuntimeArray) {
U32Type u32;
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
ArrayType arr(&u32);
arr.set_decorations(std::move(decos));
EXPECT_EQ(16u, arr.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, arr.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -45,6 +45,11 @@ TEST_F(BoolTypeTest, TypeName) {
EXPECT_EQ(b.type_name(), "__bool"); EXPECT_EQ(b.type_name(), "__bool");
} }
TEST_F(BoolTypeTest, MinBufferBindingSize) {
BoolType b;
EXPECT_EQ(0u, b.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -57,6 +57,11 @@ TEST_F(DepthTextureTypeTest, TypeName) {
EXPECT_EQ(d.type_name(), "__depth_texture_cube"); EXPECT_EQ(d.type_name(), "__depth_texture_cube");
} }
TEST_F(DepthTextureTypeTest, MinBufferBindingSize) {
DepthTextureType d(TextureDimension::kCube);
EXPECT_EQ(0u, d.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -30,7 +30,11 @@ std::string F32Type::type_name() const {
return "__f32"; return "__f32";
} }
uint64_t F32Type::MinBufferBindingSize() const { uint64_t F32Type::MinBufferBindingSize(MemoryLayout) const {
return 4;
}
uint64_t F32Type::BaseAlignment(MemoryLayout) const {
return 4; return 4;
} }

View File

@ -38,9 +38,15 @@ class F32Type : public Type {
/// @returns the name for this type /// @returns the name for this type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
}; };
} // namespace type } // namespace type

View File

@ -45,6 +45,16 @@ TEST_F(F32TypeTest, TypeName) {
EXPECT_EQ(f.type_name(), "__f32"); EXPECT_EQ(f.type_name(), "__f32");
} }
TEST_F(F32TypeTest, MinBufferBindingSize) {
F32Type f;
EXPECT_EQ(4u, f.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(F32TypeTest, BaseAlignment) {
F32Type f;
EXPECT_EQ(4u, f.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -30,7 +30,11 @@ std::string I32Type::type_name() const {
return "__i32"; return "__i32";
} }
uint64_t I32Type::MinBufferBindingSize() const { uint64_t I32Type::MinBufferBindingSize(MemoryLayout mem_layout) const {
return 4;
}
uint64_t I32Type::BaseAlignment(MemoryLayout mem_layout) const {
return 4; return 4;
} }

View File

@ -38,9 +38,15 @@ class I32Type : public Type {
/// @returns the name for this type /// @returns the name for this type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
}; };
} // namespace type } // namespace type

View File

@ -45,6 +45,16 @@ TEST_F(I32TypeTest, TypeName) {
EXPECT_EQ(i.type_name(), "__i32"); EXPECT_EQ(i.type_name(), "__i32");
} }
TEST_F(I32TypeTest, MinBufferBindingSize) {
I32Type i;
EXPECT_EQ(4u, i.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(I32TypeTest, BaseAlignment) {
I32Type i;
EXPECT_EQ(4u, i.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -16,6 +16,9 @@
#include <assert.h> #include <assert.h>
#include "src/ast/type/array_type.h"
#include "src/ast/type/vector_type.h"
namespace tint { namespace tint {
namespace ast { namespace ast {
namespace type { namespace type {
@ -39,8 +42,16 @@ std::string MatrixType::type_name() const {
subtype_->type_name(); subtype_->type_name();
} }
uint64_t MatrixType::MinBufferBindingSize() const { uint64_t MatrixType::MinBufferBindingSize(MemoryLayout mem_layout) const {
return rows_ * columns_ * subtype_->MinBufferBindingSize(); VectorType vec(subtype_, rows_);
return (columns_ - 1) * vec.BaseAlignment(mem_layout) +
vec.MinBufferBindingSize(mem_layout);
}
uint64_t MatrixType::BaseAlignment(MemoryLayout mem_layout) const {
VectorType vec(subtype_, rows_);
ArrayType arr(&vec, columns_);
return arr.BaseAlignment(mem_layout);
} }
} // namespace type } // namespace type

View File

@ -48,9 +48,15 @@ class MatrixType : public Type {
/// @returns the name for this type /// @returns the name for this type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
private: private:
Type* subtype_ = nullptr; Type* subtype_ = nullptr;

View File

@ -56,6 +56,62 @@ TEST_F(MatrixTypeTest, TypeName) {
EXPECT_EQ(m.type_name(), "__mat_2_3__i32"); EXPECT_EQ(m.type_name(), "__mat_2_3__i32");
} }
TEST_F(MatrixTypeTest, MinBufferBindingSize4x2) {
I32Type i32;
MatrixType m{&i32, 4, 2};
EXPECT_EQ(32u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(32u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTypeTest, MinBufferBindingSize3x2) {
I32Type i32;
MatrixType m{&i32, 3, 2};
EXPECT_EQ(28u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(28u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTypeTest, MinBufferBindingSize2x3) {
I32Type i32;
MatrixType m{&i32, 2, 3};
EXPECT_EQ(24u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(24u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTypeTest, MinBufferBindingSize2x2) {
I32Type i32;
MatrixType m{&i32, 2, 2};
EXPECT_EQ(16u, m.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, m.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTypeTest, BaseAlignment4x2) {
I32Type i32;
MatrixType m{&i32, 4, 2};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTypeTest, BaseAlignment3x2) {
I32Type i32;
MatrixType m{&i32, 3, 2};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTypeTest, BaseAlignment2x3) {
I32Type i32;
MatrixType m{&i32, 2, 3};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(MatrixTypeTest, BaseAlignment2x2) {
I32Type i32;
MatrixType m{&i32, 2, 2};
EXPECT_EQ(16u, m.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, m.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -69,6 +69,12 @@ TEST_F(MultisampledTextureTypeTest, TypeName) {
EXPECT_EQ(s.type_name(), "__multisampled_texture_3d__f32"); EXPECT_EQ(s.type_name(), "__multisampled_texture_3d__f32");
} }
TEST_F(MultisampledTextureTypeTest, MinBufferBindingSize) {
F32Type f32;
MultisampledTextureType s(TextureDimension::k3d, &f32);
EXPECT_EQ(0u, s.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -25,10 +25,6 @@ bool PointerType::IsPointer() const {
return true; return true;
} }
uint64_t PointerType::MinBufferBindingSize() const {
return 4;
}
std::string PointerType::type_name() const { std::string PointerType::type_name() const {
std::ostringstream out; std::ostringstream out;
out << "__ptr_" << storage_class_ << subtype_->type_name(); out << "__ptr_" << storage_class_ << subtype_->type_name();

View File

@ -39,10 +39,6 @@ class PointerType : public Type {
/// @returns true if the type is a pointer type /// @returns true if the type is a pointer type
bool IsPointer() const override; bool IsPointer() const override;
/// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override;
/// @returns the pointee type /// @returns the pointee type
Type* type() const { return subtype_; } Type* type() const { return subtype_; }
/// @returns the storage class of the pointer /// @returns the storage class of the pointer

View File

@ -68,6 +68,12 @@ TEST_F(SampledTextureTypeTest, TypeName) {
EXPECT_EQ(s.type_name(), "__sampled_texture_3d__f32"); EXPECT_EQ(s.type_name(), "__sampled_texture_3d__f32");
} }
TEST_F(SampledTextureTypeTest, MinBufferBindingSize) {
F32Type f32;
SampledTextureType s(TextureDimension::kCube, &f32);
EXPECT_EQ(0u, s.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -61,6 +61,11 @@ TEST_F(SamplerTypeTest, TypeName_Comparison) {
EXPECT_EQ(s.type_name(), "__sampler_comparison"); EXPECT_EQ(s.type_name(), "__sampler_comparison");
} }
TEST_F(SamplerTypeTest, MinBufferBindingSize) {
SamplerType s{SamplerKind::kSampler};
EXPECT_EQ(0u, s.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -119,6 +119,12 @@ TEST_F(StorageTextureTypeTest, I32Type) {
EXPECT_TRUE(s->AsTexture()->AsStorage()->type()->IsI32()); EXPECT_TRUE(s->AsTexture()->AsStorage()->type()->IsI32());
} }
TEST_F(StorageTextureTypeTest, MinBufferBindingSize) {
StorageTextureType s(TextureDimension::k2dArray, AccessControl::kReadOnly,
ImageFormat::kRgba32Sint);
EXPECT_EQ(0u, s.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -14,8 +14,14 @@
#include "src/ast/type/struct_type.h" #include "src/ast/type/struct_type.h"
#include <cmath>
#include <utility> #include <utility>
#include "src/ast/type/alias_type.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/matrix_type.h"
#include "src/ast/type/vector_type.h"
namespace tint { namespace tint {
namespace ast { namespace ast {
namespace type { namespace type {
@ -35,7 +41,7 @@ std::string StructType::type_name() const {
return "__struct_" + name_; return "__struct_" + name_;
} }
uint64_t StructType::MinBufferBindingSize() const { uint64_t StructType::MinBufferBindingSize(MemoryLayout mem_layout) const {
if (!struct_->members().size()) { if (!struct_->members().size()) {
return 0; return 0;
} }
@ -48,7 +54,32 @@ uint64_t StructType::MinBufferBindingSize() const {
return 0; return 0;
} }
return last_member->offset() + last_member->type()->MinBufferBindingSize(); uint64_t size = last_member->type()->MinBufferBindingSize(mem_layout);
if (!size) {
return 0;
}
float unaligned = last_member->offset() + size;
float alignment = BaseAlignment(mem_layout);
return alignment * std::ceil(unaligned / alignment);
}
uint64_t StructType::BaseAlignment(MemoryLayout mem_layout) const {
uint64_t max = 0;
for (const 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 16 * std::ceil(static_cast<float>(max) / 16.0f);
} else if (mem_layout == MemoryLayout::kStorageBuffer) {
return max;
}
return 0;
} }
} // namespace type } // namespace type

View File

@ -51,13 +51,21 @@ class StructType : public Type {
/// @returns the name for the type /// @returns the name for the type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
private: private:
std::string name_; std::string name_;
std::unique_ptr<Struct> struct_; std::unique_ptr<Struct> struct_;
uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
}; };
} // namespace type } // namespace type

View File

@ -17,7 +17,14 @@
#include <utility> #include <utility>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/stride_decoration.h"
#include "src/ast/struct_member.h"
#include "src/ast/struct_member_decoration.h"
#include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/i32_type.h" #include "src/ast/type/i32_type.h"
#include "src/ast/type/u32_type.h"
#include "src/ast/type/vector_type.h"
namespace tint { namespace tint {
namespace ast { namespace ast {
@ -57,6 +64,331 @@ TEST_F(StructTypeTest, TypeName) {
EXPECT_EQ(s.type_name(), "__struct_my_struct"); EXPECT_EQ(s.type_name(), "__struct_my_struct");
} }
TEST_F(StructTypeTest, MinBufferBindingSize) {
U32Type u32;
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u,
struct_type.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, struct_type.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeArray) {
U32Type u32;
ArrayType arr(&u32, 4);
{
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
arr.set_decorations(std::move(decos));
}
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(8));
members.push_back(
std::make_unique<StructMember>("bar", &arr, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(32u,
struct_type.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(24u,
struct_type.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeRuntimeArray) {
U32Type u32;
ArrayType arr(&u32);
{
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
arr.set_decorations(std::move(decos));
}
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(8));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(12u,
struct_type.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeVec2) {
U32Type u32;
VectorType vec2(&u32, 2);
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &vec2, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u,
struct_type.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, struct_type.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeVec3) {
U32Type u32;
VectorType vec3(&u32, 3);
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &vec3, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u,
struct_type.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u,
struct_type.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, MinBufferBindingSizeVec4) {
U32Type u32;
VectorType vec4(&u32, 4);
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &vec4, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u,
struct_type.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u,
struct_type.MinBufferBindingSize(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignment) {
U32Type u32;
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u, struct_type.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, struct_type.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentArray) {
U32Type u32;
ArrayType arr(&u32, 4);
{
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
arr.set_decorations(std::move(decos));
}
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(8));
members.push_back(
std::make_unique<StructMember>("bar", &arr, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u, struct_type.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(4u, struct_type.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentRuntimeArray) {
U32Type u32;
ArrayType arr(&u32);
{
ArrayDecorationList decos;
decos.push_back(std::make_unique<StrideDecoration>(4));
arr.set_decorations(std::move(decos));
}
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(8));
members.push_back(
std::make_unique<StructMember>("bar", &u32, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(4u, struct_type.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentVec2) {
U32Type u32;
VectorType vec2(&u32, 2);
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &vec2, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u, struct_type.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(8u, struct_type.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentVec3) {
U32Type u32;
VectorType vec3(&u32, 3);
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &vec3, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u, struct_type.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, struct_type.BaseAlignment(MemoryLayout::kStorageBuffer));
}
TEST_F(StructTypeTest, BaseAlignmentVec4) {
U32Type u32;
VectorType vec4(&u32, 4);
StructMemberList members;
{
StructMemberDecorationList deco;
deco.push_back(std::make_unique<StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<StructMember>("foo", &vec4, std::move(deco)));
}
ast::StructDecorationList decos;
auto str =
std::make_unique<ast::Struct>(std::move(decos), std::move(members));
StructType struct_type("struct_type", std::move(str));
EXPECT_EQ(16u, struct_type.BaseAlignment(MemoryLayout::kUniformBuffer));
EXPECT_EQ(16u, struct_type.BaseAlignment(MemoryLayout::kStorageBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -120,7 +120,11 @@ bool Type::IsVoid() const {
return false; return false;
} }
uint64_t Type::MinBufferBindingSize() const { uint64_t Type::MinBufferBindingSize(MemoryLayout) const {
return 0;
}
uint64_t Type::BaseAlignment(MemoryLayout) const {
return 0; return 0;
} }

View File

@ -36,6 +36,9 @@ class U32Type;
class VectorType; class VectorType;
class VoidType; class VoidType;
/// Supported memory layouts for calculating sizes
enum class MemoryLayout { kUniformBuffer, kStorageBuffer };
/// Base class for a type in the system /// Base class for a type in the system
class Type { class Type {
public: public:
@ -75,9 +78,15 @@ class Type {
/// @returns the name for this type. The |type_name| is unique over all types. /// @returns the name for this type. The |type_name| is unique over all types.
virtual std::string type_name() const = 0; virtual std::string type_name() const = 0;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
virtual uint64_t MinBufferBindingSize() const; 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 /// @returns the pointee type if this is a pointer, |this| otherwise
Type* UnwrapPtrIfNeeded(); Type* UnwrapPtrIfNeeded();

View File

@ -32,7 +32,11 @@ std::string U32Type::type_name() const {
return "__u32"; return "__u32";
} }
uint64_t U32Type::MinBufferBindingSize() const { uint64_t U32Type::MinBufferBindingSize(MemoryLayout) const {
return 4;
}
uint64_t U32Type::BaseAlignment(MemoryLayout) const {
return 4; return 4;
} }

View File

@ -38,9 +38,15 @@ class U32Type : public Type {
/// @returns the name for th type /// @returns the name for th type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
}; };
} // namespace type } // namespace type

View File

@ -45,6 +45,16 @@ TEST_F(U32TypeTest, TypeName) {
EXPECT_EQ(u.type_name(), "__u32"); EXPECT_EQ(u.type_name(), "__u32");
} }
TEST_F(U32TypeTest, MinBufferBindingSize) {
U32Type u;
EXPECT_EQ(4u, u.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(U32TypeTest, BaseAlignment) {
U32Type u;
EXPECT_EQ(4u, u.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -15,6 +15,7 @@
#include "src/ast/type/vector_type.h" #include "src/ast/type/vector_type.h"
#include <assert.h> #include <assert.h>
#include <cmath>
namespace tint { namespace tint {
namespace ast { namespace ast {
@ -38,8 +39,18 @@ std::string VectorType::type_name() const {
return "__vec_" + std::to_string(size_) + subtype_->type_name(); return "__vec_" + std::to_string(size_) + subtype_->type_name();
} }
uint64_t VectorType::MinBufferBindingSize() const { uint64_t VectorType::MinBufferBindingSize(MemoryLayout mem_layout) const {
return size_ * subtype_->MinBufferBindingSize(); return size_ * subtype_->MinBufferBindingSize(mem_layout);
}
uint64_t VectorType::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.
} }
} // namespace type } // namespace type

View File

@ -45,9 +45,15 @@ class VectorType : public Type {
/// @returns the name for th type /// @returns the name for th type
std::string type_name() const override; std::string type_name() const override;
/// @param mem_layout type of memory layout to use in calculation.
/// @returns minimum size required for this type, in bytes. /// @returns minimum size required for this type, in bytes.
/// 0 for non-host shareable types. /// 0 for non-host shareable types.
uint64_t MinBufferBindingSize() const override; 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;
private: private:
Type* subtype_ = nullptr; Type* subtype_ = nullptr;

View File

@ -55,6 +55,42 @@ TEST_F(VectorTypeTest, TypeName) {
EXPECT_EQ(v.type_name(), "__vec_3__i32"); EXPECT_EQ(v.type_name(), "__vec_3__i32");
} }
TEST_F(VectorTypeTest, MinBufferBindingSizeVec2) {
I32Type i32;
VectorType v{&i32, 2};
EXPECT_EQ(8u, v.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTypeTest, MinBufferBindingSizeVec3) {
I32Type i32;
VectorType v{&i32, 3};
EXPECT_EQ(12u, v.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTypeTest, MinBufferBindingSizeVec4) {
I32Type i32;
VectorType v{&i32, 4};
EXPECT_EQ(16u, v.MinBufferBindingSize(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTypeTest, BaseAlignmentVec2) {
I32Type i32;
VectorType v{&i32, 2};
EXPECT_EQ(8u, v.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTypeTest, BaseAlignmentVec3) {
I32Type i32;
VectorType v{&i32, 3};
EXPECT_EQ(16u, v.BaseAlignment(MemoryLayout::kUniformBuffer));
}
TEST_F(VectorTypeTest, BaseAlignmentVec4) {
I32Type i32;
VectorType v{&i32, 4};
EXPECT_EQ(16u, v.BaseAlignment(MemoryLayout::kUniformBuffer));
}
} // namespace } // namespace
} // namespace type } // namespace type
} // namespace ast } // namespace ast

View File

@ -27,6 +27,7 @@
#include "src/ast/scalar_constructor_expression.h" #include "src/ast/scalar_constructor_expression.h"
#include "src/ast/sint_literal.h" #include "src/ast/sint_literal.h"
#include "src/ast/type/struct_type.h" #include "src/ast/type/struct_type.h"
#include "src/ast/type/type.h"
#include "src/ast/uint_literal.h" #include "src/ast/uint_literal.h"
namespace tint { namespace tint {
@ -160,7 +161,8 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
entry.bind_group = binding_info.set->value(); entry.bind_group = binding_info.set->value();
entry.binding = binding_info.binding->value(); entry.binding = binding_info.binding->value();
entry.min_buffer_binding_size = var->type()->MinBufferBindingSize(); entry.min_buffer_binding_size = var->type()->MinBufferBindingSize(
ast::type::MemoryLayout::kUniformBuffer);
result.push_back(std::move(entry)); result.push_back(std::move(entry));
} }
@ -187,7 +189,8 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindings(
entry.bind_group = binding_info.set->value(); entry.bind_group = binding_info.set->value();
entry.binding = binding_info.binding->value(); entry.binding = binding_info.binding->value();
entry.min_buffer_binding_size = var->type()->MinBufferBindingSize(); entry.min_buffer_binding_size = var->type()->MinBufferBindingSize(
ast::type::MemoryLayout::kStorageBuffer);
result.push_back(std::move(entry)); result.push_back(std::move(entry));
} }

View File

@ -33,6 +33,7 @@
#include "src/ast/scalar_constructor_expression.h" #include "src/ast/scalar_constructor_expression.h"
#include "src/ast/sint_literal.h" #include "src/ast/sint_literal.h"
#include "src/ast/stage_decoration.h" #include "src/ast/stage_decoration.h"
#include "src/ast/stride_decoration.h"
#include "src/ast/struct_decoration.h" #include "src/ast/struct_decoration.h"
#include "src/ast/struct_member.h" #include "src/ast/struct_member.h"
#include "src/ast/struct_member_decoration.h" #include "src/ast/struct_member_decoration.h"
@ -398,6 +399,9 @@ class InspectorHelper {
if (array_type_memo_.find(count) == array_type_memo_.end()) { if (array_type_memo_.find(count) == array_type_memo_.end()) {
array_type_memo_[count] = array_type_memo_[count] =
std::make_unique<ast::type::ArrayType>(u32_type(), count); std::make_unique<ast::type::ArrayType>(u32_type(), count);
ast::ArrayDecorationList decos;
decos.push_back(std::make_unique<ast::StrideDecoration>(4));
array_type_memo_[count]->set_decorations(std::move(decos));
} }
return array_type_memo_[count].get(); return array_type_memo_[count].get();
} }
@ -914,7 +918,7 @@ TEST_F(InspectorGetUniformBufferResourceBindings, Simple) {
EXPECT_EQ(0u, result[0].bind_group); EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding); EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(4u, result[0].min_buffer_binding_size); EXPECT_EQ(16u, result[0].min_buffer_binding_size);
} }
TEST_F(InspectorGetUniformBufferResourceBindings, MultipleMembers) { TEST_F(InspectorGetUniformBufferResourceBindings, MultipleMembers) {
@ -939,7 +943,7 @@ TEST_F(InspectorGetUniformBufferResourceBindings, MultipleMembers) {
EXPECT_EQ(0u, result[0].bind_group); EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding); EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(12u, result[0].min_buffer_binding_size); EXPECT_EQ(16u, result[0].min_buffer_binding_size);
} }
TEST_F(InspectorGetUniformBufferResourceBindings, MultipleUniformBuffers) { TEST_F(InspectorGetUniformBufferResourceBindings, MultipleUniformBuffers) {
@ -989,15 +993,15 @@ TEST_F(InspectorGetUniformBufferResourceBindings, MultipleUniformBuffers) {
EXPECT_EQ(0u, result[0].bind_group); EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding); EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(12u, result[0].min_buffer_binding_size); EXPECT_EQ(16u, result[0].min_buffer_binding_size);
EXPECT_EQ(0u, result[1].bind_group); EXPECT_EQ(0u, result[1].bind_group);
EXPECT_EQ(1u, result[1].binding); EXPECT_EQ(1u, result[1].binding);
EXPECT_EQ(12u, result[1].min_buffer_binding_size); EXPECT_EQ(16u, result[1].min_buffer_binding_size);
EXPECT_EQ(2u, result[2].bind_group); EXPECT_EQ(2u, result[2].bind_group);
EXPECT_EQ(0u, result[2].binding); EXPECT_EQ(0u, result[2].binding);
EXPECT_EQ(12u, result[2].min_buffer_binding_size); EXPECT_EQ(16u, result[2].min_buffer_binding_size);
} }
TEST_F(InspectorGetUniformBufferResourceBindings, ContainingArray) { TEST_F(InspectorGetUniformBufferResourceBindings, ContainingArray) {
@ -1022,7 +1026,7 @@ TEST_F(InspectorGetUniformBufferResourceBindings, ContainingArray) {
EXPECT_EQ(0u, result[0].bind_group); EXPECT_EQ(0u, result[0].bind_group);
EXPECT_EQ(0u, result[0].binding); EXPECT_EQ(0u, result[0].binding);
EXPECT_EQ(20u, result[0].min_buffer_binding_size); EXPECT_EQ(32u, result[0].min_buffer_binding_size);
} }
TEST_F(InspectorGetStorageBufferResourceBindings, Simple) { TEST_F(InspectorGetStorageBufferResourceBindings, Simple) {