• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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