1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/ast/type/array_type.h"
16 
17 #include <cmath>
18 
19 #include "src/ast/stride_decoration.h"
20 #include "src/ast/type/vector_type.h"
21 
22 namespace tint {
23 namespace ast {
24 namespace type {
25 
ArrayType(Type * subtype)26 ArrayType::ArrayType(Type* subtype) : subtype_(subtype) {}
27 
ArrayType(Type * subtype,uint32_t size)28 ArrayType::ArrayType(Type* subtype, uint32_t size)
29     : subtype_(subtype), size_(size) {}
30 
31 ArrayType::ArrayType(ArrayType&&) = default;
32 
33 ArrayType::~ArrayType() = default;
34 
IsArray() const35 bool ArrayType::IsArray() const {
36   return true;
37 }
38 
MinBufferBindingSize(MemoryLayout mem_layout) const39 uint64_t ArrayType::MinBufferBindingSize(MemoryLayout mem_layout) const {
40   if (!has_array_stride()) {
41     // Arrays in buffers are required to have a stride.
42     return 0;
43   }
44 
45   if (IsRuntimeArray()) {
46     // WebGPU spec 10.1.2:
47     // If the last field of the corresponding structure defined in the shader
48     // has an unbounded array type, then the value of minBufferBindingSize must
49     // be greater than or equal to the byte offset of that field plus the stride
50     // of the unbounded array
51     return array_stride();
52   } else {
53     // Not including the padding for the last element
54     return (size_ - 1) * array_stride() +
55            subtype_->MinBufferBindingSize(mem_layout);
56   }
57 }
58 
BaseAlignment(MemoryLayout mem_layout) const59 uint64_t ArrayType::BaseAlignment(MemoryLayout mem_layout) const {
60   if (mem_layout == MemoryLayout::kUniformBuffer) {
61     float aligment = 16;  // for a vec4
62     float unaligned = static_cast<float>(subtype_->BaseAlignment(mem_layout));
63     return static_cast<uint64_t>(aligment * std::ceil(unaligned / aligment));
64   } else if (mem_layout == MemoryLayout::kStorageBuffer) {
65     return subtype_->BaseAlignment(mem_layout);
66   }
67   return 0;
68 }
69 
array_stride() const70 uint32_t ArrayType::array_stride() const {
71   for (const auto& deco : decos_) {
72     if (deco->IsStride()) {
73       return deco->AsStride()->stride();
74     }
75   }
76   return 0;
77 }
78 
has_array_stride() const79 bool ArrayType::has_array_stride() const {
80   for (const auto& deco : decos_) {
81     if (deco->IsStride()) {
82       return true;
83     }
84   }
85   return false;
86 }
87 
type_name() const88 std::string ArrayType::type_name() const {
89   assert(subtype_);
90 
91   std::string type_name = "__array" + subtype_->type_name();
92   if (!IsRuntimeArray())
93     type_name += "_" + std::to_string(size_);
94   if (has_array_stride())
95     type_name += "_stride_" + std::to_string(array_stride());
96 
97   return type_name;
98 }
99 
100 }  // namespace type
101 }  // namespace ast
102 }  // namespace tint
103