• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "gmock/gmock.h"
16 #include "src/ast/stage_decoration.h"
17 #include "src/ast/struct_block_decoration.h"
18 #include "src/ast/variable_decl_statement.h"
19 #include "src/ast/workgroup_decoration.h"
20 #include "src/writer/glsl/test_helper.h"
21 
22 using ::testing::HasSubstr;
23 
24 namespace tint {
25 namespace writer {
26 namespace glsl {
27 namespace {
28 
29 using GlslGeneratorImplTest_Function = TestHelper;
30 
TEST_F(GlslGeneratorImplTest_Function,Emit_Function)31 TEST_F(GlslGeneratorImplTest_Function, Emit_Function) {
32   Func("my_func", ast::VariableList{}, ty.void_(),
33        {
34            Return(),
35        });
36 
37   GeneratorImpl& gen = Build();
38 
39   gen.increment_indent();
40 
41   ASSERT_TRUE(gen.Generate()) << gen.error();
42   EXPECT_EQ(gen.result(), R"(  #version 310 es
43   precision mediump float;
44 
45   void my_func() {
46     return;
47   }
48 )");
49 }
50 
TEST_F(GlslGeneratorImplTest_Function,Emit_Function_Name_Collision)51 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
52   Func("centroid", ast::VariableList{}, ty.void_(),
53        {
54            Return(),
55        });
56 
57   GeneratorImpl& gen = SanitizeAndBuild();
58 
59   gen.increment_indent();
60 
61   ASSERT_TRUE(gen.Generate()) << gen.error();
62   EXPECT_THAT(gen.result(), HasSubstr(R"(  void tint_symbol() {
63     return;
64   })"));
65 }
66 
TEST_F(GlslGeneratorImplTest_Function,Emit_Function_WithParams)67 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithParams) {
68   Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())},
69        ty.void_(),
70        {
71            Return(),
72        });
73 
74   GeneratorImpl& gen = Build();
75 
76   gen.increment_indent();
77 
78   ASSERT_TRUE(gen.Generate()) << gen.error();
79   EXPECT_EQ(gen.result(), R"(  #version 310 es
80   precision mediump float;
81 
82   void my_func(float a, int b) {
83     return;
84   }
85 )");
86 }
87 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_NoReturn_Void)88 TEST_F(GlslGeneratorImplTest_Function,
89        Emit_Decoration_EntryPoint_NoReturn_Void) {
90   Func("func", ast::VariableList{}, ty.void_(), {/* no explicit return */},
91        {
92            Stage(ast::PipelineStage::kFragment),
93        });
94 
95   GeneratorImpl& gen = Build();
96 
97   ASSERT_TRUE(gen.Generate()) << gen.error();
98   EXPECT_EQ(gen.result(), R"(#version 310 es
99 precision mediump float;
100 
101 void func() {
102   return;
103 }
104 void main() {
105   func();
106 }
107 
108 
109 )");
110 }
111 
TEST_F(GlslGeneratorImplTest_Function,PtrParameter)112 TEST_F(GlslGeneratorImplTest_Function, PtrParameter) {
113   // fn f(foo : ptr<function, f32>) -> f32 {
114   //   return *foo;
115   // }
116   Func("f", {Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))},
117        ty.f32(), {Return(Deref("foo"))});
118 
119   GeneratorImpl& gen = SanitizeAndBuild();
120 
121   ASSERT_TRUE(gen.Generate()) << gen.error();
122   EXPECT_THAT(gen.result(), HasSubstr(R"(float f(inout float foo) {
123   return foo;
124 }
125 )"));
126 }
127 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_WithInOutVars)128 TEST_F(GlslGeneratorImplTest_Function,
129        Emit_Decoration_EntryPoint_WithInOutVars) {
130   // fn frag_main([[location(0)]] foo : f32) -> [[location(1)]] f32 {
131   //   return foo;
132   // }
133   auto* foo_in = Param("foo", ty.f32(), {Location(0)});
134   Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
135        {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
136 
137   GeneratorImpl& gen = SanitizeAndBuild();
138 
139   ASSERT_TRUE(gen.Generate()) << gen.error();
140   EXPECT_EQ(gen.result(), R"(#version 310 es
141 precision mediump float;
142 
143 struct tint_symbol_1 {
144   float foo;
145 };
146 struct tint_symbol_2 {
147   float value;
148 };
149 
150 float frag_main_inner(float foo) {
151   return foo;
152 }
153 
154 tint_symbol_2 frag_main(tint_symbol_1 tint_symbol) {
155   float inner_result = frag_main_inner(tint_symbol.foo);
156   tint_symbol_2 wrapper_result = tint_symbol_2(0.0f);
157   wrapper_result.value = inner_result;
158   return wrapper_result;
159 }
160 in float foo;
161 out float value;
162 void main() {
163   tint_symbol_1 inputs;
164   inputs.foo = foo;
165   tint_symbol_2 outputs;
166   outputs = frag_main(inputs);
167   value = outputs.value;
168 }
169 
170 
171 )");
172 }
173 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_WithInOut_Builtins)174 TEST_F(GlslGeneratorImplTest_Function,
175        Emit_Decoration_EntryPoint_WithInOut_Builtins) {
176   // fn frag_main([[position(0)]] coord : vec4<f32>) -> [[frag_depth]] f32 {
177   //   return coord.x;
178   // }
179   auto* coord_in =
180       Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
181   Func("frag_main", ast::VariableList{coord_in}, ty.f32(),
182        {Return(MemberAccessor("coord", "x"))},
183        {Stage(ast::PipelineStage::kFragment)},
184        {Builtin(ast::Builtin::kFragDepth)});
185 
186   GeneratorImpl& gen = SanitizeAndBuild();
187 
188   ASSERT_TRUE(gen.Generate()) << gen.error();
189   EXPECT_EQ(gen.result(), R"(#version 310 es
190 precision mediump float;
191 
192 struct tint_symbol_1 {
193   vec4 coord;
194 };
195 struct tint_symbol_2 {
196   float value;
197 };
198 
199 float frag_main_inner(vec4 coord) {
200   return coord.x;
201 }
202 
203 tint_symbol_2 frag_main(tint_symbol_1 tint_symbol) {
204   float inner_result = frag_main_inner(tint_symbol.coord);
205   tint_symbol_2 wrapper_result = tint_symbol_2(0.0f);
206   wrapper_result.value = inner_result;
207   return wrapper_result;
208 }
209 void main() {
210   tint_symbol_1 inputs;
211   inputs.coord = gl_FragCoord;
212   tint_symbol_2 outputs;
213   outputs = frag_main(inputs);
214   gl_FragDepth = outputs.value;
215 }
216 
217 
218 )");
219 }
220 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_SharedStruct_DifferentStages)221 TEST_F(GlslGeneratorImplTest_Function,
222        Emit_Decoration_EntryPoint_SharedStruct_DifferentStages) {
223   // struct Interface {
224   //   [[builtin(position)]] pos : vec4<f32>;
225   //   [[location(1)]] col1 : f32;
226   //   [[location(2)]] col2 : f32;
227   // };
228   // fn vert_main() -> Interface {
229   //   return Interface(vec4<f32>(), 0.4, 0.6);
230   // }
231   // fn frag_main(inputs : Interface) {
232   //   const r = inputs.col1;
233   //   const g = inputs.col2;
234   //   const p = inputs.pos;
235   // }
236   auto* interface_struct = Structure(
237       "Interface",
238       {
239           Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
240           Member("col1", ty.f32(), {Location(1)}),
241           Member("col2", ty.f32(), {Location(2)}),
242       });
243 
244   Func("vert_main", {}, ty.Of(interface_struct),
245        {Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()),
246                          Expr(0.5f), Expr(0.25f)))},
247        {Stage(ast::PipelineStage::kVertex)});
248 
249   Func("frag_main", {Param("inputs", ty.Of(interface_struct))}, ty.void_(),
250        {
251            Decl(Const("r", ty.f32(), MemberAccessor("inputs", "col1"))),
252            Decl(Const("g", ty.f32(), MemberAccessor("inputs", "col2"))),
253            Decl(Const("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
254        },
255        {Stage(ast::PipelineStage::kFragment)});
256 
257   GeneratorImpl& gen = SanitizeAndBuild();
258 
259   ASSERT_TRUE(gen.Generate()) << gen.error();
260   EXPECT_EQ(gen.result(), R"(#version 310 es
261 precision mediump float;
262 
263 struct Interface {
264   vec4 pos;
265   float col1;
266   float col2;
267 };
268 struct tint_symbol {
269   float col1;
270   float col2;
271   vec4 pos;
272 };
273 
274 Interface vert_main_inner() {
275   Interface tint_symbol_3 = Interface(vec4(0.0f, 0.0f, 0.0f, 0.0f), 0.5f, 0.25f);
276   return tint_symbol_3;
277 }
278 
279 tint_symbol vert_main() {
280   Interface inner_result = vert_main_inner();
281   tint_symbol wrapper_result = tint_symbol(0.0f, 0.0f, vec4(0.0f, 0.0f, 0.0f, 0.0f));
282   wrapper_result.pos = inner_result.pos;
283   wrapper_result.col1 = inner_result.col1;
284   wrapper_result.col2 = inner_result.col2;
285   return wrapper_result;
286 }
287 out float col1;
288 out float col2;
289 void main() {
290   tint_symbol outputs;
291   outputs = vert_main();
292   col1 = outputs.col1;
293   col2 = outputs.col2;
294   gl_Position = outputs.pos;
295   gl_Position.y = -gl_Position.y;
296 }
297 
298 
299 
300 struct tint_symbol_2 {
301   float col1;
302   float col2;
303   vec4 pos;
304 };
305 
306 void frag_main_inner(Interface inputs) {
307   float r = inputs.col1;
308   float g = inputs.col2;
309   vec4 p = inputs.pos;
310 }
311 
312 void frag_main(tint_symbol_2 tint_symbol_1) {
313   Interface tint_symbol_4 = Interface(tint_symbol_1.pos, tint_symbol_1.col1, tint_symbol_1.col2);
314   frag_main_inner(tint_symbol_4);
315   return;
316 }
317 in float col1;
318 in float col2;
319 void main() {
320   tint_symbol_2 inputs;
321   inputs.col1 = col1;
322   inputs.col2 = col2;
323   inputs.pos = gl_FragCoord;
324   frag_main(inputs);
325 }
326 
327 
328 )");
329 }
330 
331 #if 0
332 TEST_F(GlslGeneratorImplTest_Function,
333        Emit_Decoration_EntryPoint_SharedStruct_HelperFunction) {
334   // struct VertexOutput {
335   //   [[builtin(position)]] pos : vec4<f32>;
336   // };
337   // fn foo(x : f32) -> VertexOutput {
338   //   return VertexOutput(vec4<f32>(x, x, x, 1.0));
339   // }
340   // fn vert_main1() -> VertexOutput {
341   //   return foo(0.5);
342   // }
343   // fn vert_main2() -> VertexOutput {
344   //   return foo(0.25);
345   // }
346   auto* vertex_output_struct = Structure(
347       "VertexOutput",
348       {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
349 
350   Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
351        {Return(Construct(ty.Of(vertex_output_struct),
352                          Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1.f))))},
353        {});
354 
355   Func("vert_main1", {}, ty.Of(vertex_output_struct),
356        {Return(Construct(ty.Of(vertex_output_struct),
357                          Expr(Call("foo", Expr(0.5f)))))},
358        {Stage(ast::PipelineStage::kVertex)});
359 
360   Func("vert_main2", {}, ty.Of(vertex_output_struct),
361        {Return(Construct(ty.Of(vertex_output_struct),
362                          Expr(Call("foo", Expr(0.25f)))))},
363        {Stage(ast::PipelineStage::kVertex)});
364 
365   GeneratorImpl& gen = SanitizeAndBuild();
366 
367   ASSERT_TRUE(gen.Generate()) << gen.error();
368   EXPECT_EQ(gen.result(), R"(struct VertexOutput {
369   float4 pos;
370 };
371 
372 VertexOutput foo(float x) {
373   const VertexOutput tint_symbol_4 = {float4(x, x, x, 1.0f)};
374   return tint_symbol_4;
375 }
376 
377 struct tint_symbol {
378   float4 pos : SV_Position;
379 };
380 
381 tint_symbol vert_main1() {
382   const VertexOutput tint_symbol_1 = {foo(0.5f)};
383   const tint_symbol tint_symbol_5 = {tint_symbol_1.pos};
384   return tint_symbol_5;
385 }
386 
387 struct tint_symbol_2 {
388   float4 pos : SV_Position;
389 };
390 
391 tint_symbol_2 vert_main2() {
392   const VertexOutput tint_symbol_3 = {foo(0.25f)};
393   const tint_symbol_2 tint_symbol_6 = {tint_symbol_3.pos};
394   return tint_symbol_6;
395 }
396 )");
397 }
398 #endif
399 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_With_Uniform)400 TEST_F(GlslGeneratorImplTest_Function,
401        Emit_Decoration_EntryPoint_With_Uniform) {
402   auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
403                            {create<ast::StructBlockDecoration>()});
404   auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
405                      ast::DecorationList{
406                          create<ast::BindingDecoration>(0),
407                          create<ast::GroupDecoration>(1),
408                      });
409 
410   Func("sub_func",
411        {
412            Param("param", ty.f32()),
413        },
414        ty.f32(),
415        {
416            Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
417        });
418 
419   auto* var =
420       Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
421 
422   Func("frag_main", {}, ty.void_(),
423        {
424            Decl(var),
425            Return(),
426        },
427        {
428            Stage(ast::PipelineStage::kFragment),
429        });
430 
431   GeneratorImpl& gen = Build();
432 
433   ASSERT_TRUE(gen.Generate()) << gen.error();
434   EXPECT_EQ(gen.result(), R"(#version 310 es
435 precision mediump float;
436 
437 
438 layout (binding = 0) uniform UBO_1 {
439   vec4 coord;
440 } ubo;
441 
442 float sub_func(float param) {
443   return ubo.coord.x;
444 }
445 
446 void frag_main() {
447   float v = sub_func(1.0f);
448   return;
449 }
450 void main() {
451   frag_main();
452 }
453 
454 
455 )");
456 }
457 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_With_UniformStruct)458 TEST_F(GlslGeneratorImplTest_Function,
459        Emit_Decoration_EntryPoint_With_UniformStruct) {
460   auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
461                       {create<ast::StructBlockDecoration>()});
462 
463   Global("uniforms", ty.Of(s), ast::StorageClass::kUniform,
464          ast::DecorationList{
465              create<ast::BindingDecoration>(0),
466              create<ast::GroupDecoration>(1),
467          });
468 
469   auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
470                   MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
471 
472   Func("frag_main", ast::VariableList{}, ty.void_(),
473        {
474            Decl(var),
475            Return(),
476        },
477        {
478            Stage(ast::PipelineStage::kFragment),
479        });
480 
481   GeneratorImpl& gen = Build();
482 
483   ASSERT_TRUE(gen.Generate()) << gen.error();
484   EXPECT_EQ(gen.result(), R"(#version 310 es
485 precision mediump float;
486 
487 
488 layout (binding = 0) uniform Uniforms_1 {
489   vec4 coord;
490 } uniforms;
491 
492 void frag_main() {
493   float v = uniforms.coord.x;
494   return;
495 }
496 void main() {
497   frag_main();
498 }
499 
500 
501 )");
502 }
503 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_With_RW_StorageBuffer_Read)504 TEST_F(GlslGeneratorImplTest_Function,
505        Emit_Decoration_EntryPoint_With_RW_StorageBuffer_Read) {
506   auto* s = Structure("Data",
507                       {
508                           Member("a", ty.i32()),
509                           Member("b", ty.f32()),
510                       },
511                       {create<ast::StructBlockDecoration>()});
512 
513   Global("coord", ty.Of(s), ast::StorageClass::kStorage,
514          ast::Access::kReadWrite,
515          ast::DecorationList{
516              create<ast::BindingDecoration>(0),
517              create<ast::GroupDecoration>(1),
518          });
519 
520   auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
521                   MemberAccessor("coord", "b"));
522 
523   Func("frag_main", ast::VariableList{}, ty.void_(),
524        {
525            Decl(var),
526            Return(),
527        },
528        {
529            Stage(ast::PipelineStage::kFragment),
530        });
531 
532   GeneratorImpl& gen = SanitizeAndBuild();
533 
534   ASSERT_TRUE(gen.Generate()) << gen.error();
535   EXPECT_EQ(gen.result(), R"(#version 310 es
536 precision mediump float;
537 
538 
539 layout (binding = 0) buffer Data_1 {
540   int a;
541   float b;
542 } coord;
543 
544 void frag_main() {
545   float v = coord.b;
546   return;
547 }
548 void main() {
549   frag_main();
550 }
551 
552 
553 )");
554 }
555 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_With_RO_StorageBuffer_Read)556 TEST_F(GlslGeneratorImplTest_Function,
557        Emit_Decoration_EntryPoint_With_RO_StorageBuffer_Read) {
558   auto* s = Structure("Data",
559                       {
560                           Member("a", ty.i32()),
561                           Member("b", ty.f32()),
562                       },
563                       {create<ast::StructBlockDecoration>()});
564 
565   Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
566          ast::DecorationList{
567              create<ast::BindingDecoration>(0),
568              create<ast::GroupDecoration>(1),
569          });
570 
571   auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
572                   MemberAccessor("coord", "b"));
573 
574   Func("frag_main", ast::VariableList{}, ty.void_(),
575        {
576            Decl(var),
577            Return(),
578        },
579        {
580            Stage(ast::PipelineStage::kFragment),
581        });
582 
583   GeneratorImpl& gen = SanitizeAndBuild();
584 
585   ASSERT_TRUE(gen.Generate()) << gen.error();
586   EXPECT_EQ(gen.result(),
587             R"(#version 310 es
588 precision mediump float;
589 
590 
591 layout (binding = 0) buffer Data_1 {
592   int a;
593   float b;
594 } coord;
595 
596 void frag_main() {
597   float v = coord.b;
598   return;
599 }
600 void main() {
601   frag_main();
602 }
603 
604 
605 )");
606 }
607 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_With_WO_StorageBuffer_Store)608 TEST_F(GlslGeneratorImplTest_Function,
609        Emit_Decoration_EntryPoint_With_WO_StorageBuffer_Store) {
610   auto* s = Structure("Data",
611                       {
612                           Member("a", ty.i32()),
613                           Member("b", ty.f32()),
614                       },
615                       {create<ast::StructBlockDecoration>()});
616 
617   Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
618          ast::DecorationList{
619              create<ast::BindingDecoration>(0),
620              create<ast::GroupDecoration>(1),
621          });
622 
623   Func("frag_main", ast::VariableList{}, ty.void_(),
624        {
625            Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
626            Return(),
627        },
628        {
629            Stage(ast::PipelineStage::kFragment),
630        });
631 
632   GeneratorImpl& gen = SanitizeAndBuild();
633 
634   ASSERT_TRUE(gen.Generate()) << gen.error();
635   EXPECT_EQ(gen.result(), R"(#version 310 es
636 precision mediump float;
637 
638 
639 layout (binding = 0) buffer Data_1 {
640   int a;
641   float b;
642 } coord;
643 
644 void frag_main() {
645   coord.b = 2.0f;
646   return;
647 }
648 void main() {
649   frag_main();
650 }
651 
652 
653 )");
654 }
655 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_With_StorageBuffer_Store)656 TEST_F(GlslGeneratorImplTest_Function,
657        Emit_Decoration_EntryPoint_With_StorageBuffer_Store) {
658   auto* s = Structure("Data",
659                       {
660                           Member("a", ty.i32()),
661                           Member("b", ty.f32()),
662                       },
663                       {create<ast::StructBlockDecoration>()});
664 
665   Global("coord", ty.Of(s), ast::StorageClass::kStorage,
666          ast::Access::kReadWrite,
667          ast::DecorationList{
668              create<ast::BindingDecoration>(0),
669              create<ast::GroupDecoration>(1),
670          });
671 
672   Func("frag_main", ast::VariableList{}, ty.void_(),
673        {
674            Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
675            Return(),
676        },
677        {
678            Stage(ast::PipelineStage::kFragment),
679        });
680 
681   GeneratorImpl& gen = SanitizeAndBuild();
682 
683   ASSERT_TRUE(gen.Generate()) << gen.error();
684   EXPECT_EQ(gen.result(), R"(#version 310 es
685 precision mediump float;
686 
687 
688 layout (binding = 0) buffer Data_1 {
689   int a;
690   float b;
691 } coord;
692 
693 void frag_main() {
694   coord.b = 2.0f;
695   return;
696 }
697 void main() {
698   frag_main();
699 }
700 
701 
702 )");
703 }
704 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_Called_By_EntryPoint_With_Uniform)705 TEST_F(GlslGeneratorImplTest_Function,
706        Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
707   auto* s = Structure("S", {Member("x", ty.f32())},
708                       {create<ast::StructBlockDecoration>()});
709   Global("coord", ty.Of(s), ast::StorageClass::kUniform,
710          ast::DecorationList{
711              create<ast::BindingDecoration>(0),
712              create<ast::GroupDecoration>(1),
713          });
714 
715   Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
716        {
717            Return(MemberAccessor("coord", "x")),
718        });
719 
720   auto* var =
721       Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
722 
723   Func("frag_main", ast::VariableList{}, ty.void_(),
724        {
725            Decl(var),
726            Return(),
727        },
728        {
729            Stage(ast::PipelineStage::kFragment),
730        });
731 
732   GeneratorImpl& gen = Build();
733 
734   ASSERT_TRUE(gen.Generate()) << gen.error();
735   EXPECT_EQ(gen.result(), R"(#version 310 es
736 precision mediump float;
737 
738 
739 layout (binding = 0) uniform S_1 {
740   float x;
741 } coord;
742 
743 float sub_func(float param) {
744   return coord.x;
745 }
746 
747 void frag_main() {
748   float v = sub_func(1.0f);
749   return;
750 }
751 void main() {
752   frag_main();
753 }
754 
755 
756 )");
757 }
758 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer)759 TEST_F(GlslGeneratorImplTest_Function,
760        Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) {
761   auto* s = Structure("S", {Member("x", ty.f32())},
762                       {create<ast::StructBlockDecoration>()});
763   Global("coord", ty.Of(s), ast::StorageClass::kStorage,
764          ast::Access::kReadWrite,
765          ast::DecorationList{
766              create<ast::BindingDecoration>(0),
767              create<ast::GroupDecoration>(1),
768          });
769 
770   Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
771        {
772            Return(MemberAccessor("coord", "x")),
773        });
774 
775   auto* var =
776       Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
777 
778   Func("frag_main", ast::VariableList{}, ty.void_(),
779        {
780            Decl(var),
781            Return(),
782        },
783        {
784            Stage(ast::PipelineStage::kFragment),
785        });
786 
787   GeneratorImpl& gen = SanitizeAndBuild();
788 
789   ASSERT_TRUE(gen.Generate()) << gen.error();
790   EXPECT_EQ(gen.result(),
791             R"(#version 310 es
792 precision mediump float;
793 
794 
795 layout (binding = 0) buffer S_1 {
796   float x;
797 } coord;
798 
799 float sub_func(float param) {
800   return coord.x;
801 }
802 
803 void frag_main() {
804   float v = sub_func(1.0f);
805   return;
806 }
807 void main() {
808   frag_main();
809 }
810 
811 
812 )");
813 }
814 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_WithNameCollision)815 TEST_F(GlslGeneratorImplTest_Function,
816        Emit_Decoration_EntryPoint_WithNameCollision) {
817   Func("centroid", ast::VariableList{}, ty.void_(), {},
818        {
819            Stage(ast::PipelineStage::kFragment),
820        });
821 
822   GeneratorImpl& gen = SanitizeAndBuild();
823 
824   ASSERT_TRUE(gen.Generate()) << gen.error();
825   EXPECT_EQ(gen.result(), R"(#version 310 es
826 precision mediump float;
827 
828 void tint_symbol() {
829   return;
830 }
831 void main() {
832   tint_symbol();
833 }
834 
835 
836 )");
837 }
838 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_Compute)839 TEST_F(GlslGeneratorImplTest_Function, Emit_Decoration_EntryPoint_Compute) {
840   Func("main", ast::VariableList{}, ty.void_(),
841        {
842            Return(),
843        },
844        {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
845 
846   GeneratorImpl& gen = Build();
847 
848   ASSERT_TRUE(gen.Generate()) << gen.error();
849   EXPECT_EQ(gen.result(), R"(#version 310 es
850 precision mediump float;
851 
852 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
853 void main() {
854   return;
855 }
856 void main() {
857   main();
858 }
859 
860 
861 )");
862 }
863 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_Compute_WithWorkgroup_Literal)864 TEST_F(GlslGeneratorImplTest_Function,
865        Emit_Decoration_EntryPoint_Compute_WithWorkgroup_Literal) {
866   Func("main", ast::VariableList{}, ty.void_(), {},
867        {
868            Stage(ast::PipelineStage::kCompute),
869            WorkgroupSize(2, 4, 6),
870        });
871 
872   GeneratorImpl& gen = Build();
873 
874   ASSERT_TRUE(gen.Generate()) << gen.error();
875   EXPECT_EQ(gen.result(), R"(#version 310 es
876 precision mediump float;
877 
878 layout(local_size_x = 2, local_size_y = 4, local_size_z = 6) in;
879 void main() {
880   return;
881 }
882 void main() {
883   main();
884 }
885 
886 
887 )");
888 }
889 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_Compute_WithWorkgroup_Const)890 TEST_F(GlslGeneratorImplTest_Function,
891        Emit_Decoration_EntryPoint_Compute_WithWorkgroup_Const) {
892   GlobalConst("width", ty.i32(), Construct(ty.i32(), 2));
893   GlobalConst("height", ty.i32(), Construct(ty.i32(), 3));
894   GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4));
895   Func("main", ast::VariableList{}, ty.void_(), {},
896        {
897            Stage(ast::PipelineStage::kCompute),
898            WorkgroupSize("width", "height", "depth"),
899        });
900 
901   GeneratorImpl& gen = Build();
902 
903   ASSERT_TRUE(gen.Generate()) << gen.error();
904   EXPECT_EQ(gen.result(), R"(#version 310 es
905 precision mediump float;
906 
907 const int width = int(2);
908 const int height = int(3);
909 const int depth = int(4);
910 
911 layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) in;
912 void main() {
913   return;
914 }
915 void main() {
916   main();
917 }
918 
919 
920 )");
921 }
922 
TEST_F(GlslGeneratorImplTest_Function,Emit_Decoration_EntryPoint_Compute_WithWorkgroup_OverridableConst)923 TEST_F(GlslGeneratorImplTest_Function,
924        Emit_Decoration_EntryPoint_Compute_WithWorkgroup_OverridableConst) {
925   GlobalConst("width", ty.i32(), Construct(ty.i32(), 2), {Override(7u)});
926   GlobalConst("height", ty.i32(), Construct(ty.i32(), 3), {Override(8u)});
927   GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4), {Override(9u)});
928   Func("main", ast::VariableList{}, ty.void_(), {},
929        {
930            Stage(ast::PipelineStage::kCompute),
931            WorkgroupSize("width", "height", "depth"),
932        });
933 
934   GeneratorImpl& gen = Build();
935 
936   ASSERT_TRUE(gen.Generate()) << gen.error();
937   EXPECT_EQ(gen.result(), R"(#version 310 es
938 precision mediump float;
939 
940 #ifndef WGSL_SPEC_CONSTANT_7
941 #define WGSL_SPEC_CONSTANT_7 int(2)
942 #endif
943 const int width = WGSL_SPEC_CONSTANT_7;
944 #ifndef WGSL_SPEC_CONSTANT_8
945 #define WGSL_SPEC_CONSTANT_8 int(3)
946 #endif
947 const int height = WGSL_SPEC_CONSTANT_8;
948 #ifndef WGSL_SPEC_CONSTANT_9
949 #define WGSL_SPEC_CONSTANT_9 int(4)
950 #endif
951 const int depth = WGSL_SPEC_CONSTANT_9;
952 
953 layout(local_size_x = WGSL_SPEC_CONSTANT_7, local_size_y = WGSL_SPEC_CONSTANT_8, local_size_z = WGSL_SPEC_CONSTANT_9) in;
954 void main() {
955   return;
956 }
957 void main() {
958   main();
959 }
960 
961 
962 )");
963 }
964 
TEST_F(GlslGeneratorImplTest_Function,Emit_Function_WithArrayParams)965 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
966   Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
967        {
968            Return(),
969        });
970 
971   GeneratorImpl& gen = Build();
972 
973   ASSERT_TRUE(gen.Generate()) << gen.error();
974   EXPECT_EQ(gen.result(), R"(#version 310 es
975 precision mediump float;
976 
977 void my_func(float a[5]) {
978   return;
979 }
980 )");
981 }
982 
TEST_F(GlslGeneratorImplTest_Function,Emit_Function_WithArrayReturn)983 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithArrayReturn) {
984   Func("my_func", {}, ty.array<f32, 5>(),
985        {
986            Return(Construct(ty.array<f32, 5>())),
987        });
988 
989   GeneratorImpl& gen = Build();
990 
991   ASSERT_TRUE(gen.Generate()) << gen.error();
992   EXPECT_EQ(gen.result(), R"(#version 310 es
993 precision mediump float;
994 
995 float[5] my_func() {
996   return float[5](0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
997 }
998 )");
999 }
1000 
1001 // https://crbug.com/tint/297
TEST_F(GlslGeneratorImplTest_Function,Emit_Multiple_EntryPoint_With_Same_ModuleVar)1002 TEST_F(GlslGeneratorImplTest_Function,
1003        Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
1004   // [[block]] struct Data {
1005   //   d : f32;
1006   // };
1007   // [[binding(0), group(0)]] var<storage> data : Data;
1008   //
1009   // [[stage(compute), workgroup_size(1)]]
1010   // fn a() {
1011   //   var v = data.d;
1012   //   return;
1013   // }
1014   //
1015   // [[stage(compute), workgroup_size(1)]]
1016   // fn b() {
1017   //   var v = data.d;
1018   //   return;
1019   // }
1020 
1021   auto* s = Structure("Data", {Member("d", ty.f32())},
1022                       {create<ast::StructBlockDecoration>()});
1023 
1024   Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
1025          ast::DecorationList{
1026              create<ast::BindingDecoration>(0),
1027              create<ast::GroupDecoration>(0),
1028          });
1029 
1030   {
1031     auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
1032                     MemberAccessor("data", "d"));
1033 
1034     Func("a", ast::VariableList{}, ty.void_(),
1035          {
1036              Decl(var),
1037              Return(),
1038          },
1039          {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
1040   }
1041 
1042   {
1043     auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
1044                     MemberAccessor("data", "d"));
1045 
1046     Func("b", ast::VariableList{}, ty.void_(),
1047          {
1048              Decl(var),
1049              Return(),
1050          },
1051          {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
1052   }
1053 
1054   GeneratorImpl& gen = SanitizeAndBuild();
1055 
1056   ASSERT_TRUE(gen.Generate()) << gen.error();
1057   EXPECT_EQ(gen.result(), R"(#version 310 es
1058 precision mediump float;
1059 
1060 
1061 layout (binding = 0) buffer Data_1 {
1062   float d;
1063 } data;
1064 
1065 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
1066 void a() {
1067   float v = data.d;
1068   return;
1069 }
1070 void main() {
1071   a();
1072 }
1073 
1074 
1075 
1076 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
1077 void b() {
1078   float v = data.d;
1079   return;
1080 }
1081 void main() {
1082   b();
1083 }
1084 
1085 
1086 )");
1087 }
1088 
1089 }  // namespace
1090 }  // namespace glsl
1091 }  // namespace writer
1092 }  // namespace tint
1093