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