• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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