1 //
2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // MSLOutput_test.cpp:
7 // Tests for MSL output.
8 //
9
10 #include <regex>
11 #include "GLSLANG/ShaderLang.h"
12 #include "angle_gl.h"
13 #include "gtest/gtest.h"
14 #include "tests/test_utils/compiler_test.h"
15
16 using namespace sh;
17
18 class MSLVertexOutputTest : public MatchOutputCodeTest
19 {
20 public:
MSLVertexOutputTest()21 MSLVertexOutputTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_MSL_METAL_OUTPUT)
22 {
23 ShCompileOptions defaultCompileOptions = {};
24 defaultCompileOptions.validateAST = true;
25 setDefaultCompileOptions(defaultCompileOptions);
26 }
27 };
28
29 class MSLOutputTest : public MatchOutputCodeTest
30 {
31 public:
MSLOutputTest()32 MSLOutputTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_MSL_METAL_OUTPUT)
33 {
34 ShCompileOptions defaultCompileOptions = {};
35 defaultCompileOptions.rescopeGlobalVariables = true;
36 defaultCompileOptions.validateAST = true;
37 setDefaultCompileOptions(defaultCompileOptions);
38 }
39 };
40
41 // Test that having dynamic indexing of a vector inside the right hand side of logical or doesn't
42 // trigger asserts in MSL output.
TEST_F(MSLOutputTest,DynamicIndexingOfVectorOnRightSideOfLogicalOr)43 TEST_F(MSLOutputTest, DynamicIndexingOfVectorOnRightSideOfLogicalOr)
44 {
45 const std::string &shaderString =
46 "#version 300 es\n"
47 "precision highp float;\n"
48 "out vec4 my_FragColor;\n"
49 "uniform int u1;\n"
50 "void main() {\n"
51 " bvec4 v = bvec4(true, true, true, false);\n"
52 " my_FragColor = vec4(v[u1 + 1] || v[u1]);\n"
53 "}\n";
54 compile(shaderString);
55 }
56
57 // Test that having an array constructor as a statement doesn't trigger an assert in MSL output.
TEST_F(MSLOutputTest,ArrayConstructorStatement)58 TEST_F(MSLOutputTest, ArrayConstructorStatement)
59 {
60 const std::string &shaderString =
61 R"(#version 300 es
62 precision mediump float;
63 out vec4 outColor;
64 void main()
65 {
66 outColor = vec4(0.0, 0.0, 0.0, 1.0);
67 float[1](outColor[1]++);
68 })";
69 compile(shaderString);
70 }
71
72 // Test an array of arrays constructor as a statement.
TEST_F(MSLOutputTest,ArrayOfArraysStatement)73 TEST_F(MSLOutputTest, ArrayOfArraysStatement)
74 {
75 const std::string &shaderString =
76 R"(#version 310 es
77 precision mediump float;
78 out vec4 outColor;
79 void main()
80 {
81 outColor = vec4(0.0, 0.0, 0.0, 1.0);
82 float[2][2](float[2](outColor[1]++, 0.0), float[2](1.0, 2.0));
83 })";
84 compile(shaderString);
85 }
86
87 // Test dynamic indexing of a vector. This makes sure that helper functions added for dynamic
88 // indexing have correct data that subsequent traversal steps rely on.
TEST_F(MSLOutputTest,VectorDynamicIndexing)89 TEST_F(MSLOutputTest, VectorDynamicIndexing)
90 {
91 const std::string &shaderString =
92 R"(#version 300 es
93 precision mediump float;
94 out vec4 outColor;
95 uniform int i;
96 void main()
97 {
98 vec4 foo = vec4(0.0, 0.0, 0.0, 1.0);
99 foo[i] = foo[i + 1];
100 outColor = foo;
101 })";
102 compile(shaderString);
103 }
104
105 // Test returning an array from a user-defined function. This makes sure that function symbols are
106 // changed consistently when the user-defined function is changed to have an array out parameter.
TEST_F(MSLOutputTest,ArrayReturnValue)107 TEST_F(MSLOutputTest, ArrayReturnValue)
108 {
109 const std::string &shaderString =
110 R"(#version 300 es
111 precision mediump float;
112 uniform float u;
113 out vec4 outColor;
114
115 float[2] getArray(float f)
116 {
117 return float[2](f, f + 1.0);
118 }
119
120 void main()
121 {
122 float[2] arr = getArray(u);
123 outColor = vec4(arr[0], arr[1], 0.0, 1.0);
124 })";
125 compile(shaderString);
126 }
127
128 // Test that writing parameters without a name doesn't assert.
TEST_F(MSLOutputTest,ParameterWithNoName)129 TEST_F(MSLOutputTest, ParameterWithNoName)
130 {
131 const std::string &shaderString =
132 R"(precision mediump float;
133
134 uniform vec4 v;
135
136 vec4 s(vec4)
137 {
138 return v;
139 }
140 void main()
141 {
142 gl_FragColor = s(v);
143 })";
144 compile(shaderString);
145 }
146
TEST_F(MSLOutputTest,Macro)147 TEST_F(MSLOutputTest, Macro)
148 {
149 const std::string &shaderString =
150 R"(#version 300 es
151 precision highp float;
152
153 #define FOO vec4
154
155 out vec4 outColor;
156
157 void main()
158 {
159 outColor = FOO(1.0, 2.0, 3.0, 4.0);
160 })";
161 compile(shaderString);
162 }
163
TEST_F(MSLOutputTest,UniformSimple)164 TEST_F(MSLOutputTest, UniformSimple)
165 {
166 const std::string &shaderString =
167 R"(#version 300 es
168 precision highp float;
169
170 out vec4 outColor;
171 uniform float x;
172
173 void main()
174 {
175 outColor = vec4(x, x, x, x);
176 })";
177 compile(shaderString);
178 }
179
TEST_F(MSLOutputTest,FragmentOutSimple)180 TEST_F(MSLOutputTest, FragmentOutSimple)
181 {
182 const std::string &shaderString =
183 R"(#version 300 es
184 precision highp float;
185
186 out vec4 outColor;
187
188 void main()
189 {
190 outColor = vec4(1.0, 2.0, 3.0, 4.0);
191 })";
192 compile(shaderString);
193 }
194
TEST_F(MSLOutputTest,FragmentOutIndirect1)195 TEST_F(MSLOutputTest, FragmentOutIndirect1)
196 {
197 const std::string &shaderString =
198 R"(#version 300 es
199 precision highp float;
200
201 out vec4 outColor;
202
203 void foo()
204 {
205 outColor = vec4(1.0, 2.0, 3.0, 4.0);
206 }
207
208 void bar()
209 {
210 foo();
211 }
212
213 void main()
214 {
215 bar();
216 })";
217 compile(shaderString);
218 }
219
TEST_F(MSLOutputTest,FragmentOutIndirect2)220 TEST_F(MSLOutputTest, FragmentOutIndirect2)
221 {
222 const std::string &shaderString =
223 R"(#version 300 es
224 precision highp float;
225
226 out vec4 outColor;
227
228 void foo();
229
230 void bar()
231 {
232 foo();
233 }
234
235 void foo()
236 {
237 outColor = vec4(1.0, 2.0, 3.0, 4.0);
238 }
239
240 void main()
241 {
242 bar();
243 })";
244 compile(shaderString);
245 }
246
TEST_F(MSLOutputTest,FragmentOutIndirect3)247 TEST_F(MSLOutputTest, FragmentOutIndirect3)
248 {
249 const std::string &shaderString =
250 R"(#version 300 es
251 precision highp float;
252
253 out vec4 outColor;
254
255 float foo(float x, float y)
256 {
257 outColor = vec4(x, y, 3.0, 4.0);
258 return 7.0;
259 }
260
261 float bar(float x)
262 {
263 return foo(x, 2.0);
264 }
265
266 float baz()
267 {
268 return 13.0;
269 }
270
271 float identity(float x)
272 {
273 return x;
274 }
275
276 void main()
277 {
278 identity(bar(baz()));
279 })";
280 compile(shaderString);
281 }
282
TEST_F(MSLOutputTest,VertexInOut)283 TEST_F(MSLOutputTest, VertexInOut)
284 {
285 const std::string &shaderString =
286 R"(#version 300 es
287 precision highp float;
288 in float in0;
289 out float out0;
290 void main()
291 {
292 out0 = in0;
293 })";
294 compile(shaderString);
295 }
296
TEST_F(MSLOutputTest,SymbolSharing)297 TEST_F(MSLOutputTest, SymbolSharing)
298 {
299 const std::string &shaderString =
300 R"(#version 300 es
301 precision highp float;
302
303 out vec4 outColor;
304
305 struct Foo {
306 float x;
307 float y;
308 };
309
310 void doFoo(Foo foo, float zw);
311
312 void doFoo(Foo foo, float zw)
313 {
314 foo.x = foo.y;
315 outColor = vec4(foo.x, foo.y, zw, zw);
316 }
317
318 void main()
319 {
320 Foo foo;
321 foo.x = 2.0;
322 foo.y = 2.0;
323 doFoo(foo, 3.0);
324 })";
325 compile(shaderString);
326 }
327
TEST_F(MSLOutputTest,StructDecl)328 TEST_F(MSLOutputTest, StructDecl)
329 {
330 const std::string &shaderString =
331 R"(#version 300 es
332 precision highp float;
333
334 out float out0;
335
336 struct Foo {
337 float value;
338 };
339
340 void main()
341 {
342 Foo foo;
343 out0 = foo.value;
344 }
345 )";
346 compile(shaderString);
347 }
348
TEST_F(MSLOutputTest,Structs)349 TEST_F(MSLOutputTest, Structs)
350 {
351 const std::string &shaderString =
352 R"(#version 300 es
353 precision highp float;
354
355 struct Foo {
356 float value;
357 };
358
359 out vec4 out0;
360
361 struct Bar {
362 Foo foo;
363 };
364
365 void go();
366
367 uniform UniInstance {
368 Bar bar;
369 float instance;
370 } uniInstance;
371
372 uniform UniGlobal {
373 Foo foo;
374 float global;
375 };
376
377 void main()
378 {
379 go();
380 }
381
382 struct Baz {
383 Bar bar;
384 } baz;
385
386 void go()
387 {
388 out0.x = baz.bar.foo.value;
389 out0.y = global;
390 out0.z = uniInstance.instance;
391 out0.w = 0.0;
392 }
393
394 )";
395 compile(shaderString);
396 }
397
TEST_F(MSLOutputTest,KeywordConflict)398 TEST_F(MSLOutputTest, KeywordConflict)
399 {
400 const std::string &shaderString =
401 R"(#version 300 es
402 precision highp float;
403
404 struct fragment {
405 float kernel;
406 } device;
407
408 struct Foo {
409 fragment frag;
410 } foo;
411
412 out float vertex;
413 float kernel;
414
415 float stage_in(float x)
416 {
417 return x;
418 }
419
420 void metal(float metal, float fragment);
421 void metal(float metal, float fragment)
422 {
423 vertex = metal * fragment * foo.frag.kernel;
424 }
425
426 void main()
427 {
428 metal(stage_in(stage_in(kernel * device.kernel)), foo.frag.kernel);
429 })";
430 compile(shaderString);
431 }
432
TEST_F(MSLVertexOutputTest,Vertex)433 TEST_F(MSLVertexOutputTest, Vertex)
434 {
435 const std::string &shaderString =
436 R"(#version 300 es
437 precision highp float;
438 void main()
439 {
440 gl_Position = vec4(1.0,1.0,1.0,1.0);
441 })";
442 compile(shaderString);
443 }
444
TEST_F(MSLVertexOutputTest,LastReturn)445 TEST_F(MSLVertexOutputTest, LastReturn)
446 {
447 const std::string &shaderString =
448 R"(#version 300 es
449 in highp vec4 a_position;
450 in highp vec4 a_coords;
451 out highp vec4 v_color;
452
453 void main (void)
454 {
455 gl_Position = a_position;
456 v_color = vec4(a_coords.xyz, 1.0);
457 return;
458 })";
459 compile(shaderString);
460 }
461
TEST_F(MSLOutputTest,LastReturn)462 TEST_F(MSLOutputTest, LastReturn)
463 {
464 const std::string &shaderString =
465 R"(#version 300 es
466 in mediump vec4 v_coords;
467 layout(location = 0) out mediump vec4 o_color;
468
469 void main (void)
470 {
471 o_color = vec4(v_coords.xyz, 1.0);
472 return;
473 })";
474 compile(shaderString);
475 }
476
TEST_F(MSLOutputTest,FragColor)477 TEST_F(MSLOutputTest, FragColor)
478 {
479 const std::string &shaderString = R"(
480 void main ()
481 {
482 gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
483 })";
484 compile(shaderString);
485 }
486
TEST_F(MSLOutputTest,MatrixIn)487 TEST_F(MSLOutputTest, MatrixIn)
488 {
489 const std::string &shaderString =
490 R"(#version 300 es
491 precision highp float;
492
493 in mat4 mat;
494 out float out0;
495
496 void main()
497 {
498 out0 = mat[0][0];
499 }
500 )";
501 compile(shaderString);
502 }
503
TEST_F(MSLOutputTest,WhileTrue)504 TEST_F(MSLOutputTest, WhileTrue)
505 {
506 const std::string &shaderString =
507 R"(#version 300 es
508 precision mediump float;
509
510 uniform float uf;
511 out vec4 my_FragColor;
512
513 void main()
514 {
515 my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
516 while (true)
517 {
518 break;
519 }
520 })";
521 compile(shaderString);
522 }
523
TEST_F(MSLOutputTest,ForTrue)524 TEST_F(MSLOutputTest, ForTrue)
525 {
526 const std::string &shaderString =
527 R"(#version 300 es
528 precision mediump float;
529
530 uniform float uf;
531 out vec4 my_FragColor;
532
533 void main()
534 {
535 my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
536 for (;true;)
537 {
538 break;
539 }
540 })";
541 compile(shaderString);
542 }
543
TEST_F(MSLOutputTest,ForEmpty)544 TEST_F(MSLOutputTest, ForEmpty)
545 {
546 const std::string &shaderString =
547 R"(#version 300 es
548 precision mediump float;
549
550 uniform float uf;
551 out vec4 my_FragColor;
552
553 void main()
554 {
555 my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
556 for (;;)
557 {
558 break;
559 }
560 })";
561 compile(shaderString);
562 }
563
TEST_F(MSLOutputTest,ForComplex)564 TEST_F(MSLOutputTest, ForComplex)
565 {
566 const std::string &shaderString =
567 R"(#version 300 es
568 precision mediump float;
569
570 uniform float uf;
571 out vec4 my_FragColor;
572
573 void main()
574 {
575 my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
576 for (int i = 0, j = 2; i < j; ++i) {
577 if (i == 0) continue;
578 if (i == 42) break;
579 my_FragColor.x += float(i);
580 }
581 })";
582 compile(shaderString);
583 }
584
TEST_F(MSLOutputTest,ForSymbol)585 TEST_F(MSLOutputTest, ForSymbol)
586 {
587 const std::string &shaderString =
588 R"(#version 300 es
589 precision mediump float;
590
591 uniform float uf;
592 out vec4 my_FragColor;
593
594 void main()
595 {
596 bool cond = true;
597 for (;cond;)
598 {
599 my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
600 cond = false;
601 }
602 })";
603 compile(shaderString);
604 }
605
TEST_F(MSLOutputTest,DoWhileSymbol)606 TEST_F(MSLOutputTest, DoWhileSymbol)
607 {
608 const std::string &shaderString =
609 R"(#version 300 es
610 precision mediump float;
611
612 uniform float uf;
613 out vec4 my_FragColor;
614
615 void main()
616 {
617 bool cond = false;
618 do
619 {
620 my_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
621 } while (cond);
622 })";
623 compile(shaderString);
624 }
625
TEST_F(MSLOutputTest,AnonymousStruct)626 TEST_F(MSLOutputTest, AnonymousStruct)
627 {
628 const std::string &shaderString =
629 R"(
630 precision mediump float;
631 struct { vec4 v; } anonStruct;
632 void main() {
633 anonStruct.v = vec4(0.0,1.0,0.0,1.0);
634 gl_FragColor = anonStruct.v;
635 })";
636 compile(shaderString);
637 // TODO(anglebug.com/6395): This success condition is expected to fail now.
638 // When WebKit build is able to run the tests, this should be changed to something else.
639 // ASSERT_TRUE(foundInCode(SH_MSL_METAL_OUTPUT, "__unnamed"));
640 }
641
TEST_F(MSLOutputTest,GlobalRescopingSimple)642 TEST_F(MSLOutputTest, GlobalRescopingSimple)
643 {
644 const std::string &shaderString =
645 R"(#version 300 es
646 precision mediump float;
647
648 // Should rescope uf into main
649
650 float uf;
651 out vec4 my_FragColor;
652
653 void main()
654 {
655 uf += 1.0f;
656 my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
657 })";
658 compile(shaderString);
659 }
660
TEST_F(MSLOutputTest,GlobalRescopingNoRescope)661 TEST_F(MSLOutputTest, GlobalRescopingNoRescope)
662 {
663 const std::string &shaderString =
664 R"(#version 300 es
665 precision mediump float;
666
667 // Should not rescope any variable
668
669 float uf;
670 out vec4 my_FragColor;
671 void modifyGlobal()
672 {
673 uf = 1.0f;
674 }
675 void main()
676 {
677 modifyGlobal();
678 my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
679 })";
680 compile(shaderString);
681 }
682
TEST_F(MSLOutputTest,GlobalRescopingInitializer)683 TEST_F(MSLOutputTest, GlobalRescopingInitializer)
684 {
685 const std::string &shaderString =
686 R"(#version 300 es
687 precision mediump float;
688
689 // Should rescope uf into main
690
691 float uf = 1.0f;
692 out vec4 my_FragColor;
693
694 void main()
695 {
696 uf += 1.0;
697 my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
698 })";
699 compile(shaderString);
700 }
701
TEST_F(MSLOutputTest,GlobalRescopingInitializerNoRescope)702 TEST_F(MSLOutputTest, GlobalRescopingInitializerNoRescope)
703 {
704 const std::string &shaderString =
705 R"(#version 300 es
706 precision mediump float;
707
708 // Should not rescope any variable
709
710 float uf = 1.0f;
711 out vec4 my_FragColor;
712
713 void modifyGlobal()
714 {
715 uf =+ 1.0f;
716 }
717 void main()
718 {
719 modifyGlobal();
720 my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
721 })";
722 compile(shaderString);
723 }
724
TEST_F(MSLOutputTest,GlobalRescopingNestedFunction)725 TEST_F(MSLOutputTest, GlobalRescopingNestedFunction)
726 {
727 const std::string &shaderString =
728 R"(#version 300 es
729 precision mediump float;
730
731 // Should rescope a info modifyGlobal
732
733 float a = 1.0f;
734 float uf = 1.0f;
735 out vec4 my_FragColor;
736
737 void modifyGlobal()
738 {
739 uf =+ a;
740 }
741 void main()
742 {
743 modifyGlobal();
744 my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
745 })";
746 compile(shaderString);
747 }
748
TEST_F(MSLOutputTest,GlobalRescopingMultipleUses)749 TEST_F(MSLOutputTest, GlobalRescopingMultipleUses)
750 {
751 const std::string &shaderString =
752 R"(#version 300 es
753 precision mediump float;
754
755 // Should rescope uf into main
756
757 float uf = 1.0f;
758 out vec4 my_FragColor;
759
760 void main()
761 {
762 uf =+ 1.0;
763 if (uf > 0.0)
764 {
765 uf =- 0.5;
766 }
767 my_FragColor = vec4(uf, 0.0, 0.0, 1.0);
768 })";
769 compile(shaderString);
770 }
771
TEST_F(MSLOutputTest,GlobalRescopingGloballyReferencedVar)772 TEST_F(MSLOutputTest, GlobalRescopingGloballyReferencedVar)
773 {
774 const std::string &shaderString =
775 R"(#version 300 es
776 precision mediump float;
777
778 // Should rescope uf into main
779
780 const float a = 1.0f;
781 float uf = a;
782 out vec4 my_FragColor;
783
784 void main()
785 {
786 my_FragColor = vec4(uf, 0.0, a, 0.0);
787 })";
788 compile(shaderString);
789 }
790
TEST_F(MSLOutputTest,GlobalRescopingDeclarationAfterFunction)791 TEST_F(MSLOutputTest, GlobalRescopingDeclarationAfterFunction)
792 {
793 const std::string &shaderString =
794 R"(#version 300 es
795 precision mediump float;
796
797 // Should rescope c and b into main
798
799 float a = 1.0f;
800 float c = 1.0f;
801 out vec4 my_FragColor;
802
803 void modifyGlobal()
804 {
805 a =+ 1.0f;
806 }
807
808 float b = 1.0f;
809
810 void main()
811 {
812 modifyGlobal();
813 my_FragColor = vec4(a, b, c, 0.0);
814 }
815
816 )";
817 compile(shaderString);
818 }
819
TEST_F(MSLOutputTest,ReusedOutVarName)820 TEST_F(MSLOutputTest, ReusedOutVarName)
821 {
822 const std::string &shaderString =
823 R"(#version 300 es
824 precision mediump float;
825
826 out vec4 my_FragColor;
827
828 void funcWith1Out(
829 out float outC) {
830 outC = 1.0;
831 }
832
833 void funcWith4Outs(
834 out float outA,
835 out float outB,
836 out float outC,
837 out float outD) {
838 outA = 1.0;
839 outB = 1.0;
840 outD = 1.0;
841 }
842
843
844 void main()
845 {
846 funcWith1Out(my_FragColor.g);
847 funcWith4Outs(my_FragColor.r, my_FragColor.g, my_FragColor.b, my_FragColor.a);
848 }
849
850 )";
851 compile(shaderString);
852 }
853
854 // Test that for loops without body do not crash. At the time of writing, constant hoisting would
855 // traverse such ASTs and crash when loop bodies were not present.
TEST_F(MSLOutputTest,RemovedForBodyNoCrash)856 TEST_F(MSLOutputTest, RemovedForBodyNoCrash)
857 {
858 const char kShader[] = R"(#version 310 es
859 void main() {
860 for(;;)if(2==0);
861 })";
862 compile(kShader);
863 }
864
865 // Test that accessing array element of array of anonymous struct instances does not fail
866 // validation.
TEST_F(MSLOutputTest,AnonymousStructArrayValidationNoCrash)867 TEST_F(MSLOutputTest, AnonymousStructArrayValidationNoCrash)
868 {
869 const char kShader[] = R"(
870 precision mediump float;
871 void main() {
872 struct { vec4 field; } s1[1];
873 gl_FragColor = s1[0].field;
874 })";
875 compile(kShader);
876 }
877
878 // Tests that rewriting varyings for per-element element access does not cause crash.
879 // At the time of writing a_ would be confused with a due to matrixes being flattened
880 // for fragment inputs, and the new variables would be given semantic names separated
881 // with _. This would cause confusion because semantic naming would filter underscores.
TEST_F(MSLOutputTest,VaryingRewriteUnderscoreNoCrash)882 TEST_F(MSLOutputTest, VaryingRewriteUnderscoreNoCrash)
883 {
884 const char kShader[] = R"(precision mediump float;
885 varying mat2 a_;
886 varying mat3 a;
887 void main(){
888 gl_FragColor = vec4(a_) + vec4(a);
889 })";
890 compile(kShader);
891 }
892
893 // Tests that rewriting attributes for per-element element access does not cause crash.
894 // At the time of writing a_ would be confused with a due to matrixes being flattened
895 // for fragment inputs, and the new variables would be given semantic names separated
896 // with _. This would cause confusion because semantic naming would filter underscores.
TEST_F(MSLVertexOutputTest,AttributeRewriteUnderscoreNoCrash)897 TEST_F(MSLVertexOutputTest, AttributeRewriteUnderscoreNoCrash)
898 {
899 const char kShader[] = R"(precision mediump float;
900 attribute mat2 a_;
901 attribute mat3 a;
902 void main(){
903 gl_Position = vec4(a_) + vec4(a);
904 })";
905 compile(kShader);
906 }
907
908 // Test that emulated clip distance varying passes AST validation
TEST_F(MSLVertexOutputTest,ClipDistanceVarying)909 TEST_F(MSLVertexOutputTest, ClipDistanceVarying)
910 {
911 getResources()->ANGLE_clip_cull_distance = 1;
912 const char kShader[] = R"(#version 300 es
913 #extension GL_ANGLE_clip_cull_distance:require
914 void main(){gl_ClipDistance[0];})";
915 compile(kShader);
916 }
917
TEST_F(MSLVertexOutputTest,VertexIDIvecNoCrash)918 TEST_F(MSLVertexOutputTest, VertexIDIvecNoCrash)
919 {
920 const char kShader[] = R"(#version 300 es
921 void main(){ivec2 xy=ivec2((+gl_VertexID));gl_Position=vec4((xy), 0,1);})";
922 compile(kShader);
923 }
924