1 // Copyright 2021 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/inspector/test_inspector_builder.h"
16
17 #include <memory>
18 #include <string>
19 #include <tuple>
20 #include <utility>
21 #include <vector>
22
23 #include "gtest/gtest.h"
24
25 namespace tint {
26 namespace inspector {
27
28 InspectorBuilder::InspectorBuilder() = default;
29 InspectorBuilder::~InspectorBuilder() = default;
30
MakeEmptyBodyFunction(std::string name,ast::DecorationList decorations)31 void InspectorBuilder::MakeEmptyBodyFunction(std::string name,
32 ast::DecorationList decorations) {
33 Func(name, ast::VariableList(), ty.void_(), ast::StatementList{Return()},
34 decorations);
35 }
36
MakeCallerBodyFunction(std::string caller,std::vector<std::string> callees,ast::DecorationList decorations)37 void InspectorBuilder::MakeCallerBodyFunction(std::string caller,
38 std::vector<std::string> callees,
39 ast::DecorationList decorations) {
40 ast::StatementList body;
41 body.reserve(callees.size() + 1);
42 for (auto callee : callees) {
43 body.push_back(CallStmt(Call(callee)));
44 }
45 body.push_back(Return());
46
47 Func(caller, ast::VariableList(), ty.void_(), body, decorations);
48 }
49
MakeInOutStruct(std::string name,std::vector<std::tuple<std::string,uint32_t>> inout_vars)50 const ast::Struct* InspectorBuilder::MakeInOutStruct(
51 std::string name,
52 std::vector<std::tuple<std::string, uint32_t>> inout_vars) {
53 ast::StructMemberList members;
54 for (auto var : inout_vars) {
55 std::string member_name;
56 uint32_t location;
57 std::tie(member_name, location) = var;
58 members.push_back(Member(member_name, ty.u32(), {Location(location)}));
59 }
60 return Structure(name, members);
61 }
62
MakePlainGlobalReferenceBodyFunction(std::string func,std::string var,const ast::Type * type,ast::DecorationList decorations)63 const ast::Function* InspectorBuilder::MakePlainGlobalReferenceBodyFunction(
64 std::string func,
65 std::string var,
66 const ast::Type* type,
67 ast::DecorationList decorations) {
68 ast::StatementList stmts;
69 stmts.emplace_back(Decl(Var("local_" + var, type)));
70 stmts.emplace_back(Assign("local_" + var, var));
71 stmts.emplace_back(Return());
72
73 return Func(func, ast::VariableList(), ty.void_(), stmts, decorations);
74 }
75
ContainsName(const std::vector<StageVariable> & vec,const std::string & name)76 bool InspectorBuilder::ContainsName(const std::vector<StageVariable>& vec,
77 const std::string& name) {
78 for (auto& s : vec) {
79 if (s.name == name) {
80 return true;
81 }
82 }
83 return false;
84 }
85
StructMemberName(size_t idx,const ast::Type * type)86 std::string InspectorBuilder::StructMemberName(size_t idx,
87 const ast::Type* type) {
88 return std::to_string(idx) + type->FriendlyName(Symbols());
89 }
90
MakeStructType(const std::string & name,std::vector<const ast::Type * > member_types,bool is_block)91 const ast::Struct* InspectorBuilder::MakeStructType(
92 const std::string& name,
93 std::vector<const ast::Type*> member_types,
94 bool is_block) {
95 ast::StructMemberList members;
96 for (auto* type : member_types) {
97 members.push_back(MakeStructMember(members.size(), type, {}));
98 }
99 return MakeStructTypeFromMembers(name, std::move(members), is_block);
100 }
101
MakeStructTypeFromMembers(const std::string & name,ast::StructMemberList members,bool is_block)102 const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(
103 const std::string& name,
104 ast::StructMemberList members,
105 bool is_block) {
106 ast::DecorationList decos;
107 if (is_block) {
108 decos.push_back(create<ast::StructBlockDecoration>());
109 }
110 return Structure(name, std::move(members), decos);
111 }
112
MakeStructMember(size_t index,const ast::Type * type,ast::DecorationList decorations)113 const ast::StructMember* InspectorBuilder::MakeStructMember(
114 size_t index,
115 const ast::Type* type,
116 ast::DecorationList decorations) {
117 return Member(StructMemberName(index, type), type, std::move(decorations));
118 }
119
MakeUniformBufferType(const std::string & name,std::vector<const ast::Type * > member_types)120 const ast::Struct* InspectorBuilder::MakeUniformBufferType(
121 const std::string& name,
122 std::vector<const ast::Type*> member_types) {
123 return MakeStructType(name, member_types, true);
124 }
125
MakeStorageBufferTypes(const std::string & name,std::vector<const ast::Type * > member_types)126 std::function<const ast::TypeName*()> InspectorBuilder::MakeStorageBufferTypes(
127 const std::string& name,
128 std::vector<const ast::Type*> member_types) {
129 MakeStructType(name, member_types, true);
130 return [this, name] { return ty.type_name(name); };
131 }
132
AddUniformBuffer(const std::string & name,const ast::Type * type,uint32_t group,uint32_t binding)133 void InspectorBuilder::AddUniformBuffer(const std::string& name,
134 const ast::Type* type,
135 uint32_t group,
136 uint32_t binding) {
137 Global(name, type, ast::StorageClass::kUniform,
138 ast::DecorationList{
139 create<ast::BindingDecoration>(binding),
140 create<ast::GroupDecoration>(group),
141 });
142 }
143
AddWorkgroupStorage(const std::string & name,const ast::Type * type)144 void InspectorBuilder::AddWorkgroupStorage(const std::string& name,
145 const ast::Type* type) {
146 Global(name, type, ast::StorageClass::kWorkgroup);
147 }
148
AddStorageBuffer(const std::string & name,const ast::Type * type,ast::Access access,uint32_t group,uint32_t binding)149 void InspectorBuilder::AddStorageBuffer(const std::string& name,
150 const ast::Type* type,
151 ast::Access access,
152 uint32_t group,
153 uint32_t binding) {
154 Global(name, type, ast::StorageClass::kStorage, access,
155 ast::DecorationList{
156 create<ast::BindingDecoration>(binding),
157 create<ast::GroupDecoration>(group),
158 });
159 }
160
MakeStructVariableReferenceBodyFunction(std::string func_name,std::string struct_name,std::vector<std::tuple<size_t,const ast::Type * >> members)161 void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
162 std::string func_name,
163 std::string struct_name,
164 std::vector<std::tuple<size_t, const ast::Type*>> members) {
165 ast::StatementList stmts;
166 for (auto member : members) {
167 size_t member_idx;
168 const ast::Type* member_type;
169 std::tie(member_idx, member_type) = member;
170 std::string member_name = StructMemberName(member_idx, member_type);
171
172 stmts.emplace_back(Decl(Var("local" + member_name, member_type)));
173 }
174
175 for (auto member : members) {
176 size_t member_idx;
177 const ast::Type* member_type;
178 std::tie(member_idx, member_type) = member;
179 std::string member_name = StructMemberName(member_idx, member_type);
180
181 stmts.emplace_back(Assign("local" + member_name,
182 MemberAccessor(struct_name, member_name)));
183 }
184
185 stmts.emplace_back(Return());
186
187 Func(func_name, ast::VariableList(), ty.void_(), stmts,
188 ast::DecorationList{});
189 }
190
AddSampler(const std::string & name,uint32_t group,uint32_t binding)191 void InspectorBuilder::AddSampler(const std::string& name,
192 uint32_t group,
193 uint32_t binding) {
194 Global(name, sampler_type(),
195 ast::DecorationList{
196 create<ast::BindingDecoration>(binding),
197 create<ast::GroupDecoration>(group),
198 });
199 }
200
AddComparisonSampler(const std::string & name,uint32_t group,uint32_t binding)201 void InspectorBuilder::AddComparisonSampler(const std::string& name,
202 uint32_t group,
203 uint32_t binding) {
204 Global(name, comparison_sampler_type(),
205 ast::DecorationList{
206 create<ast::BindingDecoration>(binding),
207 create<ast::GroupDecoration>(group),
208 });
209 }
210
AddResource(const std::string & name,const ast::Type * type,uint32_t group,uint32_t binding)211 void InspectorBuilder::AddResource(const std::string& name,
212 const ast::Type* type,
213 uint32_t group,
214 uint32_t binding) {
215 Global(name, type,
216 ast::DecorationList{
217 create<ast::BindingDecoration>(binding),
218 create<ast::GroupDecoration>(group),
219 });
220 }
221
AddGlobalVariable(const std::string & name,const ast::Type * type)222 void InspectorBuilder::AddGlobalVariable(const std::string& name,
223 const ast::Type* type) {
224 Global(name, type, ast::StorageClass::kPrivate);
225 }
226
MakeSamplerReferenceBodyFunction(const std::string & func_name,const std::string & texture_name,const std::string & sampler_name,const std::string & coords_name,const ast::Type * base_type,ast::DecorationList decorations)227 const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
228 const std::string& func_name,
229 const std::string& texture_name,
230 const std::string& sampler_name,
231 const std::string& coords_name,
232 const ast::Type* base_type,
233 ast::DecorationList decorations) {
234 std::string result_name = "sampler_result";
235
236 ast::StatementList stmts;
237 stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4))));
238
239 stmts.emplace_back(Assign(result_name, Call("textureSample", texture_name,
240 sampler_name, coords_name)));
241 stmts.emplace_back(Return());
242
243 return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
244 }
245
MakeSamplerReferenceBodyFunction(const std::string & func_name,const std::string & texture_name,const std::string & sampler_name,const std::string & coords_name,const std::string & array_index,const ast::Type * base_type,ast::DecorationList decorations)246 const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
247 const std::string& func_name,
248 const std::string& texture_name,
249 const std::string& sampler_name,
250 const std::string& coords_name,
251 const std::string& array_index,
252 const ast::Type* base_type,
253 ast::DecorationList decorations) {
254 std::string result_name = "sampler_result";
255
256 ast::StatementList stmts;
257
258 stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4))));
259
260 stmts.emplace_back(
261 Assign("sampler_result", Call("textureSample", texture_name, sampler_name,
262 coords_name, array_index)));
263 stmts.emplace_back(Return());
264
265 return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
266 }
267
268 const ast::Function*
MakeComparisonSamplerReferenceBodyFunction(const std::string & func_name,const std::string & texture_name,const std::string & sampler_name,const std::string & coords_name,const std::string & depth_name,const ast::Type * base_type,ast::DecorationList decorations)269 InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction(
270 const std::string& func_name,
271 const std::string& texture_name,
272 const std::string& sampler_name,
273 const std::string& coords_name,
274 const std::string& depth_name,
275 const ast::Type* base_type,
276 ast::DecorationList decorations) {
277 std::string result_name = "sampler_result";
278
279 ast::StatementList stmts;
280
281 stmts.emplace_back(Decl(Var("sampler_result", base_type)));
282 stmts.emplace_back(
283 Assign("sampler_result", Call("textureSampleCompare", texture_name,
284 sampler_name, coords_name, depth_name)));
285 stmts.emplace_back(Return());
286
287 return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
288 }
289
GetBaseType(ResourceBinding::SampledKind sampled_kind)290 const ast::Type* InspectorBuilder::GetBaseType(
291 ResourceBinding::SampledKind sampled_kind) {
292 switch (sampled_kind) {
293 case ResourceBinding::SampledKind::kFloat:
294 return ty.f32();
295 case ResourceBinding::SampledKind::kSInt:
296 return ty.i32();
297 case ResourceBinding::SampledKind::kUInt:
298 return ty.u32();
299 default:
300 return nullptr;
301 }
302 }
303
GetCoordsType(ast::TextureDimension dim,const ast::Type * scalar)304 const ast::Type* InspectorBuilder::GetCoordsType(ast::TextureDimension dim,
305 const ast::Type* scalar) {
306 switch (dim) {
307 case ast::TextureDimension::k1d:
308 return scalar;
309 case ast::TextureDimension::k2d:
310 case ast::TextureDimension::k2dArray:
311 return create<ast::Vector>(scalar, 2);
312 case ast::TextureDimension::k3d:
313 case ast::TextureDimension::kCube:
314 case ast::TextureDimension::kCubeArray:
315 return create<ast::Vector>(scalar, 3);
316 default:
317 [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
318 }
319 return nullptr;
320 }
321
MakeStorageTextureTypes(ast::TextureDimension dim,ast::ImageFormat format)322 const ast::Type* InspectorBuilder::MakeStorageTextureTypes(
323 ast::TextureDimension dim,
324 ast::ImageFormat format) {
325 return ty.storage_texture(dim, format, ast::Access::kWrite);
326 }
327
AddStorageTexture(const std::string & name,const ast::Type * type,uint32_t group,uint32_t binding)328 void InspectorBuilder::AddStorageTexture(const std::string& name,
329 const ast::Type* type,
330 uint32_t group,
331 uint32_t binding) {
332 Global(name, type,
333 ast::DecorationList{
334 create<ast::BindingDecoration>(binding),
335 create<ast::GroupDecoration>(group),
336 });
337 }
338
MakeStorageTextureBodyFunction(const std::string & func_name,const std::string & st_name,const ast::Type * dim_type,ast::DecorationList decorations)339 const ast::Function* InspectorBuilder::MakeStorageTextureBodyFunction(
340 const std::string& func_name,
341 const std::string& st_name,
342 const ast::Type* dim_type,
343 ast::DecorationList decorations) {
344 ast::StatementList stmts;
345
346 stmts.emplace_back(Decl(Var("dim", dim_type)));
347 stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name)));
348 stmts.emplace_back(Return());
349
350 return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations);
351 }
352
GetTypeFunction(ComponentType component,CompositionType composition)353 std::function<const ast::Type*()> InspectorBuilder::GetTypeFunction(
354 ComponentType component,
355 CompositionType composition) {
356 std::function<const ast::Type*()> func;
357 switch (component) {
358 case ComponentType::kFloat:
359 func = [this]() -> const ast::Type* { return ty.f32(); };
360 break;
361 case ComponentType::kSInt:
362 func = [this]() -> const ast::Type* { return ty.i32(); };
363 break;
364 case ComponentType::kUInt:
365 func = [this]() -> const ast::Type* { return ty.u32(); };
366 break;
367 case ComponentType::kUnknown:
368 return []() -> const ast::Type* { return nullptr; };
369 }
370
371 uint32_t n;
372 switch (composition) {
373 case CompositionType::kScalar:
374 return func;
375 case CompositionType::kVec2:
376 n = 2;
377 break;
378 case CompositionType::kVec3:
379 n = 3;
380 break;
381 case CompositionType::kVec4:
382 n = 4;
383 break;
384 default:
385 return []() -> ast::Type* { return nullptr; };
386 }
387
388 return [this, func, n]() -> const ast::Type* { return ty.vec(func(), n); };
389 }
390
Build()391 Inspector& InspectorBuilder::Build() {
392 if (inspector_) {
393 return *inspector_;
394 }
395 program_ = std::make_unique<Program>(std::move(*this));
396 [&]() {
397 ASSERT_TRUE(program_->IsValid())
398 << diag::Formatter().format(program_->Diagnostics());
399 }();
400 inspector_ = std::make_unique<Inspector>(program_.get());
401 return *inspector_;
402 }
403
404 } // namespace inspector
405 } // namespace tint
406