• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gtest/gtest.h"
16 #include "src/ast/call_statement.h"
17 #include "src/ast/disable_validation_decoration.h"
18 #include "src/ast/override_decoration.h"
19 #include "src/ast/stage_decoration.h"
20 #include "src/ast/struct_block_decoration.h"
21 #include "src/ast/workgroup_decoration.h"
22 #include "src/inspector/test_inspector_builder.h"
23 #include "src/inspector/test_inspector_runner.h"
24 #include "src/program_builder.h"
25 #include "src/sem/depth_texture_type.h"
26 #include "src/sem/external_texture_type.h"
27 #include "src/sem/multisampled_texture_type.h"
28 #include "src/sem/sampled_texture_type.h"
29 #include "src/sem/variable.h"
30 #include "tint/tint.h"
31 
32 namespace tint {
33 namespace inspector {
34 namespace {
35 
36 // All the tests that descend from InspectorBuilder are expected to define their
37 // test state via building up the AST through InspectorBuilder and then generate
38 // the program with ::Build.
39 // The returned Inspector from ::Build can then be used to test expecations.
40 //
41 // All the tests that descend from InspectorRunner are expected to define their
42 // test state via a WGSL shader, which will be parsed to generate a Program and
43 // Inspector in ::Initialize.
44 // The returned Inspector from ::Initialize can then be used to test
45 // expecations.
46 
47 class InspectorGetEntryPointTest : public InspectorBuilder,
48                                    public testing::Test {};
49 
50 typedef std::tuple<inspector::ComponentType, inspector::CompositionType>
51     InspectorGetEntryPointComponentAndCompositionTestParams;
52 class InspectorGetEntryPointComponentAndCompositionTest
53     : public InspectorBuilder,
54       public testing::TestWithParam<
55           InspectorGetEntryPointComponentAndCompositionTestParams> {};
56 struct InspectorGetEntryPointInterpolateTestParams {
57   ast::InterpolationType in_type;
58   ast::InterpolationSampling in_sampling;
59   inspector::InterpolationType out_type;
60   inspector::InterpolationSampling out_sampling;
61 };
62 class InspectorGetEntryPointInterpolateTest
63     : public InspectorBuilder,
64       public testing::TestWithParam<
65           InspectorGetEntryPointInterpolateTestParams> {};
66 class InspectorGetRemappedNameForEntryPointTest : public InspectorBuilder,
67                                                   public testing::Test {};
68 class InspectorGetConstantIDsTest : public InspectorBuilder,
69                                     public testing::Test {};
70 class InspectorGetConstantNameToIdMapTest : public InspectorBuilder,
71                                             public testing::Test {};
72 class InspectorGetStorageSizeTest : public InspectorBuilder,
73                                     public testing::Test {};
74 class InspectorGetResourceBindingsTest : public InspectorBuilder,
75                                          public testing::Test {};
76 class InspectorGetUniformBufferResourceBindingsTest : public InspectorBuilder,
77                                                       public testing::Test {};
78 class InspectorGetStorageBufferResourceBindingsTest : public InspectorBuilder,
79                                                       public testing::Test {};
80 class InspectorGetReadOnlyStorageBufferResourceBindingsTest
81     : public InspectorBuilder,
82       public testing::Test {};
83 class InspectorGetSamplerResourceBindingsTest : public InspectorBuilder,
84                                                 public testing::Test {};
85 class InspectorGetComparisonSamplerResourceBindingsTest
86     : public InspectorBuilder,
87       public testing::Test {};
88 class InspectorGetSampledTextureResourceBindingsTest : public InspectorBuilder,
89                                                        public testing::Test {};
90 class InspectorGetSampledArrayTextureResourceBindingsTest
91     : public InspectorBuilder,
92       public testing::Test {};
93 struct GetSampledTextureTestParams {
94   ast::TextureDimension type_dim;
95   inspector::ResourceBinding::TextureDimension inspector_dim;
96   inspector::ResourceBinding::SampledKind sampled_kind;
97 };
98 class InspectorGetSampledTextureResourceBindingsTestWithParam
99     : public InspectorBuilder,
100       public testing::TestWithParam<GetSampledTextureTestParams> {};
101 class InspectorGetSampledArrayTextureResourceBindingsTestWithParam
102     : public InspectorBuilder,
103       public testing::TestWithParam<GetSampledTextureTestParams> {};
104 class InspectorGetMultisampledTextureResourceBindingsTest
105     : public InspectorBuilder,
106       public testing::Test {};
107 class InspectorGetMultisampledArrayTextureResourceBindingsTest
108     : public InspectorBuilder,
109       public testing::Test {};
110 typedef GetSampledTextureTestParams GetMultisampledTextureTestParams;
111 class InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam
112     : public InspectorBuilder,
113       public testing::TestWithParam<GetMultisampledTextureTestParams> {};
114 class InspectorGetMultisampledTextureResourceBindingsTestWithParam
115     : public InspectorBuilder,
116       public testing::TestWithParam<GetMultisampledTextureTestParams> {};
117 class InspectorGetStorageTextureResourceBindingsTest : public InspectorBuilder,
118                                                        public testing::Test {};
119 struct GetDepthTextureTestParams {
120   ast::TextureDimension type_dim;
121   inspector::ResourceBinding::TextureDimension inspector_dim;
122 };
123 class InspectorGetDepthTextureResourceBindingsTestWithParam
124     : public InspectorBuilder,
125       public testing::TestWithParam<GetDepthTextureTestParams> {};
126 
127 class InspectorGetDepthMultisampledTextureResourceBindingsTest
128     : public InspectorBuilder,
129       public testing::Test {};
130 
131 typedef std::tuple<ast::TextureDimension, ResourceBinding::TextureDimension>
132     DimensionParams;
133 typedef std::tuple<ast::ImageFormat,
134                    ResourceBinding::ImageFormat,
135                    ResourceBinding::SampledKind>
136     ImageFormatParams;
137 typedef std::tuple<DimensionParams, ImageFormatParams>
138     GetStorageTextureTestParams;
139 class InspectorGetStorageTextureResourceBindingsTestWithParam
140     : public InspectorBuilder,
141       public testing::TestWithParam<GetStorageTextureTestParams> {};
142 
143 class InspectorGetExternalTextureResourceBindingsTest : public InspectorBuilder,
144                                                         public testing::Test {};
145 
146 class InspectorGetSamplerTextureUsesTest : public InspectorRunner,
147                                            public testing::Test {};
148 
149 class InspectorGetWorkgroupStorageSizeTest : public InspectorBuilder,
150                                              public testing::Test {};
151 
152 // This is a catch all for shaders that have demonstrated regressions/crashes in
153 // the wild.
154 class InspectorRegressionTest : public InspectorRunner, public testing::Test {};
155 
TEST_F(InspectorGetEntryPointTest,NoFunctions)156 TEST_F(InspectorGetEntryPointTest, NoFunctions) {
157   Inspector& inspector = Build();
158 
159   auto result = inspector.GetEntryPoints();
160   ASSERT_FALSE(inspector.has_error()) << inspector.error();
161 
162   EXPECT_EQ(0u, result.size());
163 }
164 
TEST_F(InspectorGetEntryPointTest,NoEntryPoints)165 TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
166   Inspector& inspector = Build();
167 
168   auto result = inspector.GetEntryPoints();
169   ASSERT_FALSE(inspector.has_error()) << inspector.error();
170 
171   EXPECT_EQ(0u, result.size());
172 }
173 
TEST_F(InspectorGetEntryPointTest,OneEntryPoint)174 TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
175   MakeEmptyBodyFunction("foo", ast::DecorationList{
176                                    Stage(ast::PipelineStage::kFragment),
177                                });
178 
179   // TODO(dsinclair): Update to run the namer transform when available.
180 
181   Inspector& inspector = Build();
182 
183   auto result = inspector.GetEntryPoints();
184   ASSERT_FALSE(inspector.has_error()) << inspector.error();
185 
186   ASSERT_EQ(1u, result.size());
187   EXPECT_EQ("foo", result[0].name);
188   EXPECT_EQ("foo", result[0].remapped_name);
189   EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
190 }
191 
TEST_F(InspectorGetEntryPointTest,MultipleEntryPoints)192 TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
193   MakeEmptyBodyFunction("foo", ast::DecorationList{
194                                    Stage(ast::PipelineStage::kFragment),
195                                });
196 
197   MakeEmptyBodyFunction("bar",
198                         ast::DecorationList{Stage(ast::PipelineStage::kCompute),
199                                             WorkgroupSize(1)});
200 
201   // TODO(dsinclair): Update to run the namer transform when available.
202 
203   Inspector& inspector = Build();
204 
205   auto result = inspector.GetEntryPoints();
206   ASSERT_FALSE(inspector.has_error()) << inspector.error();
207 
208   ASSERT_EQ(2u, result.size());
209   EXPECT_EQ("foo", result[0].name);
210   EXPECT_EQ("foo", result[0].remapped_name);
211   EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
212   EXPECT_EQ("bar", result[1].name);
213   EXPECT_EQ("bar", result[1].remapped_name);
214   EXPECT_EQ(ast::PipelineStage::kCompute, result[1].stage);
215 }
216 
TEST_F(InspectorGetEntryPointTest,MixFunctionsAndEntryPoints)217 TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
218   MakeEmptyBodyFunction("func", {});
219 
220   MakeCallerBodyFunction(
221       "foo", {"func"},
222       ast::DecorationList{Stage(ast::PipelineStage::kCompute),
223                           WorkgroupSize(1)});
224 
225   MakeCallerBodyFunction("bar", {"func"},
226                          ast::DecorationList{
227                              Stage(ast::PipelineStage::kFragment),
228                          });
229 
230   // TODO(dsinclair): Update to run the namer transform when available.
231 
232   Inspector& inspector = Build();
233 
234   auto result = inspector.GetEntryPoints();
235   EXPECT_FALSE(inspector.has_error());
236 
237   ASSERT_EQ(2u, result.size());
238   EXPECT_EQ("foo", result[0].name);
239   EXPECT_EQ("foo", result[0].remapped_name);
240   EXPECT_EQ(ast::PipelineStage::kCompute, result[0].stage);
241   EXPECT_EQ("bar", result[1].name);
242   EXPECT_EQ("bar", result[1].remapped_name);
243   EXPECT_EQ(ast::PipelineStage::kFragment, result[1].stage);
244 }
245 
TEST_F(InspectorGetEntryPointTest,DefaultWorkgroupSize)246 TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
247   MakeEmptyBodyFunction("foo",
248                         ast::DecorationList{Stage(ast::PipelineStage::kCompute),
249                                             WorkgroupSize(8, 2, 1)});
250 
251   Inspector& inspector = Build();
252 
253   auto result = inspector.GetEntryPoints();
254   ASSERT_FALSE(inspector.has_error()) << inspector.error();
255 
256   ASSERT_EQ(1u, result.size());
257   uint32_t x, y, z;
258   std::tie(x, y, z) = result[0].workgroup_size();
259   EXPECT_EQ(8u, x);
260   EXPECT_EQ(2u, y);
261   EXPECT_EQ(1u, z);
262 }
263 
TEST_F(InspectorGetEntryPointTest,NonDefaultWorkgroupSize)264 TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
265   MakeEmptyBodyFunction(
266       "foo", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8, 2, 1)});
267 
268   Inspector& inspector = Build();
269 
270   auto result = inspector.GetEntryPoints();
271   ASSERT_FALSE(inspector.has_error()) << inspector.error();
272 
273   ASSERT_EQ(1u, result.size());
274   uint32_t x, y, z;
275   std::tie(x, y, z) = result[0].workgroup_size();
276   EXPECT_EQ(8u, x);
277   EXPECT_EQ(2u, y);
278   EXPECT_EQ(1u, z);
279 }
280 
TEST_F(InspectorGetEntryPointTest,NoInOutVariables)281 TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
282   MakeEmptyBodyFunction("func", {});
283 
284   MakeCallerBodyFunction("foo", {"func"},
285                          ast::DecorationList{
286                              Stage(ast::PipelineStage::kFragment),
287                          });
288 
289   Inspector& inspector = Build();
290 
291   auto result = inspector.GetEntryPoints();
292   ASSERT_FALSE(inspector.has_error()) << inspector.error();
293 
294   ASSERT_EQ(1u, result.size());
295   EXPECT_EQ(0u, result[0].input_variables.size());
296   EXPECT_EQ(0u, result[0].output_variables.size());
297 }
298 
TEST_P(InspectorGetEntryPointComponentAndCompositionTest,Test)299 TEST_P(InspectorGetEntryPointComponentAndCompositionTest, Test) {
300   ComponentType component;
301   CompositionType composition;
302   std::tie(component, composition) = GetParam();
303   std::function<const ast::Type*()> tint_type =
304       GetTypeFunction(component, composition);
305 
306   auto* in_var = Param("in_var", tint_type(), {Location(0u)});
307   Func("foo", {in_var}, tint_type(), {Return("in_var")},
308        {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
309   Inspector& inspector = Build();
310 
311   auto result = inspector.GetEntryPoints();
312   ASSERT_FALSE(inspector.has_error()) << inspector.error();
313 
314   ASSERT_EQ(1u, result.size());
315 
316   ASSERT_EQ(1u, result[0].input_variables.size());
317   EXPECT_EQ("in_var", result[0].input_variables[0].name);
318   EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
319   EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
320   EXPECT_EQ(component, result[0].input_variables[0].component_type);
321 
322   ASSERT_EQ(1u, result[0].output_variables.size());
323   EXPECT_EQ("<retval>", result[0].output_variables[0].name);
324   EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
325   EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
326   EXPECT_EQ(component, result[0].output_variables[0].component_type);
327 }
328 INSTANTIATE_TEST_SUITE_P(
329     InspectorGetEntryPointTest,
330     InspectorGetEntryPointComponentAndCompositionTest,
331     testing::Combine(testing::Values(ComponentType::kFloat,
332                                      ComponentType::kSInt,
333                                      ComponentType::kUInt),
334                      testing::Values(CompositionType::kScalar,
335                                      CompositionType::kVec2,
336                                      CompositionType::kVec3,
337                                      CompositionType::kVec4)));
338 
TEST_F(InspectorGetEntryPointTest,MultipleInOutVariables)339 TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) {
340   auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u)});
341   auto* in_var1 = Param("in_var1", ty.u32(), {Location(1u)});
342   auto* in_var4 = Param("in_var4", ty.u32(), {Location(4u)});
343   Func("foo", {in_var0, in_var1, in_var4}, ty.u32(), {Return("in_var0")},
344        {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
345   Inspector& inspector = Build();
346 
347   auto result = inspector.GetEntryPoints();
348   ASSERT_FALSE(inspector.has_error()) << inspector.error();
349 
350   ASSERT_EQ(1u, result.size());
351 
352   ASSERT_EQ(3u, result[0].input_variables.size());
353   EXPECT_EQ("in_var0", result[0].input_variables[0].name);
354   EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
355   EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
356   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
357   EXPECT_EQ("in_var1", result[0].input_variables[1].name);
358   EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
359   EXPECT_EQ(1u, result[0].input_variables[1].location_decoration);
360   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
361   EXPECT_EQ("in_var4", result[0].input_variables[2].name);
362   EXPECT_TRUE(result[0].input_variables[2].has_location_decoration);
363   EXPECT_EQ(4u, result[0].input_variables[2].location_decoration);
364   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
365 
366   ASSERT_EQ(1u, result[0].output_variables.size());
367   EXPECT_EQ("<retval>", result[0].output_variables[0].name);
368   EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
369   EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
370   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
371 }
372 
TEST_F(InspectorGetEntryPointTest,MultipleEntryPointsInOutVariables)373 TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
374   auto* in_var_foo = Param("in_var_foo", ty.u32(), {Location(0u)});
375   Func("foo", {in_var_foo}, ty.u32(), {Return("in_var_foo")},
376        {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
377 
378   auto* in_var_bar = Param("in_var_bar", ty.u32(), {Location(0u)});
379   Func("bar", {in_var_bar}, ty.u32(), {Return("in_var_bar")},
380        {Stage(ast::PipelineStage::kFragment)}, {Location(1u)});
381 
382   Inspector& inspector = Build();
383 
384   auto result = inspector.GetEntryPoints();
385   ASSERT_FALSE(inspector.has_error()) << inspector.error();
386 
387   ASSERT_EQ(2u, result.size());
388 
389   ASSERT_EQ(1u, result[0].input_variables.size());
390   EXPECT_EQ("in_var_foo", result[0].input_variables[0].name);
391   EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
392   EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
393   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
394 
395   ASSERT_EQ(1u, result[0].output_variables.size());
396   EXPECT_EQ("<retval>", result[0].output_variables[0].name);
397   EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
398   EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
399   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
400 
401   ASSERT_EQ(1u, result[1].input_variables.size());
402   EXPECT_EQ("in_var_bar", result[1].input_variables[0].name);
403   EXPECT_TRUE(result[1].input_variables[0].has_location_decoration);
404   EXPECT_EQ(0u, result[1].input_variables[0].location_decoration);
405   EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
406 
407   ASSERT_EQ(1u, result[1].output_variables.size());
408   EXPECT_EQ("<retval>", result[1].output_variables[0].name);
409   EXPECT_TRUE(result[1].output_variables[0].has_location_decoration);
410   EXPECT_EQ(1u, result[1].output_variables[0].location_decoration);
411   EXPECT_EQ(ComponentType::kUInt, result[1].output_variables[0].component_type);
412 }
413 
TEST_F(InspectorGetEntryPointTest,BuiltInsNotStageVariables)414 TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
415   auto* in_var0 =
416       Param("in_var0", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
417   auto* in_var1 = Param("in_var1", ty.f32(), {Location(0u)});
418   Func("foo", {in_var0, in_var1}, ty.f32(), {Return("in_var1")},
419        {Stage(ast::PipelineStage::kFragment)},
420        {Builtin(ast::Builtin::kFragDepth)});
421   Inspector& inspector = Build();
422 
423   auto result = inspector.GetEntryPoints();
424   ASSERT_FALSE(inspector.has_error()) << inspector.error();
425 
426   ASSERT_EQ(1u, result.size());
427 
428   ASSERT_EQ(1u, result[0].input_variables.size());
429   EXPECT_EQ("in_var1", result[0].input_variables[0].name);
430   EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
431   EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
432   EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[0].component_type);
433 
434   ASSERT_EQ(0u, result[0].output_variables.size());
435 }
436 
TEST_F(InspectorGetEntryPointTest,InOutStruct)437 TEST_F(InspectorGetEntryPointTest, InOutStruct) {
438   auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
439   Func("foo", {Param("param", ty.Of(interface))}, ty.Of(interface),
440        {Return("param")}, {Stage(ast::PipelineStage::kFragment)});
441   Inspector& inspector = Build();
442 
443   auto result = inspector.GetEntryPoints();
444   ASSERT_FALSE(inspector.has_error()) << inspector.error();
445 
446   ASSERT_EQ(1u, result.size());
447 
448   ASSERT_EQ(2u, result[0].input_variables.size());
449   EXPECT_EQ("param.a", result[0].input_variables[0].name);
450   EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
451   EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
452   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
453   EXPECT_EQ("param.b", result[0].input_variables[1].name);
454   EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
455   EXPECT_EQ(1u, result[0].input_variables[1].location_decoration);
456   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
457 
458   ASSERT_EQ(2u, result[0].output_variables.size());
459   EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
460   EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
461   EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
462   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
463   EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
464   EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
465   EXPECT_EQ(1u, result[0].output_variables[1].location_decoration);
466   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
467 }
468 
TEST_F(InspectorGetEntryPointTest,MultipleEntryPointsInOutSharedStruct)469 TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutSharedStruct) {
470   auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
471   Func("foo", {}, ty.Of(interface), {Return(Construct(ty.Of(interface)))},
472        {Stage(ast::PipelineStage::kFragment)});
473   Func("bar", {Param("param", ty.Of(interface))}, ty.void_(), {},
474        {Stage(ast::PipelineStage::kFragment)});
475   Inspector& inspector = Build();
476 
477   auto result = inspector.GetEntryPoints();
478   ASSERT_FALSE(inspector.has_error()) << inspector.error();
479 
480   ASSERT_EQ(2u, result.size());
481 
482   ASSERT_EQ(0u, result[0].input_variables.size());
483 
484   ASSERT_EQ(2u, result[0].output_variables.size());
485   EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
486   EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
487   EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
488   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
489   EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
490   EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
491   EXPECT_EQ(1u, result[0].output_variables[1].location_decoration);
492   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
493 
494   ASSERT_EQ(2u, result[1].input_variables.size());
495   EXPECT_EQ("param.a", result[1].input_variables[0].name);
496   EXPECT_TRUE(result[1].input_variables[0].has_location_decoration);
497   EXPECT_EQ(0u, result[1].input_variables[0].location_decoration);
498   EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
499   EXPECT_EQ("param.b", result[1].input_variables[1].name);
500   EXPECT_TRUE(result[1].input_variables[1].has_location_decoration);
501   EXPECT_EQ(1u, result[1].input_variables[1].location_decoration);
502   EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[1].component_type);
503 
504   ASSERT_EQ(0u, result[1].output_variables.size());
505 }
506 
TEST_F(InspectorGetEntryPointTest,MixInOutVariablesAndStruct)507 TEST_F(InspectorGetEntryPointTest, MixInOutVariablesAndStruct) {
508   auto* struct_a = MakeInOutStruct("struct_a", {{"a", 0u}, {"b", 1u}});
509   auto* struct_b = MakeInOutStruct("struct_b", {{"a", 2u}});
510   Func("foo",
511        {Param("param_a", ty.Of(struct_a)), Param("param_b", ty.Of(struct_b)),
512         Param("param_c", ty.f32(), {Location(3u)}),
513         Param("param_d", ty.f32(), {Location(4u)})},
514        ty.Of(struct_a), {Return("param_a")},
515        {Stage(ast::PipelineStage::kFragment)});
516   Inspector& inspector = Build();
517 
518   auto result = inspector.GetEntryPoints();
519   ASSERT_FALSE(inspector.has_error()) << inspector.error();
520 
521   ASSERT_EQ(1u, result.size());
522 
523   ASSERT_EQ(5u, result[0].input_variables.size());
524   EXPECT_EQ("param_a.a", result[0].input_variables[0].name);
525   EXPECT_TRUE(result[0].input_variables[0].has_location_decoration);
526   EXPECT_EQ(0u, result[0].input_variables[0].location_decoration);
527   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
528   EXPECT_EQ("param_a.b", result[0].input_variables[1].name);
529   EXPECT_TRUE(result[0].input_variables[1].has_location_decoration);
530   EXPECT_EQ(1u, result[0].input_variables[1].location_decoration);
531   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
532   EXPECT_EQ("param_b.a", result[0].input_variables[2].name);
533   EXPECT_TRUE(result[0].input_variables[2].has_location_decoration);
534   EXPECT_EQ(2u, result[0].input_variables[2].location_decoration);
535   EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
536   EXPECT_EQ("param_c", result[0].input_variables[3].name);
537   EXPECT_TRUE(result[0].input_variables[3].has_location_decoration);
538   EXPECT_EQ(3u, result[0].input_variables[3].location_decoration);
539   EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[3].component_type);
540   EXPECT_EQ("param_d", result[0].input_variables[4].name);
541   EXPECT_TRUE(result[0].input_variables[4].has_location_decoration);
542   EXPECT_EQ(4u, result[0].input_variables[4].location_decoration);
543   EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[4].component_type);
544 
545   ASSERT_EQ(2u, result[0].output_variables.size());
546   EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
547   EXPECT_TRUE(result[0].output_variables[0].has_location_decoration);
548   EXPECT_EQ(0u, result[0].output_variables[0].location_decoration);
549   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
550   EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
551   EXPECT_TRUE(result[0].output_variables[1].has_location_decoration);
552   EXPECT_EQ(1u, result[0].output_variables[1].location_decoration);
553   EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
554 }
555 
TEST_F(InspectorGetEntryPointTest,OverridableConstantUnreferenced)556 TEST_F(InspectorGetEntryPointTest, OverridableConstantUnreferenced) {
557   AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
558   MakeEmptyBodyFunction(
559       "ep_func", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
560 
561   Inspector& inspector = Build();
562 
563   auto result = inspector.GetEntryPoints();
564 
565   ASSERT_EQ(1u, result.size());
566   EXPECT_EQ(0u, result[0].overridable_constants.size());
567 }
568 
TEST_F(InspectorGetEntryPointTest,OverridableConstantReferencedByEntryPoint)569 TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByEntryPoint) {
570   AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
571   MakePlainGlobalReferenceBodyFunction(
572       "ep_func", "foo", ty.f32(),
573       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
574 
575   Inspector& inspector = Build();
576 
577   auto result = inspector.GetEntryPoints();
578 
579   ASSERT_EQ(1u, result.size());
580   ASSERT_EQ(1u, result[0].overridable_constants.size());
581   EXPECT_EQ("foo", result[0].overridable_constants[0].name);
582 }
583 
TEST_F(InspectorGetEntryPointTest,OverridableConstantReferencedByCallee)584 TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByCallee) {
585   AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
586   MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
587   MakeCallerBodyFunction(
588       "ep_func", {"callee_func"},
589       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
590 
591   Inspector& inspector = Build();
592 
593   auto result = inspector.GetEntryPoints();
594 
595   ASSERT_EQ(1u, result.size());
596   ASSERT_EQ(1u, result[0].overridable_constants.size());
597   EXPECT_EQ("foo", result[0].overridable_constants[0].name);
598 }
599 
TEST_F(InspectorGetEntryPointTest,OverridableConstantSomeReferenced)600 TEST_F(InspectorGetEntryPointTest, OverridableConstantSomeReferenced) {
601   AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
602   AddOverridableConstantWithID("bar", 2, ty.f32(), nullptr);
603   MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
604   MakeCallerBodyFunction(
605       "ep_func", {"callee_func"},
606       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
607 
608   Inspector& inspector = Build();
609 
610   auto result = inspector.GetEntryPoints();
611 
612   ASSERT_EQ(1u, result.size());
613   ASSERT_EQ(1u, result[0].overridable_constants.size());
614   EXPECT_EQ("foo", result[0].overridable_constants[0].name);
615   EXPECT_EQ(1, result[0].overridable_constants[0].numeric_id);
616 }
617 
TEST_F(InspectorGetEntryPointTest,OverridableConstantTypes)618 TEST_F(InspectorGetEntryPointTest, OverridableConstantTypes) {
619   AddOverridableConstantWithoutID("bool_var", ty.bool_(), nullptr);
620   AddOverridableConstantWithoutID("float_var", ty.f32(), nullptr);
621   AddOverridableConstantWithoutID("u32_var", ty.u32(), nullptr);
622   AddOverridableConstantWithoutID("i32_var", ty.i32(), nullptr);
623 
624   MakePlainGlobalReferenceBodyFunction("bool_func", "bool_var", ty.bool_(), {});
625   MakePlainGlobalReferenceBodyFunction("float_func", "float_var", ty.f32(), {});
626   MakePlainGlobalReferenceBodyFunction("u32_func", "u32_var", ty.u32(), {});
627   MakePlainGlobalReferenceBodyFunction("i32_func", "i32_var", ty.i32(), {});
628 
629   MakeCallerBodyFunction(
630       "ep_func", {"bool_func", "float_func", "u32_func", "i32_func"},
631       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
632 
633   Inspector& inspector = Build();
634 
635   auto result = inspector.GetEntryPoints();
636 
637   ASSERT_EQ(1u, result.size());
638   ASSERT_EQ(4u, result[0].overridable_constants.size());
639   EXPECT_EQ("bool_var", result[0].overridable_constants[0].name);
640   EXPECT_EQ(inspector::OverridableConstant::Type::kBool,
641             result[0].overridable_constants[0].type);
642   EXPECT_EQ("float_var", result[0].overridable_constants[1].name);
643   EXPECT_EQ(inspector::OverridableConstant::Type::kFloat32,
644             result[0].overridable_constants[1].type);
645   EXPECT_EQ("u32_var", result[0].overridable_constants[2].name);
646   EXPECT_EQ(inspector::OverridableConstant::Type::kUint32,
647             result[0].overridable_constants[2].type);
648   EXPECT_EQ("i32_var", result[0].overridable_constants[3].name);
649   EXPECT_EQ(inspector::OverridableConstant::Type::kInt32,
650             result[0].overridable_constants[3].type);
651 }
652 
TEST_F(InspectorGetEntryPointTest,OverridableConstantInitialized)653 TEST_F(InspectorGetEntryPointTest, OverridableConstantInitialized) {
654   AddOverridableConstantWithoutID("foo", ty.f32(), Expr(0.0f));
655   MakePlainGlobalReferenceBodyFunction(
656       "ep_func", "foo", ty.f32(),
657       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
658 
659   Inspector& inspector = Build();
660 
661   auto result = inspector.GetEntryPoints();
662 
663   ASSERT_EQ(1u, result.size());
664   ASSERT_EQ(1u, result[0].overridable_constants.size());
665   EXPECT_EQ("foo", result[0].overridable_constants[0].name);
666   EXPECT_TRUE(result[0].overridable_constants[0].is_initialized);
667 }
668 
TEST_F(InspectorGetEntryPointTest,OverridableConstantUninitialized)669 TEST_F(InspectorGetEntryPointTest, OverridableConstantUninitialized) {
670   AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
671   MakePlainGlobalReferenceBodyFunction(
672       "ep_func", "foo", ty.f32(),
673       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
674 
675   Inspector& inspector = Build();
676 
677   auto result = inspector.GetEntryPoints();
678 
679   ASSERT_EQ(1u, result.size());
680   ASSERT_EQ(1u, result[0].overridable_constants.size());
681   EXPECT_EQ("foo", result[0].overridable_constants[0].name);
682 
683   EXPECT_FALSE(result[0].overridable_constants[0].is_initialized);
684 }
685 
TEST_F(InspectorGetEntryPointTest,OverridableConstantNumericIDSpecified)686 TEST_F(InspectorGetEntryPointTest, OverridableConstantNumericIDSpecified) {
687   AddOverridableConstantWithoutID("foo_no_id", ty.f32(), nullptr);
688   AddOverridableConstantWithID("foo_id", 1234, ty.f32(), nullptr);
689 
690   MakePlainGlobalReferenceBodyFunction("no_id_func", "foo_no_id", ty.f32(), {});
691   MakePlainGlobalReferenceBodyFunction("id_func", "foo_id", ty.f32(), {});
692 
693   MakeCallerBodyFunction(
694       "ep_func", {"no_id_func", "id_func"},
695       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
696 
697   Inspector& inspector = Build();
698 
699   auto result = inspector.GetEntryPoints();
700 
701   ASSERT_EQ(1u, result.size());
702   ASSERT_EQ(2u, result[0].overridable_constants.size());
703   EXPECT_EQ("foo_no_id", result[0].overridable_constants[0].name);
704   EXPECT_EQ("foo_id", result[0].overridable_constants[1].name);
705   EXPECT_EQ(1234, result[0].overridable_constants[1].numeric_id);
706 
707   EXPECT_FALSE(result[0].overridable_constants[0].is_numeric_id_specified);
708   EXPECT_TRUE(result[0].overridable_constants[1].is_numeric_id_specified);
709 }
710 
TEST_F(InspectorGetEntryPointTest,NonOverridableConstantSkipped)711 TEST_F(InspectorGetEntryPointTest, NonOverridableConstantSkipped) {
712   auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
713   AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
714   MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
715   MakeCallerBodyFunction("ep_func", {"ub_func"},
716                          {Stage(ast::PipelineStage::kFragment)});
717 
718   Inspector& inspector = Build();
719 
720   auto result = inspector.GetEntryPoints();
721 
722   ASSERT_EQ(1u, result.size());
723   EXPECT_EQ(0u, result[0].overridable_constants.size());
724 }
725 
TEST_F(InspectorGetEntryPointTest,BuiltinNotReferenced)726 TEST_F(InspectorGetEntryPointTest, BuiltinNotReferenced) {
727   MakeEmptyBodyFunction("ep_func", {Stage(ast::PipelineStage::kFragment)});
728 
729   Inspector& inspector = Build();
730 
731   auto result = inspector.GetEntryPoints();
732 
733   ASSERT_EQ(1u, result.size());
734   EXPECT_FALSE(result[0].input_sample_mask_used);
735   EXPECT_FALSE(result[0].output_sample_mask_used);
736   EXPECT_FALSE(result[0].input_position_used);
737   EXPECT_FALSE(result[0].front_facing_used);
738   EXPECT_FALSE(result[0].sample_index_used);
739   EXPECT_FALSE(result[0].num_workgroups_used);
740 }
741 
TEST_F(InspectorGetEntryPointTest,InputSampleMaskSimpleReferenced)742 TEST_F(InspectorGetEntryPointTest, InputSampleMaskSimpleReferenced) {
743   auto* in_var =
744       Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
745   Func("ep_func", {in_var}, ty.void_(), {Return()},
746        {Stage(ast::PipelineStage::kFragment)}, {});
747 
748   Inspector& inspector = Build();
749 
750   auto result = inspector.GetEntryPoints();
751 
752   ASSERT_EQ(1u, result.size());
753   EXPECT_TRUE(result[0].input_sample_mask_used);
754 }
755 
TEST_F(InspectorGetEntryPointTest,InputSampleMaskStructReferenced)756 TEST_F(InspectorGetEntryPointTest, InputSampleMaskStructReferenced) {
757   ast::StructMemberList members;
758   members.push_back(
759       Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}));
760   Structure("in_struct", members, {});
761   auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
762 
763   Func("ep_func", {in_var}, ty.void_(), {Return()},
764        {Stage(ast::PipelineStage::kFragment)}, {});
765 
766   Inspector& inspector = Build();
767 
768   auto result = inspector.GetEntryPoints();
769 
770   ASSERT_EQ(1u, result.size());
771   EXPECT_TRUE(result[0].input_sample_mask_used);
772 }
773 
TEST_F(InspectorGetEntryPointTest,OutputSampleMaskSimpleReferenced)774 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskSimpleReferenced) {
775   auto* in_var =
776       Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
777   Func("ep_func", {in_var}, ty.u32(), {Return("in_var")},
778        {Stage(ast::PipelineStage::kFragment)},
779        {Builtin(ast::Builtin::kSampleMask)});
780 
781   Inspector& inspector = Build();
782 
783   auto result = inspector.GetEntryPoints();
784 
785   ASSERT_EQ(1u, result.size());
786   EXPECT_TRUE(result[0].output_sample_mask_used);
787 }
788 
TEST_F(InspectorGetEntryPointTest,OutputSampleMaskStructReferenced)789 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskStructReferenced) {
790   ast::StructMemberList members;
791   members.push_back(Member("inner_sample_mask", ty.u32(),
792                            {Builtin(ast::Builtin::kSampleMask)}));
793   Structure("out_struct", members, {});
794 
795   Func("ep_func", {}, ty.type_name("out_struct"),
796        {Decl(Var("out_var", ty.type_name("out_struct"))), Return("out_var")},
797        {Stage(ast::PipelineStage::kFragment)}, {});
798 
799   Inspector& inspector = Build();
800 
801   auto result = inspector.GetEntryPoints();
802 
803   ASSERT_EQ(1u, result.size());
804   EXPECT_TRUE(result[0].output_sample_mask_used);
805 }
806 
TEST_F(InspectorGetEntryPointTest,InputPositionSimpleReferenced)807 TEST_F(InspectorGetEntryPointTest, InputPositionSimpleReferenced) {
808   auto* in_var =
809       Param("in_var", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
810   Func("ep_func", {in_var}, ty.void_(), {Return()},
811        {Stage(ast::PipelineStage::kFragment)}, {});
812 
813   Inspector& inspector = Build();
814 
815   auto result = inspector.GetEntryPoints();
816 
817   ASSERT_EQ(1u, result.size());
818   EXPECT_TRUE(result[0].input_position_used);
819 }
820 
TEST_F(InspectorGetEntryPointTest,InputPositionStructReferenced)821 TEST_F(InspectorGetEntryPointTest, InputPositionStructReferenced) {
822   ast::StructMemberList members;
823   members.push_back(Member("inner_position", ty.vec4<f32>(),
824                            {Builtin(ast::Builtin::kPosition)}));
825   Structure("in_struct", members, {});
826   auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
827 
828   Func("ep_func", {in_var}, ty.void_(), {Return()},
829        {Stage(ast::PipelineStage::kFragment)}, {});
830 
831   Inspector& inspector = Build();
832 
833   auto result = inspector.GetEntryPoints();
834 
835   ASSERT_EQ(1u, result.size());
836   EXPECT_TRUE(result[0].input_position_used);
837 }
838 
TEST_F(InspectorGetEntryPointTest,FrontFacingSimpleReferenced)839 TEST_F(InspectorGetEntryPointTest, FrontFacingSimpleReferenced) {
840   auto* in_var =
841       Param("in_var", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)});
842   Func("ep_func", {in_var}, ty.void_(), {Return()},
843        {Stage(ast::PipelineStage::kFragment)}, {});
844 
845   Inspector& inspector = Build();
846 
847   auto result = inspector.GetEntryPoints();
848 
849   ASSERT_EQ(1u, result.size());
850   EXPECT_TRUE(result[0].front_facing_used);
851 }
852 
TEST_F(InspectorGetEntryPointTest,FrontFacingStructReferenced)853 TEST_F(InspectorGetEntryPointTest, FrontFacingStructReferenced) {
854   ast::StructMemberList members;
855   members.push_back(Member("inner_position", ty.bool_(),
856                            {Builtin(ast::Builtin::kFrontFacing)}));
857   Structure("in_struct", members, {});
858   auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
859 
860   Func("ep_func", {in_var}, ty.void_(), {Return()},
861        {Stage(ast::PipelineStage::kFragment)}, {});
862 
863   Inspector& inspector = Build();
864 
865   auto result = inspector.GetEntryPoints();
866 
867   ASSERT_EQ(1u, result.size());
868   EXPECT_TRUE(result[0].front_facing_used);
869 }
870 
TEST_F(InspectorGetEntryPointTest,SampleIndexSimpleReferenced)871 TEST_F(InspectorGetEntryPointTest, SampleIndexSimpleReferenced) {
872   auto* in_var =
873       Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
874   Func("ep_func", {in_var}, ty.void_(), {Return()},
875        {Stage(ast::PipelineStage::kFragment)}, {});
876 
877   Inspector& inspector = Build();
878 
879   auto result = inspector.GetEntryPoints();
880 
881   ASSERT_EQ(1u, result.size());
882   EXPECT_TRUE(result[0].sample_index_used);
883 }
884 
TEST_F(InspectorGetEntryPointTest,SampleIndexStructReferenced)885 TEST_F(InspectorGetEntryPointTest, SampleIndexStructReferenced) {
886   ast::StructMemberList members;
887   members.push_back(Member("inner_position", ty.u32(),
888                            {Builtin(ast::Builtin::kSampleIndex)}));
889   Structure("in_struct", members, {});
890   auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
891 
892   Func("ep_func", {in_var}, ty.void_(), {Return()},
893        {Stage(ast::PipelineStage::kFragment)}, {});
894 
895   Inspector& inspector = Build();
896 
897   auto result = inspector.GetEntryPoints();
898 
899   ASSERT_EQ(1u, result.size());
900   EXPECT_TRUE(result[0].sample_index_used);
901 }
902 
TEST_F(InspectorGetEntryPointTest,NumWorkgroupsSimpleReferenced)903 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsSimpleReferenced) {
904   auto* in_var =
905       Param("in_var", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)});
906   Func("ep_func", {in_var}, ty.void_(), {Return()},
907        {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)}, {});
908 
909   Inspector& inspector = Build();
910 
911   auto result = inspector.GetEntryPoints();
912 
913   ASSERT_EQ(1u, result.size());
914   EXPECT_TRUE(result[0].num_workgroups_used);
915 }
916 
TEST_F(InspectorGetEntryPointTest,NumWorkgroupsStructReferenced)917 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsStructReferenced) {
918   ast::StructMemberList members;
919   members.push_back(Member("inner_position", ty.vec3<u32>(),
920                            {Builtin(ast::Builtin::kNumWorkgroups)}));
921   Structure("in_struct", members, {});
922   auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
923 
924   Func("ep_func", {in_var}, ty.void_(), {Return()},
925        {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)}, {});
926 
927   Inspector& inspector = Build();
928 
929   auto result = inspector.GetEntryPoints();
930 
931   ASSERT_EQ(1u, result.size());
932   EXPECT_TRUE(result[0].num_workgroups_used);
933 }
934 
TEST_F(InspectorGetEntryPointTest,ImplicitInterpolate)935 TEST_F(InspectorGetEntryPointTest, ImplicitInterpolate) {
936   ast::StructMemberList members;
937   members.push_back(Member("struct_inner", ty.f32(), {Location(0)}));
938   Structure("in_struct", members, {});
939   auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
940 
941   Func("ep_func", {in_var}, ty.void_(), {Return()},
942        {Stage(ast::PipelineStage::kFragment)}, {});
943 
944   Inspector& inspector = Build();
945 
946   auto result = inspector.GetEntryPoints();
947 
948   ASSERT_EQ(1u, result.size());
949   ASSERT_EQ(1u, result[0].input_variables.size());
950   EXPECT_EQ(InterpolationType::kPerspective,
951             result[0].input_variables[0].interpolation_type);
952   EXPECT_EQ(InterpolationSampling::kCenter,
953             result[0].input_variables[0].interpolation_sampling);
954 }
955 
TEST_P(InspectorGetEntryPointInterpolateTest,Test)956 TEST_P(InspectorGetEntryPointInterpolateTest, Test) {
957   auto& params = GetParam();
958   ast::StructMemberList members;
959   members.push_back(
960       Member("struct_inner", ty.f32(),
961              {Interpolate(params.in_type, params.in_sampling), Location(0)}));
962   Structure("in_struct", members, {});
963   auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
964 
965   Func("ep_func", {in_var}, ty.void_(), {Return()},
966        {Stage(ast::PipelineStage::kFragment)}, {});
967 
968   Inspector& inspector = Build();
969 
970   auto result = inspector.GetEntryPoints();
971 
972   ASSERT_EQ(1u, result.size());
973   ASSERT_EQ(1u, result[0].input_variables.size());
974   EXPECT_EQ(params.out_type, result[0].input_variables[0].interpolation_type);
975   EXPECT_EQ(params.out_sampling,
976             result[0].input_variables[0].interpolation_sampling);
977 }
978 
979 INSTANTIATE_TEST_SUITE_P(
980     InspectorGetEntryPointTest,
981     InspectorGetEntryPointInterpolateTest,
982     testing::Values(
983         InspectorGetEntryPointInterpolateTestParams{
984             ast::InterpolationType::kPerspective,
985             ast::InterpolationSampling::kCenter,
986             InterpolationType::kPerspective, InterpolationSampling::kCenter},
987         InspectorGetEntryPointInterpolateTestParams{
988             ast::InterpolationType::kPerspective,
989             ast::InterpolationSampling::kCentroid,
990             InterpolationType::kPerspective, InterpolationSampling::kCentroid},
991         InspectorGetEntryPointInterpolateTestParams{
992             ast::InterpolationType::kPerspective,
993             ast::InterpolationSampling::kSample,
994             InterpolationType::kPerspective, InterpolationSampling::kSample},
995         InspectorGetEntryPointInterpolateTestParams{
996             ast::InterpolationType::kPerspective,
997             ast::InterpolationSampling::kNone, InterpolationType::kPerspective,
998             InterpolationSampling::kCenter},
999         InspectorGetEntryPointInterpolateTestParams{
1000             ast::InterpolationType::kLinear,
1001             ast::InterpolationSampling::kCenter, InterpolationType::kLinear,
1002             InterpolationSampling::kCenter},
1003         InspectorGetEntryPointInterpolateTestParams{
1004             ast::InterpolationType::kLinear,
1005             ast::InterpolationSampling::kCentroid, InterpolationType::kLinear,
1006             InterpolationSampling::kCentroid},
1007         InspectorGetEntryPointInterpolateTestParams{
1008             ast::InterpolationType::kLinear,
1009             ast::InterpolationSampling::kSample, InterpolationType::kLinear,
1010             InterpolationSampling::kSample},
1011         InspectorGetEntryPointInterpolateTestParams{
1012             ast::InterpolationType::kLinear, ast::InterpolationSampling::kNone,
1013             InterpolationType::kLinear, InterpolationSampling::kCenter},
1014         InspectorGetEntryPointInterpolateTestParams{
1015             ast::InterpolationType::kFlat, ast::InterpolationSampling::kNone,
1016             InterpolationType::kFlat, InterpolationSampling::kNone}));
1017 
1018 // TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
1019 // through
TEST_F(InspectorGetRemappedNameForEntryPointTest,DISABLED_NoFunctions)1020 TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoFunctions) {
1021   Inspector& inspector = Build();
1022 
1023   auto result = inspector.GetRemappedNameForEntryPoint("foo");
1024   ASSERT_TRUE(inspector.has_error());
1025 
1026   EXPECT_EQ("", result);
1027 }
1028 
1029 // TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
1030 // through
TEST_F(InspectorGetRemappedNameForEntryPointTest,DISABLED_NoEntryPoints)1031 TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoEntryPoints) {
1032   Inspector& inspector = Build();
1033 
1034   auto result = inspector.GetRemappedNameForEntryPoint("foo");
1035   ASSERT_TRUE(inspector.has_error());
1036 
1037   EXPECT_EQ("", result);
1038 }
1039 
1040 // TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
1041 // through
TEST_F(InspectorGetRemappedNameForEntryPointTest,DISABLED_OneEntryPoint)1042 TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_OneEntryPoint) {
1043   MakeEmptyBodyFunction("foo", ast::DecorationList{
1044                                    Stage(ast::PipelineStage::kVertex),
1045                                });
1046 
1047   // TODO(dsinclair): Update to run the namer transform when
1048   // available.
1049 
1050   Inspector& inspector = Build();
1051 
1052   auto result = inspector.GetRemappedNameForEntryPoint("foo");
1053   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1054 
1055   EXPECT_EQ("foo", result);
1056 }
1057 
1058 // TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
1059 // through
TEST_F(InspectorGetRemappedNameForEntryPointTest,DISABLED_MultipleEntryPoints)1060 TEST_F(InspectorGetRemappedNameForEntryPointTest,
1061        DISABLED_MultipleEntryPoints) {
1062   MakeEmptyBodyFunction("foo", ast::DecorationList{
1063                                    Stage(ast::PipelineStage::kVertex),
1064                                });
1065 
1066   // TODO(dsinclair): Update to run the namer transform when
1067   // available.
1068 
1069   MakeEmptyBodyFunction("bar",
1070                         ast::DecorationList{Stage(ast::PipelineStage::kCompute),
1071                                             WorkgroupSize(1)});
1072 
1073   Inspector& inspector = Build();
1074 
1075   {
1076     auto result = inspector.GetRemappedNameForEntryPoint("foo");
1077     ASSERT_FALSE(inspector.has_error()) << inspector.error();
1078     EXPECT_EQ("foo", result);
1079   }
1080   {
1081     auto result = inspector.GetRemappedNameForEntryPoint("bar");
1082     ASSERT_FALSE(inspector.has_error()) << inspector.error();
1083     EXPECT_EQ("bar", result);
1084   }
1085 }
1086 
TEST_F(InspectorGetConstantIDsTest,Bool)1087 TEST_F(InspectorGetConstantIDsTest, Bool) {
1088   AddOverridableConstantWithID("foo", 1, ty.bool_(), nullptr);
1089   AddOverridableConstantWithID("bar", 20, ty.bool_(), Expr(true));
1090   AddOverridableConstantWithID("baz", 300, ty.bool_(), Expr(false));
1091 
1092   Inspector& inspector = Build();
1093 
1094   auto result = inspector.GetConstantIDs();
1095   ASSERT_EQ(3u, result.size());
1096 
1097   ASSERT_TRUE(result.find(1) != result.end());
1098   EXPECT_TRUE(result[1].IsNull());
1099 
1100   ASSERT_TRUE(result.find(20) != result.end());
1101   EXPECT_TRUE(result[20].IsBool());
1102   EXPECT_TRUE(result[20].AsBool());
1103 
1104   ASSERT_TRUE(result.find(300) != result.end());
1105   EXPECT_TRUE(result[300].IsBool());
1106   EXPECT_FALSE(result[300].AsBool());
1107 }
1108 
TEST_F(InspectorGetConstantIDsTest,U32)1109 TEST_F(InspectorGetConstantIDsTest, U32) {
1110   AddOverridableConstantWithID("foo", 1, ty.u32(), nullptr);
1111   AddOverridableConstantWithID("bar", 20, ty.u32(), Expr(42u));
1112 
1113   Inspector& inspector = Build();
1114 
1115   auto result = inspector.GetConstantIDs();
1116   ASSERT_EQ(2u, result.size());
1117 
1118   ASSERT_TRUE(result.find(1) != result.end());
1119   EXPECT_TRUE(result[1].IsNull());
1120 
1121   ASSERT_TRUE(result.find(20) != result.end());
1122   EXPECT_TRUE(result[20].IsU32());
1123   EXPECT_EQ(42u, result[20].AsU32());
1124 }
1125 
TEST_F(InspectorGetConstantIDsTest,I32)1126 TEST_F(InspectorGetConstantIDsTest, I32) {
1127   AddOverridableConstantWithID("foo", 1, ty.i32(), nullptr);
1128   AddOverridableConstantWithID("bar", 20, ty.i32(), Expr(-42));
1129   AddOverridableConstantWithID("baz", 300, ty.i32(), Expr(42));
1130 
1131   Inspector& inspector = Build();
1132 
1133   auto result = inspector.GetConstantIDs();
1134   ASSERT_EQ(3u, result.size());
1135 
1136   ASSERT_TRUE(result.find(1) != result.end());
1137   EXPECT_TRUE(result[1].IsNull());
1138 
1139   ASSERT_TRUE(result.find(20) != result.end());
1140   EXPECT_TRUE(result[20].IsI32());
1141   EXPECT_EQ(-42, result[20].AsI32());
1142 
1143   ASSERT_TRUE(result.find(300) != result.end());
1144   EXPECT_TRUE(result[300].IsI32());
1145   EXPECT_EQ(42, result[300].AsI32());
1146 }
1147 
TEST_F(InspectorGetConstantIDsTest,Float)1148 TEST_F(InspectorGetConstantIDsTest, Float) {
1149   AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
1150   AddOverridableConstantWithID("bar", 20, ty.f32(), Expr(0.0f));
1151   AddOverridableConstantWithID("baz", 300, ty.f32(), Expr(-10.0f));
1152   AddOverridableConstantWithID("x", 4000, ty.f32(), Expr(15.0f));
1153 
1154   Inspector& inspector = Build();
1155 
1156   auto result = inspector.GetConstantIDs();
1157   ASSERT_EQ(4u, result.size());
1158 
1159   ASSERT_TRUE(result.find(1) != result.end());
1160   EXPECT_TRUE(result[1].IsNull());
1161 
1162   ASSERT_TRUE(result.find(20) != result.end());
1163   EXPECT_TRUE(result[20].IsFloat());
1164   EXPECT_FLOAT_EQ(0.0, result[20].AsFloat());
1165 
1166   ASSERT_TRUE(result.find(300) != result.end());
1167   EXPECT_TRUE(result[300].IsFloat());
1168   EXPECT_FLOAT_EQ(-10.0, result[300].AsFloat());
1169 
1170   ASSERT_TRUE(result.find(4000) != result.end());
1171   EXPECT_TRUE(result[4000].IsFloat());
1172   EXPECT_FLOAT_EQ(15.0, result[4000].AsFloat());
1173 }
1174 
TEST_F(InspectorGetConstantNameToIdMapTest,WithAndWithoutIds)1175 TEST_F(InspectorGetConstantNameToIdMapTest, WithAndWithoutIds) {
1176   AddOverridableConstantWithID("v1", 1, ty.f32(), nullptr);
1177   AddOverridableConstantWithID("v20", 20, ty.f32(), nullptr);
1178   AddOverridableConstantWithID("v300", 300, ty.f32(), nullptr);
1179   auto* a = AddOverridableConstantWithoutID("a", ty.f32(), nullptr);
1180   auto* b = AddOverridableConstantWithoutID("b", ty.f32(), nullptr);
1181   auto* c = AddOverridableConstantWithoutID("c", ty.f32(), nullptr);
1182 
1183   Inspector& inspector = Build();
1184 
1185   auto result = inspector.GetConstantNameToIdMap();
1186   ASSERT_EQ(6u, result.size());
1187 
1188   ASSERT_TRUE(result.count("v1"));
1189   EXPECT_EQ(result["v1"], 1u);
1190 
1191   ASSERT_TRUE(result.count("v20"));
1192   EXPECT_EQ(result["v20"], 20u);
1193 
1194   ASSERT_TRUE(result.count("v300"));
1195   EXPECT_EQ(result["v300"], 300u);
1196 
1197   ASSERT_TRUE(result.count("a"));
1198   ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(a));
1199   EXPECT_EQ(result["a"],
1200             program_->Sem().Get<sem::GlobalVariable>(a)->ConstantId());
1201 
1202   ASSERT_TRUE(result.count("b"));
1203   ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(b));
1204   EXPECT_EQ(result["b"],
1205             program_->Sem().Get<sem::GlobalVariable>(b)->ConstantId());
1206 
1207   ASSERT_TRUE(result.count("c"));
1208   ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(c));
1209   EXPECT_EQ(result["c"],
1210             program_->Sem().Get<sem::GlobalVariable>(c)->ConstantId());
1211 }
1212 
TEST_F(InspectorGetStorageSizeTest,Empty)1213 TEST_F(InspectorGetStorageSizeTest, Empty) {
1214   MakeEmptyBodyFunction("ep_func",
1215                         ast::DecorationList{Stage(ast::PipelineStage::kCompute),
1216                                             WorkgroupSize(1)});
1217   Inspector& inspector = Build();
1218   EXPECT_EQ(0u, inspector.GetStorageSize("ep_func"));
1219 }
1220 
TEST_F(InspectorGetStorageSizeTest,Simple)1221 TEST_F(InspectorGetStorageSizeTest, Simple) {
1222   auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32(), ty.i32()});
1223   AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
1224   MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
1225 
1226   auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
1227   AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
1228   MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
1229 
1230   auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
1231   AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
1232   MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
1233                                           {{0, ty.i32()}});
1234 
1235   MakeCallerBodyFunction("ep_func", {"ub_func", "sb_func", "rosb_func"},
1236                          ast::DecorationList{
1237                              Stage(ast::PipelineStage::kCompute),
1238                              WorkgroupSize(1),
1239                          });
1240 
1241   Inspector& inspector = Build();
1242 
1243   EXPECT_EQ(16u, inspector.GetStorageSize("ep_func"));
1244 }
1245 
TEST_F(InspectorGetResourceBindingsTest,Empty)1246 TEST_F(InspectorGetResourceBindingsTest, Empty) {
1247   MakeCallerBodyFunction("ep_func", {},
1248                          ast::DecorationList{
1249                              Stage(ast::PipelineStage::kFragment),
1250                          });
1251 
1252   Inspector& inspector = Build();
1253 
1254   auto result = inspector.GetResourceBindings("ep_func");
1255   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1256   ASSERT_EQ(0u, result.size());
1257 }
1258 
TEST_F(InspectorGetResourceBindingsTest,Simple)1259 TEST_F(InspectorGetResourceBindingsTest, Simple) {
1260   auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32()});
1261   AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
1262   MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
1263 
1264   auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
1265   AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
1266   MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
1267 
1268   auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
1269   AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
1270   MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
1271                                           {{0, ty.i32()}});
1272 
1273   auto* s_texture_type =
1274       ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
1275   AddResource("s_texture", s_texture_type, 2, 0);
1276   AddSampler("s_var", 3, 0);
1277   AddGlobalVariable("s_coords", ty.f32());
1278   MakeSamplerReferenceBodyFunction("s_func", "s_texture", "s_var", "s_coords",
1279                                    ty.f32(), {});
1280 
1281   auto* cs_depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
1282   AddResource("cs_texture", cs_depth_texture_type, 3, 1);
1283   AddComparisonSampler("cs_var", 3, 2);
1284   AddGlobalVariable("cs_coords", ty.vec2<f32>());
1285   AddGlobalVariable("cs_depth", ty.f32());
1286   MakeComparisonSamplerReferenceBodyFunction(
1287       "cs_func", "cs_texture", "cs_var", "cs_coords", "cs_depth", ty.f32(), {});
1288 
1289   auto* depth_ms_texture_type =
1290       ty.depth_multisampled_texture(ast::TextureDimension::k2d);
1291   AddResource("depth_ms_texture", depth_ms_texture_type, 3, 3);
1292   Func("depth_ms_func", {}, ty.void_(), {Ignore("depth_ms_texture")});
1293 
1294   auto* st_type = MakeStorageTextureTypes(ast::TextureDimension::k2d,
1295                                           ast::ImageFormat::kR32Uint);
1296   AddStorageTexture("st_var", st_type, 4, 0);
1297   MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), {});
1298 
1299   MakeCallerBodyFunction("ep_func",
1300                          {"ub_func", "sb_func", "rosb_func", "s_func",
1301                           "cs_func", "depth_ms_func", "st_func"},
1302                          ast::DecorationList{
1303                              Stage(ast::PipelineStage::kFragment),
1304                          });
1305 
1306   Inspector& inspector = Build();
1307 
1308   auto result = inspector.GetResourceBindings("ep_func");
1309   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1310   ASSERT_EQ(9u, result.size());
1311 
1312   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1313             result[0].resource_type);
1314   EXPECT_EQ(0u, result[0].bind_group);
1315   EXPECT_EQ(0u, result[0].binding);
1316 
1317   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1318             result[1].resource_type);
1319   EXPECT_EQ(1u, result[1].bind_group);
1320   EXPECT_EQ(0u, result[1].binding);
1321 
1322   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
1323             result[2].resource_type);
1324   EXPECT_EQ(1u, result[2].bind_group);
1325   EXPECT_EQ(1u, result[2].binding);
1326 
1327   EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[3].resource_type);
1328   EXPECT_EQ(3u, result[3].bind_group);
1329   EXPECT_EQ(0u, result[3].binding);
1330 
1331   EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
1332             result[4].resource_type);
1333   EXPECT_EQ(3u, result[4].bind_group);
1334   EXPECT_EQ(2u, result[4].binding);
1335 
1336   EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
1337             result[5].resource_type);
1338   EXPECT_EQ(2u, result[5].bind_group);
1339   EXPECT_EQ(0u, result[5].binding);
1340 
1341   EXPECT_EQ(ResourceBinding::ResourceType::kWriteOnlyStorageTexture,
1342             result[6].resource_type);
1343   EXPECT_EQ(4u, result[6].bind_group);
1344   EXPECT_EQ(0u, result[6].binding);
1345 
1346   EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture,
1347             result[7].resource_type);
1348   EXPECT_EQ(3u, result[7].bind_group);
1349   EXPECT_EQ(1u, result[7].binding);
1350 
1351   EXPECT_EQ(ResourceBinding::ResourceType::kDepthMultisampledTexture,
1352             result[8].resource_type);
1353   EXPECT_EQ(3u, result[8].bind_group);
1354   EXPECT_EQ(3u, result[8].binding);
1355 }
1356 
TEST_F(InspectorGetUniformBufferResourceBindingsTest,MissingEntryPoint)1357 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingEntryPoint) {
1358   Inspector& inspector = Build();
1359 
1360   auto result = inspector.GetUniformBufferResourceBindings("ep_func");
1361   ASSERT_TRUE(inspector.has_error());
1362   std::string error = inspector.error();
1363   EXPECT_TRUE(error.find("not found") != std::string::npos);
1364 }
1365 
TEST_F(InspectorGetUniformBufferResourceBindingsTest,NonEntryPointFunc)1366 TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonEntryPointFunc) {
1367   auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
1368   AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
1369 
1370   MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
1371 
1372   MakeCallerBodyFunction("ep_func", {"ub_func"},
1373                          ast::DecorationList{
1374                              Stage(ast::PipelineStage::kFragment),
1375                          });
1376 
1377   Inspector& inspector = Build();
1378 
1379   auto result = inspector.GetUniformBufferResourceBindings("ub_func");
1380   std::string error = inspector.error();
1381   EXPECT_TRUE(error.find("not an entry point") != std::string::npos);
1382 }
1383 
TEST_F(InspectorGetUniformBufferResourceBindingsTest,Simple)1384 TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple) {
1385   auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
1386   AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
1387 
1388   MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
1389 
1390   MakeCallerBodyFunction("ep_func", {"ub_func"},
1391                          ast::DecorationList{
1392                              Stage(ast::PipelineStage::kFragment),
1393                          });
1394 
1395   Inspector& inspector = Build();
1396 
1397   auto result = inspector.GetUniformBufferResourceBindings("ep_func");
1398   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1399   ASSERT_EQ(1u, result.size());
1400 
1401   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1402             result[0].resource_type);
1403   EXPECT_EQ(0u, result[0].bind_group);
1404   EXPECT_EQ(0u, result[0].binding);
1405   EXPECT_EQ(4u, result[0].size);
1406   EXPECT_EQ(4u, result[0].size_no_padding);
1407 }
1408 
TEST_F(InspectorGetUniformBufferResourceBindingsTest,MultipleMembers)1409 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleMembers) {
1410   auto* foo_struct_type =
1411       MakeUniformBufferType("foo_type", {ty.i32(), ty.u32(), ty.f32()});
1412   AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
1413 
1414   MakeStructVariableReferenceBodyFunction(
1415       "ub_func", "foo_ub", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
1416 
1417   MakeCallerBodyFunction("ep_func", {"ub_func"},
1418                          ast::DecorationList{
1419                              Stage(ast::PipelineStage::kFragment),
1420                          });
1421 
1422   Inspector& inspector = Build();
1423 
1424   auto result = inspector.GetUniformBufferResourceBindings("ep_func");
1425   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1426   ASSERT_EQ(1u, result.size());
1427 
1428   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1429             result[0].resource_type);
1430   EXPECT_EQ(0u, result[0].bind_group);
1431   EXPECT_EQ(0u, result[0].binding);
1432   EXPECT_EQ(12u, result[0].size);
1433   EXPECT_EQ(12u, result[0].size_no_padding);
1434 }
1435 
TEST_F(InspectorGetUniformBufferResourceBindingsTest,ContainingPadding)1436 TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingPadding) {
1437   auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.vec3<f32>()});
1438   AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
1439 
1440   MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
1441                                           {{0, ty.vec3<f32>()}});
1442 
1443   MakeCallerBodyFunction("ep_func", {"ub_func"},
1444                          ast::DecorationList{
1445                              Stage(ast::PipelineStage::kFragment),
1446                          });
1447 
1448   Inspector& inspector = Build();
1449 
1450   auto result = inspector.GetUniformBufferResourceBindings("ep_func");
1451   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1452   ASSERT_EQ(1u, result.size());
1453 
1454   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1455             result[0].resource_type);
1456   EXPECT_EQ(0u, result[0].bind_group);
1457   EXPECT_EQ(0u, result[0].binding);
1458   EXPECT_EQ(16u, result[0].size);
1459   EXPECT_EQ(12u, result[0].size_no_padding);
1460 }
1461 
TEST_F(InspectorGetUniformBufferResourceBindingsTest,MultipleUniformBuffers)1462 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleUniformBuffers) {
1463   auto* ub_struct_type =
1464       MakeUniformBufferType("ub_type", {ty.i32(), ty.u32(), ty.f32()});
1465   AddUniformBuffer("ub_foo", ty.Of(ub_struct_type), 0, 0);
1466   AddUniformBuffer("ub_bar", ty.Of(ub_struct_type), 0, 1);
1467   AddUniformBuffer("ub_baz", ty.Of(ub_struct_type), 2, 0);
1468 
1469   auto AddReferenceFunc = [this](const std::string& func_name,
1470                                  const std::string& var_name) {
1471     MakeStructVariableReferenceBodyFunction(
1472         func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
1473   };
1474   AddReferenceFunc("ub_foo_func", "ub_foo");
1475   AddReferenceFunc("ub_bar_func", "ub_bar");
1476   AddReferenceFunc("ub_baz_func", "ub_baz");
1477 
1478   auto FuncCall = [&](const std::string& callee) {
1479     return create<ast::CallStatement>(Call(callee));
1480   };
1481 
1482   Func("ep_func", ast::VariableList(), ty.void_(),
1483        ast::StatementList{FuncCall("ub_foo_func"), FuncCall("ub_bar_func"),
1484                           FuncCall("ub_baz_func"), Return()},
1485        ast::DecorationList{
1486            Stage(ast::PipelineStage::kFragment),
1487        });
1488 
1489   Inspector& inspector = Build();
1490 
1491   auto result = inspector.GetUniformBufferResourceBindings("ep_func");
1492   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1493   ASSERT_EQ(3u, result.size());
1494 
1495   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1496             result[0].resource_type);
1497   EXPECT_EQ(0u, result[0].bind_group);
1498   EXPECT_EQ(0u, result[0].binding);
1499   EXPECT_EQ(12u, result[0].size);
1500   EXPECT_EQ(12u, result[0].size_no_padding);
1501 
1502   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1503             result[1].resource_type);
1504   EXPECT_EQ(0u, result[1].bind_group);
1505   EXPECT_EQ(1u, result[1].binding);
1506   EXPECT_EQ(12u, result[1].size);
1507   EXPECT_EQ(12u, result[1].size_no_padding);
1508 
1509   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1510             result[2].resource_type);
1511   EXPECT_EQ(2u, result[2].bind_group);
1512   EXPECT_EQ(0u, result[2].binding);
1513   EXPECT_EQ(12u, result[2].size);
1514   EXPECT_EQ(12u, result[2].size_no_padding);
1515 }
1516 
TEST_F(InspectorGetUniformBufferResourceBindingsTest,ContainingArray)1517 TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
1518   // Manually create uniform buffer to make sure it had a valid layout (array
1519   // with elem stride of 16, and that is 16-byte aligned within the struct)
1520   auto* foo_struct_type = Structure(
1521       "foo_type",
1522       {Member("0i32", ty.i32()),
1523        Member("b", ty.array(ty.u32(), 4, /*stride*/ 16), {MemberAlign(16)})},
1524       {create<ast::StructBlockDecoration>()});
1525 
1526   AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
1527 
1528   MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
1529 
1530   MakeCallerBodyFunction("ep_func", {"ub_func"},
1531                          ast::DecorationList{
1532                              Stage(ast::PipelineStage::kFragment),
1533                          });
1534 
1535   Inspector& inspector = Build();
1536 
1537   auto result = inspector.GetUniformBufferResourceBindings("ep_func");
1538   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1539   ASSERT_EQ(1u, result.size());
1540 
1541   EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
1542             result[0].resource_type);
1543   EXPECT_EQ(0u, result[0].bind_group);
1544   EXPECT_EQ(0u, result[0].binding);
1545   EXPECT_EQ(80u, result[0].size);
1546   EXPECT_EQ(80u, result[0].size_no_padding);
1547 }
1548 
TEST_F(InspectorGetStorageBufferResourceBindingsTest,Simple)1549 TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) {
1550   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
1551   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
1552 
1553   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1554 
1555   MakeCallerBodyFunction("ep_func", {"sb_func"},
1556                          ast::DecorationList{
1557                              Stage(ast::PipelineStage::kFragment),
1558                          });
1559 
1560   Inspector& inspector = Build();
1561 
1562   auto result = inspector.GetStorageBufferResourceBindings("ep_func");
1563   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1564   ASSERT_EQ(1u, result.size());
1565 
1566   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1567             result[0].resource_type);
1568   EXPECT_EQ(0u, result[0].bind_group);
1569   EXPECT_EQ(0u, result[0].binding);
1570   EXPECT_EQ(4u, result[0].size);
1571   EXPECT_EQ(4u, result[0].size_no_padding);
1572 }
1573 
TEST_F(InspectorGetStorageBufferResourceBindingsTest,MultipleMembers)1574 TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
1575   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
1576                                                                 ty.i32(),
1577                                                                 ty.u32(),
1578                                                                 ty.f32(),
1579                                                             });
1580   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
1581 
1582   MakeStructVariableReferenceBodyFunction(
1583       "sb_func", "foo_sb", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
1584 
1585   MakeCallerBodyFunction("ep_func", {"sb_func"},
1586                          ast::DecorationList{
1587                              Stage(ast::PipelineStage::kFragment),
1588                          });
1589 
1590   Inspector& inspector = Build();
1591 
1592   auto result = inspector.GetStorageBufferResourceBindings("ep_func");
1593   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1594   ASSERT_EQ(1u, result.size());
1595 
1596   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1597             result[0].resource_type);
1598   EXPECT_EQ(0u, result[0].bind_group);
1599   EXPECT_EQ(0u, result[0].binding);
1600   EXPECT_EQ(12u, result[0].size);
1601   EXPECT_EQ(12u, result[0].size_no_padding);
1602 }
1603 
TEST_F(InspectorGetStorageBufferResourceBindingsTest,MultipleStorageBuffers)1604 TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
1605   auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
1606                                                               ty.i32(),
1607                                                               ty.u32(),
1608                                                               ty.f32(),
1609                                                           });
1610   AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kReadWrite, 0, 0);
1611   AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kReadWrite, 0, 1);
1612   AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kReadWrite, 2, 0);
1613 
1614   auto AddReferenceFunc = [this](const std::string& func_name,
1615                                  const std::string& var_name) {
1616     MakeStructVariableReferenceBodyFunction(
1617         func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
1618   };
1619   AddReferenceFunc("sb_foo_func", "sb_foo");
1620   AddReferenceFunc("sb_bar_func", "sb_bar");
1621   AddReferenceFunc("sb_baz_func", "sb_baz");
1622 
1623   auto FuncCall = [&](const std::string& callee) {
1624     return create<ast::CallStatement>(Call(callee));
1625   };
1626 
1627   Func("ep_func", ast::VariableList(), ty.void_(),
1628        ast::StatementList{
1629            FuncCall("sb_foo_func"),
1630            FuncCall("sb_bar_func"),
1631            FuncCall("sb_baz_func"),
1632            Return(),
1633        },
1634        ast::DecorationList{
1635            Stage(ast::PipelineStage::kFragment),
1636        });
1637 
1638   Inspector& inspector = Build();
1639 
1640   auto result = inspector.GetStorageBufferResourceBindings("ep_func");
1641   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1642   ASSERT_EQ(3u, result.size());
1643 
1644   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1645             result[0].resource_type);
1646   EXPECT_EQ(0u, result[0].bind_group);
1647   EXPECT_EQ(0u, result[0].binding);
1648   EXPECT_EQ(12u, result[0].size);
1649   EXPECT_EQ(12u, result[0].size_no_padding);
1650 
1651   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1652             result[1].resource_type);
1653   EXPECT_EQ(0u, result[1].bind_group);
1654   EXPECT_EQ(1u, result[1].binding);
1655   EXPECT_EQ(12u, result[1].size);
1656   EXPECT_EQ(12u, result[1].size_no_padding);
1657 
1658   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1659             result[2].resource_type);
1660   EXPECT_EQ(2u, result[2].bind_group);
1661   EXPECT_EQ(0u, result[2].binding);
1662   EXPECT_EQ(12u, result[2].size);
1663   EXPECT_EQ(12u, result[2].size_no_padding);
1664 }
1665 
TEST_F(InspectorGetStorageBufferResourceBindingsTest,ContainingArray)1666 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
1667   auto foo_struct_type =
1668       MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
1669   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
1670 
1671   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1672 
1673   MakeCallerBodyFunction("ep_func", {"sb_func"},
1674                          ast::DecorationList{
1675                              Stage(ast::PipelineStage::kFragment),
1676                          });
1677 
1678   Inspector& inspector = Build();
1679 
1680   auto result = inspector.GetStorageBufferResourceBindings("ep_func");
1681   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1682   ASSERT_EQ(1u, result.size());
1683 
1684   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1685             result[0].resource_type);
1686   EXPECT_EQ(0u, result[0].bind_group);
1687   EXPECT_EQ(0u, result[0].binding);
1688   EXPECT_EQ(20u, result[0].size);
1689   EXPECT_EQ(20u, result[0].size_no_padding);
1690 }
1691 
TEST_F(InspectorGetStorageBufferResourceBindingsTest,ContainingRuntimeArray)1692 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
1693   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
1694                                                                 ty.i32(),
1695                                                                 ty.array<u32>(),
1696                                                             });
1697   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
1698 
1699   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1700 
1701   MakeCallerBodyFunction("ep_func", {"sb_func"},
1702                          ast::DecorationList{
1703                              Stage(ast::PipelineStage::kFragment),
1704                          });
1705 
1706   Inspector& inspector = Build();
1707 
1708   auto result = inspector.GetStorageBufferResourceBindings("ep_func");
1709   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1710   ASSERT_EQ(1u, result.size());
1711 
1712   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1713             result[0].resource_type);
1714   EXPECT_EQ(0u, result[0].bind_group);
1715   EXPECT_EQ(0u, result[0].binding);
1716   EXPECT_EQ(8u, result[0].size);
1717   EXPECT_EQ(8u, result[0].size_no_padding);
1718 }
1719 
TEST_F(InspectorGetStorageBufferResourceBindingsTest,ContainingPadding)1720 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
1721   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
1722   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
1723 
1724   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
1725                                           {{0, ty.vec3<f32>()}});
1726 
1727   MakeCallerBodyFunction("ep_func", {"sb_func"},
1728                          ast::DecorationList{
1729                              Stage(ast::PipelineStage::kFragment),
1730                          });
1731 
1732   Inspector& inspector = Build();
1733 
1734   auto result = inspector.GetStorageBufferResourceBindings("ep_func");
1735   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1736   ASSERT_EQ(1u, result.size());
1737 
1738   EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
1739             result[0].resource_type);
1740   EXPECT_EQ(0u, result[0].bind_group);
1741   EXPECT_EQ(0u, result[0].binding);
1742   EXPECT_EQ(16u, result[0].size);
1743   EXPECT_EQ(12u, result[0].size_no_padding);
1744 }
1745 
TEST_F(InspectorGetStorageBufferResourceBindingsTest,SkipReadOnly)1746 TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
1747   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
1748   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
1749 
1750   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1751 
1752   MakeCallerBodyFunction("ep_func", {"sb_func"},
1753                          ast::DecorationList{
1754                              Stage(ast::PipelineStage::kFragment),
1755                          });
1756 
1757   Inspector& inspector = Build();
1758 
1759   auto result = inspector.GetStorageBufferResourceBindings("ep_func");
1760   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1761   ASSERT_EQ(0u, result.size());
1762 }
1763 
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,Simple)1764 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
1765   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
1766   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
1767 
1768   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1769 
1770   MakeCallerBodyFunction("ep_func", {"sb_func"},
1771                          ast::DecorationList{
1772                              Stage(ast::PipelineStage::kFragment),
1773                          });
1774 
1775   Inspector& inspector = Build();
1776 
1777   auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
1778   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1779   ASSERT_EQ(1u, result.size());
1780 
1781   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
1782             result[0].resource_type);
1783   EXPECT_EQ(0u, result[0].bind_group);
1784   EXPECT_EQ(0u, result[0].binding);
1785   EXPECT_EQ(4u, result[0].size);
1786   EXPECT_EQ(4u, result[0].size_no_padding);
1787 }
1788 
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,MultipleStorageBuffers)1789 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
1790        MultipleStorageBuffers) {
1791   auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
1792                                                               ty.i32(),
1793                                                               ty.u32(),
1794                                                               ty.f32(),
1795                                                           });
1796   AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kRead, 0, 0);
1797   AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kRead, 0, 1);
1798   AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kRead, 2, 0);
1799 
1800   auto AddReferenceFunc = [this](const std::string& func_name,
1801                                  const std::string& var_name) {
1802     MakeStructVariableReferenceBodyFunction(
1803         func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
1804   };
1805   AddReferenceFunc("sb_foo_func", "sb_foo");
1806   AddReferenceFunc("sb_bar_func", "sb_bar");
1807   AddReferenceFunc("sb_baz_func", "sb_baz");
1808 
1809   auto FuncCall = [&](const std::string& callee) {
1810     return create<ast::CallStatement>(Call(callee));
1811   };
1812 
1813   Func("ep_func", ast::VariableList(), ty.void_(),
1814        ast::StatementList{
1815            FuncCall("sb_foo_func"),
1816            FuncCall("sb_bar_func"),
1817            FuncCall("sb_baz_func"),
1818            Return(),
1819        },
1820        ast::DecorationList{
1821            Stage(ast::PipelineStage::kFragment),
1822        });
1823 
1824   Inspector& inspector = Build();
1825 
1826   auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
1827   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1828   ASSERT_EQ(3u, result.size());
1829 
1830   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
1831             result[0].resource_type);
1832   EXPECT_EQ(0u, result[0].bind_group);
1833   EXPECT_EQ(0u, result[0].binding);
1834   EXPECT_EQ(12u, result[0].size);
1835   EXPECT_EQ(12u, result[0].size_no_padding);
1836 
1837   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
1838             result[1].resource_type);
1839   EXPECT_EQ(0u, result[1].bind_group);
1840   EXPECT_EQ(1u, result[1].binding);
1841   EXPECT_EQ(12u, result[1].size);
1842   EXPECT_EQ(12u, result[1].size_no_padding);
1843 
1844   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
1845             result[2].resource_type);
1846   EXPECT_EQ(2u, result[2].bind_group);
1847   EXPECT_EQ(0u, result[2].binding);
1848   EXPECT_EQ(12u, result[2].size);
1849   EXPECT_EQ(12u, result[2].size_no_padding);
1850 }
1851 
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,ContainingArray)1852 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
1853   auto foo_struct_type =
1854       MakeStorageBufferTypes("foo_type", {
1855                                              ty.i32(),
1856                                              ty.array<u32, 4>(),
1857                                          });
1858   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
1859 
1860   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1861 
1862   MakeCallerBodyFunction("ep_func", {"sb_func"},
1863                          ast::DecorationList{
1864                              Stage(ast::PipelineStage::kFragment),
1865                          });
1866 
1867   Inspector& inspector = Build();
1868 
1869   auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
1870   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1871   ASSERT_EQ(1u, result.size());
1872 
1873   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
1874             result[0].resource_type);
1875   EXPECT_EQ(0u, result[0].bind_group);
1876   EXPECT_EQ(0u, result[0].binding);
1877   EXPECT_EQ(20u, result[0].size);
1878   EXPECT_EQ(20u, result[0].size_no_padding);
1879 }
1880 
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,ContainingRuntimeArray)1881 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
1882        ContainingRuntimeArray) {
1883   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
1884                                                                 ty.i32(),
1885                                                                 ty.array<u32>(),
1886                                                             });
1887   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
1888 
1889   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1890 
1891   MakeCallerBodyFunction("ep_func", {"sb_func"},
1892                          ast::DecorationList{
1893                              Stage(ast::PipelineStage::kFragment),
1894                          });
1895 
1896   Inspector& inspector = Build();
1897 
1898   auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
1899   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1900   ASSERT_EQ(1u, result.size());
1901 
1902   EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
1903             result[0].resource_type);
1904   EXPECT_EQ(0u, result[0].bind_group);
1905   EXPECT_EQ(0u, result[0].binding);
1906   EXPECT_EQ(8u, result[0].size);
1907   EXPECT_EQ(8u, result[0].size_no_padding);
1908 }
1909 
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,SkipNonReadOnly)1910 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
1911   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
1912   AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
1913 
1914   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
1915 
1916   MakeCallerBodyFunction("ep_func", {"sb_func"},
1917                          ast::DecorationList{
1918                              Stage(ast::PipelineStage::kFragment),
1919                          });
1920 
1921   Inspector& inspector = Build();
1922 
1923   auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
1924   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1925   ASSERT_EQ(0u, result.size());
1926 }
1927 
TEST_F(InspectorGetSamplerResourceBindingsTest,Simple)1928 TEST_F(InspectorGetSamplerResourceBindingsTest, Simple) {
1929   auto* sampled_texture_type =
1930       ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
1931   AddResource("foo_texture", sampled_texture_type, 0, 0);
1932   AddSampler("foo_sampler", 0, 1);
1933   AddGlobalVariable("foo_coords", ty.f32());
1934 
1935   MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
1936                                    "foo_coords", ty.f32(),
1937                                    ast::DecorationList{
1938                                        Stage(ast::PipelineStage::kFragment),
1939                                    });
1940 
1941   Inspector& inspector = Build();
1942 
1943   auto result = inspector.GetSamplerResourceBindings("ep");
1944   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1945 
1946   EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
1947   ASSERT_EQ(1u, result.size());
1948   EXPECT_EQ(0u, result[0].bind_group);
1949   EXPECT_EQ(1u, result[0].binding);
1950 }
1951 
TEST_F(InspectorGetSamplerResourceBindingsTest,NoSampler)1952 TEST_F(InspectorGetSamplerResourceBindingsTest, NoSampler) {
1953   MakeEmptyBodyFunction("ep_func", ast::DecorationList{
1954                                        Stage(ast::PipelineStage::kFragment),
1955                                    });
1956 
1957   Inspector& inspector = Build();
1958 
1959   auto result = inspector.GetSamplerResourceBindings("ep_func");
1960   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1961 
1962   ASSERT_EQ(0u, result.size());
1963 }
1964 
TEST_F(InspectorGetSamplerResourceBindingsTest,InFunction)1965 TEST_F(InspectorGetSamplerResourceBindingsTest, InFunction) {
1966   auto* sampled_texture_type =
1967       ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
1968   AddResource("foo_texture", sampled_texture_type, 0, 0);
1969   AddSampler("foo_sampler", 0, 1);
1970   AddGlobalVariable("foo_coords", ty.f32());
1971 
1972   MakeSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler",
1973                                    "foo_coords", ty.f32(), {});
1974 
1975   MakeCallerBodyFunction("ep_func", {"foo_func"},
1976                          ast::DecorationList{
1977                              Stage(ast::PipelineStage::kFragment),
1978                          });
1979 
1980   Inspector& inspector = Build();
1981 
1982   auto result = inspector.GetSamplerResourceBindings("ep_func");
1983   ASSERT_FALSE(inspector.has_error()) << inspector.error();
1984 
1985   EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
1986   ASSERT_EQ(1u, result.size());
1987   EXPECT_EQ(0u, result[0].bind_group);
1988   EXPECT_EQ(1u, result[0].binding);
1989 }
1990 
TEST_F(InspectorGetSamplerResourceBindingsTest,UnknownEntryPoint)1991 TEST_F(InspectorGetSamplerResourceBindingsTest, UnknownEntryPoint) {
1992   auto* sampled_texture_type =
1993       ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
1994   AddResource("foo_texture", sampled_texture_type, 0, 0);
1995   AddSampler("foo_sampler", 0, 1);
1996   AddGlobalVariable("foo_coords", ty.f32());
1997 
1998   MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
1999                                    "foo_coords", ty.f32(),
2000                                    ast::DecorationList{
2001                                        Stage(ast::PipelineStage::kFragment),
2002                                    });
2003 
2004   Inspector& inspector = Build();
2005 
2006   auto result = inspector.GetSamplerResourceBindings("foo");
2007   ASSERT_TRUE(inspector.has_error()) << inspector.error();
2008 }
2009 
TEST_F(InspectorGetSamplerResourceBindingsTest,SkipsComparisonSamplers)2010 TEST_F(InspectorGetSamplerResourceBindingsTest, SkipsComparisonSamplers) {
2011   auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
2012   AddResource("foo_texture", depth_texture_type, 0, 0);
2013   AddComparisonSampler("foo_sampler", 0, 1);
2014   AddGlobalVariable("foo_coords", ty.vec2<f32>());
2015   AddGlobalVariable("foo_depth", ty.f32());
2016 
2017   MakeComparisonSamplerReferenceBodyFunction(
2018       "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
2019       ast::DecorationList{
2020           Stage(ast::PipelineStage::kFragment),
2021       });
2022 
2023   Inspector& inspector = Build();
2024 
2025   auto result = inspector.GetSamplerResourceBindings("ep");
2026   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2027 
2028   ASSERT_EQ(0u, result.size());
2029 }
2030 
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest,Simple)2031 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, Simple) {
2032   auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
2033   AddResource("foo_texture", depth_texture_type, 0, 0);
2034   AddComparisonSampler("foo_sampler", 0, 1);
2035   AddGlobalVariable("foo_coords", ty.vec2<f32>());
2036   AddGlobalVariable("foo_depth", ty.f32());
2037 
2038   MakeComparisonSamplerReferenceBodyFunction(
2039       "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
2040       ast::DecorationList{
2041           Stage(ast::PipelineStage::kFragment),
2042       });
2043 
2044   Inspector& inspector = Build();
2045 
2046   auto result = inspector.GetComparisonSamplerResourceBindings("ep");
2047   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2048 
2049   EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
2050             result[0].resource_type);
2051   ASSERT_EQ(1u, result.size());
2052   EXPECT_EQ(0u, result[0].bind_group);
2053   EXPECT_EQ(1u, result[0].binding);
2054 }
2055 
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest,NoSampler)2056 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, NoSampler) {
2057   MakeEmptyBodyFunction("ep_func", ast::DecorationList{
2058                                        Stage(ast::PipelineStage::kFragment),
2059                                    });
2060 
2061   Inspector& inspector = Build();
2062 
2063   auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
2064   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2065 
2066   ASSERT_EQ(0u, result.size());
2067 }
2068 
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest,InFunction)2069 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, InFunction) {
2070   auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
2071   AddResource("foo_texture", depth_texture_type, 0, 0);
2072   AddComparisonSampler("foo_sampler", 0, 1);
2073   AddGlobalVariable("foo_coords", ty.vec2<f32>());
2074   AddGlobalVariable("foo_depth", ty.f32());
2075 
2076   MakeComparisonSamplerReferenceBodyFunction("foo_func", "foo_texture",
2077                                              "foo_sampler", "foo_coords",
2078                                              "foo_depth", ty.f32(), {});
2079 
2080   MakeCallerBodyFunction("ep_func", {"foo_func"},
2081                          ast::DecorationList{
2082                              Stage(ast::PipelineStage::kFragment),
2083                          });
2084 
2085   Inspector& inspector = Build();
2086 
2087   auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
2088   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2089 
2090   EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
2091             result[0].resource_type);
2092   ASSERT_EQ(1u, result.size());
2093   EXPECT_EQ(0u, result[0].bind_group);
2094   EXPECT_EQ(1u, result[0].binding);
2095 }
2096 
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest,UnknownEntryPoint)2097 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, UnknownEntryPoint) {
2098   auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
2099   AddResource("foo_texture", depth_texture_type, 0, 0);
2100   AddComparisonSampler("foo_sampler", 0, 1);
2101   AddGlobalVariable("foo_coords", ty.vec2<f32>());
2102   AddGlobalVariable("foo_depth", ty.f32());
2103 
2104   MakeComparisonSamplerReferenceBodyFunction(
2105       "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
2106       ast::DecorationList{
2107           Stage(ast::PipelineStage::kFragment),
2108       });
2109 
2110   Inspector& inspector = Build();
2111 
2112   auto result = inspector.GetSamplerResourceBindings("foo");
2113   ASSERT_TRUE(inspector.has_error()) << inspector.error();
2114 }
2115 
TEST_F(InspectorGetComparisonSamplerResourceBindingsTest,SkipsSamplers)2116 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, SkipsSamplers) {
2117   auto* sampled_texture_type =
2118       ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
2119   AddResource("foo_texture", sampled_texture_type, 0, 0);
2120   AddSampler("foo_sampler", 0, 1);
2121   AddGlobalVariable("foo_coords", ty.f32());
2122 
2123   MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
2124                                    "foo_coords", ty.f32(),
2125                                    ast::DecorationList{
2126                                        Stage(ast::PipelineStage::kFragment),
2127                                    });
2128 
2129   Inspector& inspector = Build();
2130 
2131   auto result = inspector.GetComparisonSamplerResourceBindings("ep");
2132   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2133 
2134   ASSERT_EQ(0u, result.size());
2135 }
2136 
TEST_F(InspectorGetSampledTextureResourceBindingsTest,Empty)2137 TEST_F(InspectorGetSampledTextureResourceBindingsTest, Empty) {
2138   MakeEmptyBodyFunction("foo", ast::DecorationList{
2139                                    Stage(ast::PipelineStage::kFragment),
2140                                });
2141 
2142   Inspector& inspector = Build();
2143 
2144   auto result = inspector.GetSampledTextureResourceBindings("foo");
2145   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2146 
2147   EXPECT_EQ(0u, result.size());
2148 }
2149 
TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam,textureSample)2150 TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam, textureSample) {
2151   auto* sampled_texture_type = ty.sampled_texture(
2152       GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
2153   AddResource("foo_texture", sampled_texture_type, 0, 0);
2154   AddSampler("foo_sampler", 0, 1);
2155   auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
2156   AddGlobalVariable("foo_coords", coord_type);
2157 
2158   MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
2159                                    "foo_coords",
2160                                    GetBaseType(GetParam().sampled_kind),
2161                                    ast::DecorationList{
2162                                        Stage(ast::PipelineStage::kFragment),
2163                                    });
2164 
2165   Inspector& inspector = Build();
2166 
2167   auto result = inspector.GetSampledTextureResourceBindings("ep");
2168   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2169 
2170   EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
2171             result[0].resource_type);
2172   ASSERT_EQ(1u, result.size());
2173   EXPECT_EQ(0u, result[0].bind_group);
2174   EXPECT_EQ(0u, result[0].binding);
2175   EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
2176   EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
2177 
2178   // Prove that sampled and multi-sampled bindings are accounted
2179   // for separately.
2180   auto multisampled_result =
2181       inspector.GetMultisampledTextureResourceBindings("ep");
2182   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2183   ASSERT_TRUE(multisampled_result.empty());
2184 }
2185 
2186 INSTANTIATE_TEST_SUITE_P(
2187     InspectorGetSampledTextureResourceBindingsTest,
2188     InspectorGetSampledTextureResourceBindingsTestWithParam,
2189     testing::Values(
2190         GetSampledTextureTestParams{
2191             ast::TextureDimension::k1d,
2192             inspector::ResourceBinding::TextureDimension::k1d,
2193             inspector::ResourceBinding::SampledKind::kFloat},
2194         GetSampledTextureTestParams{
2195             ast::TextureDimension::k2d,
2196             inspector::ResourceBinding::TextureDimension::k2d,
2197             inspector::ResourceBinding::SampledKind::kFloat},
2198         GetSampledTextureTestParams{
2199             ast::TextureDimension::k3d,
2200             inspector::ResourceBinding::TextureDimension::k3d,
2201             inspector::ResourceBinding::SampledKind::kFloat},
2202         GetSampledTextureTestParams{
2203             ast::TextureDimension::kCube,
2204             inspector::ResourceBinding::TextureDimension::kCube,
2205             inspector::ResourceBinding::SampledKind::kFloat}));
2206 
TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam,textureSample)2207 TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
2208        textureSample) {
2209   auto* sampled_texture_type = ty.sampled_texture(
2210       GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
2211   AddResource("foo_texture", sampled_texture_type, 0, 0);
2212   AddSampler("foo_sampler", 0, 1);
2213   auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
2214   AddGlobalVariable("foo_coords", coord_type);
2215   AddGlobalVariable("foo_array_index", ty.i32());
2216 
2217   MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
2218                                    "foo_coords", "foo_array_index",
2219                                    GetBaseType(GetParam().sampled_kind),
2220                                    ast::DecorationList{
2221                                        Stage(ast::PipelineStage::kFragment),
2222                                    });
2223 
2224   Inspector& inspector = Build();
2225 
2226   auto result = inspector.GetSampledTextureResourceBindings("ep");
2227   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2228   ASSERT_EQ(1u, result.size());
2229 
2230   EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
2231             result[0].resource_type);
2232   EXPECT_EQ(0u, result[0].bind_group);
2233   EXPECT_EQ(0u, result[0].binding);
2234   EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
2235   EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
2236 }
2237 
2238 INSTANTIATE_TEST_SUITE_P(
2239     InspectorGetSampledArrayTextureResourceBindingsTest,
2240     InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
2241     testing::Values(
2242         GetSampledTextureTestParams{
2243             ast::TextureDimension::k2dArray,
2244             inspector::ResourceBinding::TextureDimension::k2dArray,
2245             inspector::ResourceBinding::SampledKind::kFloat},
2246         GetSampledTextureTestParams{
2247             ast::TextureDimension::kCubeArray,
2248             inspector::ResourceBinding::TextureDimension::kCubeArray,
2249             inspector::ResourceBinding::SampledKind::kFloat}));
2250 
TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,textureLoad)2251 TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
2252        textureLoad) {
2253   auto* multisampled_texture_type = ty.multisampled_texture(
2254       GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
2255   AddResource("foo_texture", multisampled_texture_type, 0, 0);
2256   auto* coord_type = GetCoordsType(GetParam().type_dim, ty.i32());
2257   AddGlobalVariable("foo_coords", coord_type);
2258   AddGlobalVariable("foo_sample_index", ty.i32());
2259 
2260   Func("ep", ast::VariableList(), ty.void_(),
2261        ast::StatementList{
2262            CallStmt(Call("textureLoad", "foo_texture", "foo_coords",
2263                          "foo_sample_index")),
2264        },
2265        ast::DecorationList{
2266            Stage(ast::PipelineStage::kFragment),
2267        });
2268 
2269   Inspector& inspector = Build();
2270 
2271   auto result = inspector.GetMultisampledTextureResourceBindings("ep");
2272   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2273 
2274   ASSERT_EQ(1u, result.size());
2275   EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
2276             result[0].resource_type);
2277   EXPECT_EQ(0u, result[0].bind_group);
2278   EXPECT_EQ(0u, result[0].binding);
2279   EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
2280   EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
2281 
2282   // Prove that sampled and multi-sampled bindings are accounted
2283   // for separately.
2284   auto single_sampled_result =
2285       inspector.GetSampledTextureResourceBindings("ep");
2286   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2287   ASSERT_TRUE(single_sampled_result.empty());
2288 }
2289 
2290 INSTANTIATE_TEST_SUITE_P(
2291     InspectorGetMultisampledTextureResourceBindingsTest,
2292     InspectorGetMultisampledTextureResourceBindingsTestWithParam,
2293     testing::Values(
2294         GetMultisampledTextureTestParams{
2295             ast::TextureDimension::k2d,
2296             inspector::ResourceBinding::TextureDimension::k2d,
2297             inspector::ResourceBinding::SampledKind::kFloat},
2298         GetMultisampledTextureTestParams{
2299             ast::TextureDimension::k2d,
2300             inspector::ResourceBinding::TextureDimension::k2d,
2301             inspector::ResourceBinding::SampledKind::kSInt},
2302         GetMultisampledTextureTestParams{
2303             ast::TextureDimension::k2d,
2304             inspector::ResourceBinding::TextureDimension::k2d,
2305             inspector::ResourceBinding::SampledKind::kUInt}));
2306 
TEST_F(InspectorGetMultisampledArrayTextureResourceBindingsTest,Empty)2307 TEST_F(InspectorGetMultisampledArrayTextureResourceBindingsTest, Empty) {
2308   MakeEmptyBodyFunction("foo", ast::DecorationList{
2309                                    Stage(ast::PipelineStage::kFragment),
2310                                });
2311 
2312   Inspector& inspector = Build();
2313 
2314   auto result = inspector.GetSampledTextureResourceBindings("foo");
2315   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2316 
2317   EXPECT_EQ(0u, result.size());
2318 }
2319 
TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,DISABLED_textureSample)2320 TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
2321        DISABLED_textureSample) {
2322   auto* multisampled_texture_type = ty.multisampled_texture(
2323       GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
2324   AddResource("foo_texture", multisampled_texture_type, 0, 0);
2325   AddSampler("foo_sampler", 0, 1);
2326   auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
2327   AddGlobalVariable("foo_coords", coord_type);
2328   AddGlobalVariable("foo_array_index", ty.i32());
2329 
2330   MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
2331                                    "foo_coords", "foo_array_index",
2332                                    GetBaseType(GetParam().sampled_kind),
2333                                    ast::DecorationList{
2334                                        Stage(ast::PipelineStage::kFragment),
2335                                    });
2336 
2337   Inspector& inspector = Build();
2338 
2339   auto result = inspector.GetMultisampledTextureResourceBindings("ep");
2340   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2341   ASSERT_EQ(1u, result.size());
2342 
2343   EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
2344             result[0].resource_type);
2345   EXPECT_EQ(0u, result[0].bind_group);
2346   EXPECT_EQ(0u, result[0].binding);
2347   EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
2348   EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
2349 }
2350 
2351 INSTANTIATE_TEST_SUITE_P(
2352     InspectorGetMultisampledArrayTextureResourceBindingsTest,
2353     InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
2354     testing::Values(
2355         GetMultisampledTextureTestParams{
2356             ast::TextureDimension::k2dArray,
2357             inspector::ResourceBinding::TextureDimension::k2dArray,
2358             inspector::ResourceBinding::SampledKind::kFloat},
2359         GetMultisampledTextureTestParams{
2360             ast::TextureDimension::k2dArray,
2361             inspector::ResourceBinding::TextureDimension::k2dArray,
2362             inspector::ResourceBinding::SampledKind::kSInt},
2363         GetMultisampledTextureTestParams{
2364             ast::TextureDimension::k2dArray,
2365             inspector::ResourceBinding::TextureDimension::k2dArray,
2366             inspector::ResourceBinding::SampledKind::kUInt}));
2367 
TEST_F(InspectorGetStorageTextureResourceBindingsTest,Empty)2368 TEST_F(InspectorGetStorageTextureResourceBindingsTest, Empty) {
2369   MakeEmptyBodyFunction("ep", ast::DecorationList{
2370                                   Stage(ast::PipelineStage::kFragment),
2371                               });
2372 
2373   Inspector& inspector = Build();
2374 
2375   auto result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
2376   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2377   EXPECT_EQ(0u, result.size());
2378 }
2379 
TEST_P(InspectorGetStorageTextureResourceBindingsTestWithParam,Simple)2380 TEST_P(InspectorGetStorageTextureResourceBindingsTestWithParam, Simple) {
2381   DimensionParams dim_params;
2382   ImageFormatParams format_params;
2383   std::tie(dim_params, format_params) = GetParam();
2384 
2385   ast::TextureDimension dim;
2386   ResourceBinding::TextureDimension expected_dim;
2387   std::tie(dim, expected_dim) = dim_params;
2388 
2389   ast::ImageFormat format;
2390   ResourceBinding::ImageFormat expected_format;
2391   ResourceBinding::SampledKind expected_kind;
2392   std::tie(format, expected_format, expected_kind) = format_params;
2393 
2394   auto* st_type = MakeStorageTextureTypes(dim, format);
2395   AddStorageTexture("st_var", st_type, 0, 0);
2396 
2397   const ast::Type* dim_type = nullptr;
2398   switch (dim) {
2399     case ast::TextureDimension::k1d:
2400       dim_type = ty.i32();
2401       break;
2402     case ast::TextureDimension::k2d:
2403     case ast::TextureDimension::k2dArray:
2404       dim_type = ty.vec2<i32>();
2405       break;
2406     case ast::TextureDimension::k3d:
2407       dim_type = ty.vec3<i32>();
2408       break;
2409     default:
2410       break;
2411   }
2412 
2413   ASSERT_FALSE(dim_type == nullptr);
2414 
2415   MakeStorageTextureBodyFunction(
2416       "ep", "st_var", dim_type,
2417       ast::DecorationList{Stage(ast::PipelineStage::kFragment)});
2418 
2419   Inspector& inspector = Build();
2420 
2421   auto result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
2422   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2423   ASSERT_EQ(1u, result.size());
2424 
2425   EXPECT_EQ(ResourceBinding::ResourceType::kWriteOnlyStorageTexture,
2426             result[0].resource_type);
2427   EXPECT_EQ(0u, result[0].bind_group);
2428   EXPECT_EQ(0u, result[0].binding);
2429   EXPECT_EQ(expected_dim, result[0].dim);
2430   EXPECT_EQ(expected_format, result[0].image_format);
2431   EXPECT_EQ(expected_kind, result[0].sampled_kind);
2432 }
2433 
2434 INSTANTIATE_TEST_SUITE_P(
2435     InspectorGetStorageTextureResourceBindingsTest,
2436     InspectorGetStorageTextureResourceBindingsTestWithParam,
2437     testing::Combine(
2438         testing::Values(
2439             std::make_tuple(ast::TextureDimension::k1d,
2440                             ResourceBinding::TextureDimension::k1d),
2441             std::make_tuple(ast::TextureDimension::k2d,
2442                             ResourceBinding::TextureDimension::k2d),
2443             std::make_tuple(ast::TextureDimension::k2dArray,
2444                             ResourceBinding::TextureDimension::k2dArray),
2445             std::make_tuple(ast::TextureDimension::k3d,
2446                             ResourceBinding::TextureDimension::k3d)),
2447         testing::Values(
2448             std::make_tuple(ast::ImageFormat::kR32Float,
2449                             ResourceBinding::ImageFormat::kR32Float,
2450                             ResourceBinding::SampledKind::kFloat),
2451             std::make_tuple(ast::ImageFormat::kR32Sint,
2452                             ResourceBinding::ImageFormat::kR32Sint,
2453                             ResourceBinding::SampledKind::kSInt),
2454             std::make_tuple(ast::ImageFormat::kR32Uint,
2455                             ResourceBinding::ImageFormat::kR32Uint,
2456                             ResourceBinding::SampledKind::kUInt),
2457             std::make_tuple(ast::ImageFormat::kRg32Float,
2458                             ResourceBinding::ImageFormat::kRg32Float,
2459                             ResourceBinding::SampledKind::kFloat),
2460             std::make_tuple(ast::ImageFormat::kRg32Sint,
2461                             ResourceBinding::ImageFormat::kRg32Sint,
2462                             ResourceBinding::SampledKind::kSInt),
2463             std::make_tuple(ast::ImageFormat::kRg32Uint,
2464                             ResourceBinding::ImageFormat::kRg32Uint,
2465                             ResourceBinding::SampledKind::kUInt),
2466             std::make_tuple(ast::ImageFormat::kRgba16Float,
2467                             ResourceBinding::ImageFormat::kRgba16Float,
2468                             ResourceBinding::SampledKind::kFloat),
2469             std::make_tuple(ast::ImageFormat::kRgba16Sint,
2470                             ResourceBinding::ImageFormat::kRgba16Sint,
2471                             ResourceBinding::SampledKind::kSInt),
2472             std::make_tuple(ast::ImageFormat::kRgba16Uint,
2473                             ResourceBinding::ImageFormat::kRgba16Uint,
2474                             ResourceBinding::SampledKind::kUInt),
2475             std::make_tuple(ast::ImageFormat::kRgba32Float,
2476                             ResourceBinding::ImageFormat::kRgba32Float,
2477                             ResourceBinding::SampledKind::kFloat),
2478             std::make_tuple(ast::ImageFormat::kRgba32Sint,
2479                             ResourceBinding::ImageFormat::kRgba32Sint,
2480                             ResourceBinding::SampledKind::kSInt),
2481             std::make_tuple(ast::ImageFormat::kRgba32Uint,
2482                             ResourceBinding::ImageFormat::kRgba32Uint,
2483                             ResourceBinding::SampledKind::kUInt),
2484             std::make_tuple(ast::ImageFormat::kRgba8Sint,
2485                             ResourceBinding::ImageFormat::kRgba8Sint,
2486                             ResourceBinding::SampledKind::kSInt),
2487             std::make_tuple(ast::ImageFormat::kRgba8Snorm,
2488                             ResourceBinding::ImageFormat::kRgba8Snorm,
2489                             ResourceBinding::SampledKind::kFloat),
2490             std::make_tuple(ast::ImageFormat::kRgba8Uint,
2491                             ResourceBinding::ImageFormat::kRgba8Uint,
2492                             ResourceBinding::SampledKind::kUInt),
2493             std::make_tuple(ast::ImageFormat::kRgba8Unorm,
2494                             ResourceBinding::ImageFormat::kRgba8Unorm,
2495                             ResourceBinding::SampledKind::kFloat))));
2496 
TEST_P(InspectorGetDepthTextureResourceBindingsTestWithParam,textureDimensions)2497 TEST_P(InspectorGetDepthTextureResourceBindingsTestWithParam,
2498        textureDimensions) {
2499   auto* depth_texture_type = ty.depth_texture(GetParam().type_dim);
2500   AddResource("dt", depth_texture_type, 0, 0);
2501 
2502   Func("ep", ast::VariableList(), ty.void_(),
2503        ast::StatementList{
2504            CallStmt(Call("textureDimensions", "dt")),
2505        },
2506        ast::DecorationList{
2507            Stage(ast::PipelineStage::kFragment),
2508        });
2509 
2510   Inspector& inspector = Build();
2511 
2512   auto result = inspector.GetDepthTextureResourceBindings("ep");
2513   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2514 
2515   EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture,
2516             result[0].resource_type);
2517   ASSERT_EQ(1u, result.size());
2518   EXPECT_EQ(0u, result[0].bind_group);
2519   EXPECT_EQ(0u, result[0].binding);
2520   EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
2521 }
2522 
2523 INSTANTIATE_TEST_SUITE_P(
2524     InspectorGetDepthTextureResourceBindingsTest,
2525     InspectorGetDepthTextureResourceBindingsTestWithParam,
2526     testing::Values(
2527         GetDepthTextureTestParams{
2528             ast::TextureDimension::k2d,
2529             inspector::ResourceBinding::TextureDimension::k2d},
2530         GetDepthTextureTestParams{
2531             ast::TextureDimension::k2dArray,
2532             inspector::ResourceBinding::TextureDimension::k2dArray},
2533         GetDepthTextureTestParams{
2534             ast::TextureDimension::kCube,
2535             inspector::ResourceBinding::TextureDimension::kCube},
2536         GetDepthTextureTestParams{
2537             ast::TextureDimension::kCubeArray,
2538             inspector::ResourceBinding::TextureDimension::kCubeArray}));
2539 
TEST_F(InspectorGetDepthMultisampledTextureResourceBindingsTest,textureDimensions)2540 TEST_F(InspectorGetDepthMultisampledTextureResourceBindingsTest,
2541        textureDimensions) {
2542   auto* depth_ms_texture_type =
2543       ty.depth_multisampled_texture(ast::TextureDimension::k2d);
2544   AddResource("tex", depth_ms_texture_type, 0, 0);
2545 
2546   Func("ep", ast::VariableList(), ty.void_(),
2547        ast::StatementList{
2548            CallStmt(Call("textureDimensions", "tex")),
2549        },
2550        ast::DecorationList{
2551            Stage(ast::PipelineStage::kFragment),
2552        });
2553 
2554   Inspector& inspector = Build();
2555 
2556   auto result = inspector.GetDepthMultisampledTextureResourceBindings("ep");
2557   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2558 
2559   EXPECT_EQ(ResourceBinding::ResourceType::kDepthMultisampledTexture,
2560             result[0].resource_type);
2561   ASSERT_EQ(1u, result.size());
2562   EXPECT_EQ(0u, result[0].bind_group);
2563   EXPECT_EQ(0u, result[0].binding);
2564   EXPECT_EQ(ResourceBinding::TextureDimension::k2d, result[0].dim);
2565 }
2566 
TEST_F(InspectorGetExternalTextureResourceBindingsTest,Simple)2567 TEST_F(InspectorGetExternalTextureResourceBindingsTest, Simple) {
2568   auto* external_texture_type = ty.external_texture();
2569   AddResource("et", external_texture_type, 0, 0);
2570 
2571   Func("ep", ast::VariableList(), ty.void_(),
2572        ast::StatementList{
2573            CallStmt(Call("textureDimensions", "et")),
2574        },
2575        ast::DecorationList{
2576            Stage(ast::PipelineStage::kFragment),
2577        });
2578 
2579   Inspector& inspector = Build();
2580 
2581   auto result = inspector.GetExternalTextureResourceBindings("ep");
2582   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2583   EXPECT_EQ(ResourceBinding::ResourceType::kExternalTexture,
2584             result[0].resource_type);
2585 
2586   ASSERT_EQ(1u, result.size());
2587   EXPECT_EQ(0u, result[0].bind_group);
2588   EXPECT_EQ(0u, result[0].binding);
2589 }
2590 
TEST_F(InspectorGetSamplerTextureUsesTest,None)2591 TEST_F(InspectorGetSamplerTextureUsesTest, None) {
2592   std::string shader = R"(
2593 [[stage(fragment)]]
2594 fn main() {
2595 })";
2596 
2597   Inspector& inspector = Initialize(shader);
2598   auto result = inspector.GetSamplerTextureUses("main");
2599   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2600 
2601   ASSERT_EQ(0u, result.size());
2602 }
2603 
TEST_F(InspectorGetSamplerTextureUsesTest,Simple)2604 TEST_F(InspectorGetSamplerTextureUsesTest, Simple) {
2605   std::string shader = R"(
2606 [[group(0), binding(1)]] var mySampler: sampler;
2607 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2608 
2609 [[stage(fragment)]]
2610 fn main([[location(0)]] fragUV: vec2<f32>,
2611         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2612   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
2613 })";
2614 
2615   Inspector& inspector = Initialize(shader);
2616   auto result = inspector.GetSamplerTextureUses("main");
2617   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2618 
2619   ASSERT_EQ(1u, result.size());
2620 
2621   EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2622   EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2623   EXPECT_EQ(0u, result[0].texture_binding_point.group);
2624   EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2625 }
2626 
TEST_F(InspectorGetSamplerTextureUsesTest,UnknownEntryPoint)2627 TEST_F(InspectorGetSamplerTextureUsesTest, UnknownEntryPoint) {
2628   std::string shader = R"(
2629 [[group(0), binding(1)]] var mySampler: sampler;
2630 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2631 
2632 [[stage(fragment)]]
2633 fn main([[location(0)]] fragUV: vec2<f32>,
2634         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2635   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
2636 })";
2637 
2638   Inspector& inspector = Initialize(shader);
2639   auto result = inspector.GetSamplerTextureUses("foo");
2640   ASSERT_TRUE(inspector.has_error()) << inspector.error();
2641 }
2642 
TEST_F(InspectorGetSamplerTextureUsesTest,MultipleCalls)2643 TEST_F(InspectorGetSamplerTextureUsesTest, MultipleCalls) {
2644   std::string shader = R"(
2645 [[group(0), binding(1)]] var mySampler: sampler;
2646 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2647 
2648 [[stage(fragment)]]
2649 fn main([[location(0)]] fragUV: vec2<f32>,
2650         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2651   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
2652 })";
2653 
2654   Inspector& inspector = Initialize(shader);
2655   auto result_0 = inspector.GetSamplerTextureUses("main");
2656   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2657 
2658   auto result_1 = inspector.GetSamplerTextureUses("main");
2659   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2660 
2661   EXPECT_EQ(result_0, result_1);
2662 }
2663 
TEST_F(InspectorGetSamplerTextureUsesTest,BothIndirect)2664 TEST_F(InspectorGetSamplerTextureUsesTest, BothIndirect) {
2665   std::string shader = R"(
2666 [[group(0), binding(1)]] var mySampler: sampler;
2667 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2668 
2669 fn doSample(t: texture_2d<f32>, s: sampler, uv: vec2<f32>) -> vec4<f32> {
2670   return textureSample(t, s, uv);
2671 }
2672 
2673 [[stage(fragment)]]
2674 fn main([[location(0)]] fragUV: vec2<f32>,
2675         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2676   return doSample(myTexture, mySampler, fragUV) * fragPosition;
2677 })";
2678 
2679   Inspector& inspector = Initialize(shader);
2680   auto result = inspector.GetSamplerTextureUses("main");
2681   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2682 
2683   ASSERT_EQ(1u, result.size());
2684 
2685   EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2686   EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2687   EXPECT_EQ(0u, result[0].texture_binding_point.group);
2688   EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2689 }
2690 
TEST_F(InspectorGetSamplerTextureUsesTest,SamplerIndirect)2691 TEST_F(InspectorGetSamplerTextureUsesTest, SamplerIndirect) {
2692   std::string shader = R"(
2693 [[group(0), binding(1)]] var mySampler: sampler;
2694 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2695 
2696 fn doSample(s: sampler, uv: vec2<f32>) -> vec4<f32> {
2697   return textureSample(myTexture, s, uv);
2698 }
2699 
2700 [[stage(fragment)]]
2701 fn main([[location(0)]] fragUV: vec2<f32>,
2702         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2703   return doSample(mySampler, fragUV) * fragPosition;
2704 })";
2705 
2706   Inspector& inspector = Initialize(shader);
2707   auto result = inspector.GetSamplerTextureUses("main");
2708   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2709 
2710   ASSERT_EQ(1u, result.size());
2711 
2712   EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2713   EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2714   EXPECT_EQ(0u, result[0].texture_binding_point.group);
2715   EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2716 }
2717 
TEST_F(InspectorGetSamplerTextureUsesTest,TextureIndirect)2718 TEST_F(InspectorGetSamplerTextureUsesTest, TextureIndirect) {
2719   std::string shader = R"(
2720 [[group(0), binding(1)]] var mySampler: sampler;
2721 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2722 
2723 fn doSample(t: texture_2d<f32>, uv: vec2<f32>) -> vec4<f32> {
2724   return textureSample(t, mySampler, uv);
2725 }
2726 
2727 [[stage(fragment)]]
2728 fn main([[location(0)]] fragUV: vec2<f32>,
2729         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2730   return doSample(myTexture, fragUV) * fragPosition;
2731 })";
2732 
2733   Inspector& inspector = Initialize(shader);
2734   auto result = inspector.GetSamplerTextureUses("main");
2735   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2736 
2737   ASSERT_EQ(1u, result.size());
2738 
2739   EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2740   EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2741   EXPECT_EQ(0u, result[0].texture_binding_point.group);
2742   EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2743 }
2744 
TEST_F(InspectorGetSamplerTextureUsesTest,NeitherIndirect)2745 TEST_F(InspectorGetSamplerTextureUsesTest, NeitherIndirect) {
2746   std::string shader = R"(
2747 [[group(0), binding(1)]] var mySampler: sampler;
2748 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2749 
2750 fn doSample(uv: vec2<f32>) -> vec4<f32> {
2751   return textureSample(myTexture, mySampler, uv);
2752 }
2753 
2754 [[stage(fragment)]]
2755 fn main([[location(0)]] fragUV: vec2<f32>,
2756         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2757   return doSample(fragUV) * fragPosition;
2758 })";
2759 
2760   Inspector& inspector = Initialize(shader);
2761   auto result = inspector.GetSamplerTextureUses("main");
2762   ASSERT_FALSE(inspector.has_error()) << inspector.error();
2763 
2764   ASSERT_EQ(1u, result.size());
2765 
2766   EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2767   EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2768   EXPECT_EQ(0u, result[0].texture_binding_point.group);
2769   EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2770 }
2771 
TEST_F(InspectorGetSamplerTextureUsesTest,Complex)2772 TEST_F(InspectorGetSamplerTextureUsesTest, Complex) {
2773   std::string shader = R"(
2774 [[group(0), binding(1)]] var mySampler: sampler;
2775 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2776 
2777 
2778 fn doSample(t: texture_2d<f32>, s: sampler, uv: vec2<f32>) -> vec4<f32> {
2779   return textureSample(t, s, uv);
2780 }
2781 
2782 fn X(t: texture_2d<f32>, s: sampler, uv: vec2<f32>) -> vec4<f32> {
2783   return doSample(t, s, uv);
2784 }
2785 
2786 fn Y(t: texture_2d<f32>, s: sampler, uv: vec2<f32>) -> vec4<f32> {
2787   return doSample(t, s, uv);
2788 }
2789 
2790 fn Z(t: texture_2d<f32>, s: sampler, uv: vec2<f32>) -> vec4<f32> {
2791   return X(t, s, uv) + Y(t, s, uv);
2792 }
2793 
2794 [[stage(fragment)]]
2795 fn via_call([[location(0)]] fragUV: vec2<f32>,
2796         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2797   return Z(myTexture, mySampler, fragUV) * fragPosition;
2798 }
2799 
2800 [[stage(fragment)]]
2801 fn via_ptr([[location(0)]] fragUV: vec2<f32>,
2802         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2803   return textureSample(myTexture, mySampler, fragUV) + fragPosition;
2804 }
2805 
2806 [[stage(fragment)]]
2807 fn direct([[location(0)]] fragUV: vec2<f32>,
2808         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2809   return textureSample(myTexture, mySampler, fragUV) + fragPosition;
2810 })";
2811 
2812   Inspector& inspector = Initialize(shader);
2813 
2814   {
2815     auto result = inspector.GetSamplerTextureUses("via_call");
2816     ASSERT_FALSE(inspector.has_error()) << inspector.error();
2817 
2818     ASSERT_EQ(1u, result.size());
2819 
2820     EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2821     EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2822     EXPECT_EQ(0u, result[0].texture_binding_point.group);
2823     EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2824   }
2825 
2826   {
2827     auto result = inspector.GetSamplerTextureUses("via_ptr");
2828     ASSERT_FALSE(inspector.has_error()) << inspector.error();
2829 
2830     ASSERT_EQ(1u, result.size());
2831 
2832     EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2833     EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2834     EXPECT_EQ(0u, result[0].texture_binding_point.group);
2835     EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2836   }
2837 
2838   {
2839     auto result = inspector.GetSamplerTextureUses("direct");
2840     ASSERT_FALSE(inspector.has_error()) << inspector.error();
2841 
2842     ASSERT_EQ(1u, result.size());
2843 
2844     EXPECT_EQ(0u, result[0].sampler_binding_point.group);
2845     EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
2846     EXPECT_EQ(0u, result[0].texture_binding_point.group);
2847     EXPECT_EQ(2u, result[0].texture_binding_point.binding);
2848   }
2849 }
2850 
TEST_F(InspectorGetWorkgroupStorageSizeTest,Empty)2851 TEST_F(InspectorGetWorkgroupStorageSizeTest, Empty) {
2852   MakeEmptyBodyFunction("ep_func",
2853                         ast::DecorationList{Stage(ast::PipelineStage::kCompute),
2854                                             WorkgroupSize(1)});
2855   Inspector& inspector = Build();
2856   EXPECT_EQ(0u, inspector.GetWorkgroupStorageSize("ep_func"));
2857 }
2858 
TEST_F(InspectorGetWorkgroupStorageSizeTest,Simple)2859 TEST_F(InspectorGetWorkgroupStorageSizeTest, Simple) {
2860   AddWorkgroupStorage("wg_f32", ty.f32());
2861   MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
2862 
2863   MakeCallerBodyFunction("ep_func", {"f32_func"},
2864                          ast::DecorationList{
2865                              Stage(ast::PipelineStage::kCompute),
2866                              WorkgroupSize(1),
2867                          });
2868 
2869   Inspector& inspector = Build();
2870   EXPECT_EQ(4u, inspector.GetWorkgroupStorageSize("ep_func"));
2871 }
2872 
TEST_F(InspectorGetWorkgroupStorageSizeTest,CompoundTypes)2873 TEST_F(InspectorGetWorkgroupStorageSizeTest, CompoundTypes) {
2874   // This struct should occupy 68 bytes. 4 from the i32 field, and another 64
2875   // from the 4-element array with 16-byte stride.
2876   auto* wg_struct_type = MakeStructType(
2877       "WgStruct", {ty.i32(), ty.array(ty.i32(), 4, /*stride=*/16)},
2878       /*is_block=*/false);
2879   AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
2880   MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
2881                                           {{0, ty.i32()}});
2882 
2883   // Plus another 4 bytes from this other workgroup-class f32.
2884   AddWorkgroupStorage("wg_f32", ty.f32());
2885   MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
2886 
2887   MakeCallerBodyFunction("ep_func", {"wg_struct_func", "f32_func"},
2888                          ast::DecorationList{
2889                              Stage(ast::PipelineStage::kCompute),
2890                              WorkgroupSize(1),
2891                          });
2892 
2893   Inspector& inspector = Build();
2894   EXPECT_EQ(72u, inspector.GetWorkgroupStorageSize("ep_func"));
2895 }
2896 
TEST_F(InspectorGetWorkgroupStorageSizeTest,AlignmentPadding)2897 TEST_F(InspectorGetWorkgroupStorageSizeTest, AlignmentPadding) {
2898   // vec3<f32> has an alignment of 16 but a size of 12. We leverage this to test
2899   // that our padded size calculation for workgroup storage is accurate.
2900   AddWorkgroupStorage("wg_vec3", ty.vec3<f32>());
2901   MakePlainGlobalReferenceBodyFunction("wg_func", "wg_vec3", ty.vec3<f32>(),
2902                                        {});
2903 
2904   MakeCallerBodyFunction("ep_func", {"wg_func"},
2905                          ast::DecorationList{
2906                              Stage(ast::PipelineStage::kCompute),
2907                              WorkgroupSize(1),
2908                          });
2909 
2910   Inspector& inspector = Build();
2911   EXPECT_EQ(16u, inspector.GetWorkgroupStorageSize("ep_func"));
2912 }
2913 
TEST_F(InspectorGetWorkgroupStorageSizeTest,StructAlignment)2914 TEST_F(InspectorGetWorkgroupStorageSizeTest, StructAlignment) {
2915   // Per WGSL spec, a struct's size is the offset its last member plus the size
2916   // of its last member, rounded up to the alignment of its largest member. So
2917   // here the struct is expected to occupy 1024 bytes of workgroup storage.
2918   const auto* wg_struct_type = MakeStructTypeFromMembers(
2919       "WgStruct",
2920       {MakeStructMember(0, ty.f32(),
2921                         {create<ast::StructMemberAlignDecoration>(1024)})},
2922       /*is_block=*/false);
2923 
2924   AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
2925   MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
2926                                           {{0, ty.f32()}});
2927 
2928   MakeCallerBodyFunction("ep_func", {"wg_struct_func"},
2929                          ast::DecorationList{
2930                              Stage(ast::PipelineStage::kCompute),
2931                              WorkgroupSize(1),
2932                          });
2933 
2934   Inspector& inspector = Build();
2935   EXPECT_EQ(1024u, inspector.GetWorkgroupStorageSize("ep_func"));
2936 }
2937 
2938 // Crash was occuring in ::GenerateSamplerTargets, when
2939 // ::GetSamplerTextureUses was called.
TEST_F(InspectorRegressionTest,tint967)2940 TEST_F(InspectorRegressionTest, tint967) {
2941   std::string shader = R"(
2942 [[group(0), binding(1)]] var mySampler: sampler;
2943 [[group(0), binding(2)]] var myTexture: texture_2d<f32>;
2944 
2945 fn doSample(t: texture_2d<f32>, s: sampler, uv: vec2<f32>) -> vec4<f32> {
2946   return textureSample(t, s, uv);
2947 }
2948 
2949 [[stage(fragment)]]
2950 fn main([[location(0)]] fragUV: vec2<f32>,
2951         [[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
2952   return doSample(myTexture, mySampler, fragUV) * fragPosition;
2953 })";
2954 
2955   Inspector& inspector = Initialize(shader);
2956   auto result = inspector.GetSamplerTextureUses("main");
2957 }
2958 
2959 }  // namespace
2960 }  // namespace inspector
2961 }  // namespace tint
2962