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