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 // GeometryShader_test.cpp:
7 // tests for compiling a Geometry Shader
8 //
9 
10 #include "GLSLANG/ShaderLang.h"
11 #include "angle_gl.h"
12 #include "compiler/translator/BaseTypes.h"
13 #include "compiler/translator/TranslatorESSL.h"
14 #include "gtest/gtest.h"
15 #include "tests/test_utils/ShaderCompileTreeTest.h"
16 #include "tests/test_utils/compiler_test.h"
17 
18 using namespace sh;
19 
20 class GeometryShaderTest : public ShaderCompileTreeTest
21 {
22   public:
GeometryShaderTest()23     GeometryShaderTest() {}
24 
25   protected:
initResources(ShBuiltInResources * resources)26     void initResources(ShBuiltInResources *resources) override
27     {
28         resources->EXT_geometry_shader = 1;
29     }
30 
getShaderType() const31     ::GLenum getShaderType() const override { return GL_GEOMETRY_SHADER_EXT; }
32 
getShaderSpec() const33     ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
34 
compileGeometryShader(const std::string & statement1,const std::string & statement2)35     bool compileGeometryShader(const std::string &statement1, const std::string &statement2)
36     {
37         std::ostringstream sstream;
38         sstream << kHeader << statement1 << statement2 << kEmptyBody;
39         return compile(sstream.str());
40     }
41 
compileGeometryShader(const std::string & statement1,const std::string & statement2,const std::string & statement3,const std::string & statement4)42     bool compileGeometryShader(const std::string &statement1,
43                                const std::string &statement2,
44                                const std::string &statement3,
45                                const std::string &statement4)
46     {
47         std::ostringstream sstream;
48         sstream << kHeader << statement1 << statement2 << statement3 << statement4 << kEmptyBody;
49         return compile(sstream.str());
50     }
51 
GetGeometryShaderLayout(const std::string & layoutType,const std::string & primitive,int invocations,int maxVertices)52     static std::string GetGeometryShaderLayout(const std::string &layoutType,
53                                                const std::string &primitive,
54                                                int invocations,
55                                                int maxVertices)
56     {
57         std::ostringstream sstream;
58 
59         sstream << "layout (";
60         if (!primitive.empty())
61         {
62             sstream << primitive;
63         }
64         if (invocations > 0)
65         {
66             sstream << ", invocations = " << invocations;
67         }
68         if (maxVertices >= 0)
69         {
70             sstream << ", max_vertices = " << maxVertices;
71         }
72         sstream << ") " << layoutType << ";" << std::endl;
73 
74         return sstream.str();
75     }
76 
GetInputDeclaration(const std::string & var,int size)77     static std::string GetInputDeclaration(const std::string &var, int size)
78     {
79         std::ostringstream sstream;
80 
81         sstream << "in ";
82         if (size < 0)
83         {
84             sstream << var << "[];\n";
85         }
86         else
87         {
88             sstream << var << "[" << size << "];\n";
89         }
90 
91         return sstream.str();
92     }
93 
94     const std::string kVersion = "#version 310 es\n";
95     const std::string kHeader =
96         "#version 310 es\n"
97         "#extension GL_EXT_geometry_shader : require\n";
98     const std::string kInputLayout  = "layout (points) in;\n";
99     const std::string kOutputLayout = "layout (points, max_vertices = 1) out;\n";
100 
101     const std::array<std::string, 4> kInterpolationQualifiers = {{"flat", "smooth", "centroid"}};
102     const std::map<std::string, int> kInputPrimitivesAndInputArraySizeMap = {
103         {"points", 1},
104         {"lines", 2},
105         {"lines_adjacency", 4},
106         {"triangles", 3},
107         {"triangles_adjacency", 6}};
108 
109     const std::string kEmptyBody =
110         "void main()\n"
111         "{\n"
112         "}\n";
113 };
114 
115 class GeometryShaderOutputCodeTest : public MatchOutputCodeTest
116 {
117   public:
GeometryShaderOutputCodeTest()118     GeometryShaderOutputCodeTest()
119         : MatchOutputCodeTest(GL_GEOMETRY_SHADER_EXT, SH_OBJECT_CODE, SH_ESSL_OUTPUT)
120     {
121         getResources()->EXT_geometry_shader = 1;
122     }
123 };
124 
125 // Geometry Shaders are not supported in GLSL ES shaders version lower than 310.
TEST_F(GeometryShaderTest,Version300)126 TEST_F(GeometryShaderTest, Version300)
127 {
128     const std::string &shaderString =
129         R"(#version 300 es
130         void main()
131         {
132         })";
133 
134     if (compile(shaderString))
135     {
136         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
137     }
138 }
139 
140 // Geometry Shaders are not supported in GLSL ES shaders version 310 without extension
141 // EXT_geometry_shader enabled.
TEST_F(GeometryShaderTest,Version310WithoutExtension)142 TEST_F(GeometryShaderTest, Version310WithoutExtension)
143 {
144     const std::string &shaderString =
145         R"(#version 310 es
146         void main()
147         {
148         })";
149 
150     if (compile(shaderString))
151     {
152         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
153     }
154 }
155 
156 // Geometry Shaders are not supported in GLSL ES shaders version 310 with extension
157 // EXT_geometry_shader disabled.
TEST_F(GeometryShaderTest,Version310ExtensionDisabled)158 TEST_F(GeometryShaderTest, Version310ExtensionDisabled)
159 {
160     const std::string &shaderString =
161         R"(#version 310 es
162         #extension GL_EXT_geometry_shader : disable
163         void main()
164         {
165         })";
166 
167     if (compile(shaderString))
168     {
169         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
170     }
171 }
172 
173 // Geometry Shaders are supported in GLSL ES shaders version 310 with EXT_geometry_shader enabled.
TEST_F(GeometryShaderTest,Version310WithEXTExtension)174 TEST_F(GeometryShaderTest, Version310WithEXTExtension)
175 {
176     const std::string &shaderString =
177         R"(#version 310 es
178         #extension GL_EXT_geometry_shader : require
179         layout(points) in;
180         layout(points, max_vertices = 1) out;
181         void main()
182         {
183         })";
184 
185     if (!compile(shaderString))
186     {
187         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
188     }
189 }
190 
191 // Missing the declaration of input primitive in a geometry shader should be a link error instead of
192 // a compile error.
TEST_F(GeometryShaderTest,NoInputPrimitives)193 TEST_F(GeometryShaderTest, NoInputPrimitives)
194 {
195     const std::string &shaderString =
196         R"(#version 310 es
197         #extension GL_EXT_geometry_shader : require
198         layout(points, max_vertices = 1) out;
199         void main()
200         {
201         })";
202 
203     if (!compile(shaderString))
204     {
205         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
206     }
207 }
208 
209 // Geometry Shaders can only support 5 kinds of input primitives, which cannot be used as output
210 // primitives except 'points'.
211 // Skip testing "points" as it can be used as both input and output primitives.
TEST_F(GeometryShaderTest,ValidInputPrimitives)212 TEST_F(GeometryShaderTest, ValidInputPrimitives)
213 {
214     const std::array<std::string, 4> kInputPrimitives = {
215         {"lines", "lines_adjacency", "triangles", "triangles_adjacency"}};
216 
217     for (const std::string &inputPrimitive : kInputPrimitives)
218     {
219         if (!compileGeometryShader(GetGeometryShaderLayout("in", inputPrimitive, -1, -1),
220                                    kOutputLayout))
221         {
222             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
223         }
224         if (compileGeometryShader(kInputLayout,
225                                   GetGeometryShaderLayout("out", inputPrimitive, -1, 6)))
226         {
227             FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
228         }
229     }
230 }
231 
232 // Geometry Shaders allow duplicated declaration of input primitive, but all of them must be same.
TEST_F(GeometryShaderTest,RedeclareInputPrimitives)233 TEST_F(GeometryShaderTest, RedeclareInputPrimitives)
234 {
235     const std::array<std::string, 5> kInputPrimitives = {
236         {"points", "lines", "lines_adjacency", "triangles", "triangles_adjacency"}};
237 
238     for (GLuint i = 0; i < kInputPrimitives.size(); ++i)
239     {
240         const std::string &inputLayoutStr1 =
241             GetGeometryShaderLayout("in", kInputPrimitives[i], -1, -1);
242         if (!compileGeometryShader(inputLayoutStr1, inputLayoutStr1, kOutputLayout, ""))
243         {
244             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
245         }
246 
247         for (GLuint j = i + 1; j < kInputPrimitives.size(); ++j)
248         {
249             const std::string &inputLayoutStr2 =
250                 GetGeometryShaderLayout("in", kInputPrimitives[j], -1, -1);
251             if (compileGeometryShader(inputLayoutStr1, inputLayoutStr2, kOutputLayout, ""))
252             {
253                 FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
254             }
255         }
256     }
257 }
258 
259 // Geometry Shaders don't allow declaring different input primitives in one layout.
TEST_F(GeometryShaderTest,DeclareDifferentInputPrimitivesInOneLayout)260 TEST_F(GeometryShaderTest, DeclareDifferentInputPrimitivesInOneLayout)
261 {
262     const std::string &shaderString =
263         R"(#version 310 es
264         #extension GL_EXT_geometry_shader : require
265         layout (points, triangles) in;
266         layout (points, max_vertices = 1) out;
267         void main()
268         {
269         })";
270 
271     if (compile(shaderString))
272     {
273         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
274     }
275 }
276 
277 // Geometry Shaders don't allow 'invocations' < 1.
TEST_F(GeometryShaderTest,InvocationsLessThanOne)278 TEST_F(GeometryShaderTest, InvocationsLessThanOne)
279 {
280     const std::string &shaderString =
281         R"(#version 310 es
282         #extension GL_EXT_geometry_shader : require
283         layout (points, invocations = 0) in;
284         layout (points, max_vertices = 1) out;
285         void main()
286         {
287         })";
288 
289     if (compile(shaderString))
290     {
291         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
292     }
293 }
294 
295 // Geometry Shaders allow declaring 'invocations' == 1 together with input primitive declaration in
296 // one layout.
TEST_F(GeometryShaderTest,InvocationsEqualsOne)297 TEST_F(GeometryShaderTest, InvocationsEqualsOne)
298 {
299     const std::string &shaderString =
300         R"(#version 310 es
301         #extension GL_EXT_geometry_shader : require
302         layout (points, invocations = 1) in;
303         layout (points, max_vertices = 1) out;
304         void main()
305         {
306         })";
307 
308     if (!compile(shaderString))
309     {
310         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
311     }
312 }
313 
314 // Geometry Shaders allow declaring 'invocations' == 1 in an individual layout.
TEST_F(GeometryShaderTest,InvocationsEqualsOneInSeparatedLayout)315 TEST_F(GeometryShaderTest, InvocationsEqualsOneInSeparatedLayout)
316 {
317     const std::string &shaderString =
318         R"(#version 310 es
319         #extension GL_EXT_geometry_shader : require
320         layout (points) in;
321         layout (invocations = 1) in;
322         layout (points, max_vertices = 1) out;
323         void main()
324         {
325         })";
326 
327     if (!compile(shaderString))
328     {
329         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
330     }
331 }
332 
333 // Geometry Shaders don't allow 'invocations' larger than the implementation-dependent maximum value
334 // (32 in this test).
TEST_F(GeometryShaderTest,TooLargeInvocations)335 TEST_F(GeometryShaderTest, TooLargeInvocations)
336 {
337     const std::string &shaderString =
338         R"(#version 310 es
339         #extension GL_EXT_geometry_shader : require
340         layout (points, invocations = 9989899) in;
341         layout (points, max_vertices = 1) out;
342         void main()
343         {
344         })";
345 
346     if (compile(shaderString))
347     {
348         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
349     }
350 }
351 
352 // Geometry Shaders allow 'invocations' declared together with input primitives in one layout.
TEST_F(GeometryShaderTest,InvocationsDeclaredWithInputPrimitives)353 TEST_F(GeometryShaderTest, InvocationsDeclaredWithInputPrimitives)
354 {
355     const std::string &shaderString =
356         R"(#version 310 es
357         #extension GL_EXT_geometry_shader : require
358         layout (points, invocations = 3) in;
359         layout (points, max_vertices = 1) out;
360         void main()
361         {
362         })";
363 
364     if (!compile(shaderString))
365     {
366         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
367     }
368 }
369 
370 // Geometry Shaders allow 'invocations' declared before input primitives in one input layout.
TEST_F(GeometryShaderTest,InvocationsBeforeInputPrimitives)371 TEST_F(GeometryShaderTest, InvocationsBeforeInputPrimitives)
372 {
373     const std::string &shaderString =
374         R"(#version 310 es
375         #extension GL_EXT_geometry_shader : require
376         layout (invocations = 3, points) in;
377         layout (points, max_vertices = 1) out;
378         void main()
379         {
380         })";
381 
382     if (!compile(shaderString))
383     {
384         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
385     }
386 }
387 
388 // Geometry Shaders allow 'invocations' declared in an individual input layout.
TEST_F(GeometryShaderTest,InvocationsInIndividualLayout)389 TEST_F(GeometryShaderTest, InvocationsInIndividualLayout)
390 {
391     const std::string &shaderString =
392         R"(#version 310 es
393         #extension GL_EXT_geometry_shader : require
394         layout (points) in;
395         layout (invocations = 3) in;
396         layout (points, max_vertices = 1) out;
397         void main()
398         {
399         })";
400 
401     if (!compile(shaderString))
402     {
403         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
404     }
405 }
406 
407 // Geometry Shaders allow duplicated 'invocations' declarations.
TEST_F(GeometryShaderTest,DuplicatedInvocations)408 TEST_F(GeometryShaderTest, DuplicatedInvocations)
409 {
410     const std::string &shaderString =
411         R"(#version 310 es
412         #extension GL_EXT_geometry_shader : require
413         layout (points, invocations = 3) in;
414         layout (invocations = 3) in;
415         layout (points, max_vertices = 1) out;
416         void main()
417         {
418         })";
419 
420     if (!compile(shaderString))
421     {
422         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
423     }
424 }
425 
426 // Geometry Shaders don't allow multiple different 'invocations' declarations in different
427 // layouts.
TEST_F(GeometryShaderTest,RedeclareDifferentInvocations)428 TEST_F(GeometryShaderTest, RedeclareDifferentInvocations)
429 {
430     const std::string &shaderString =
431         R"(#version 310 es
432         #extension GL_EXT_geometry_shader : require
433         layout (points, invocations = 3) in;
434         layout (invocations = 5) in;
435         layout (points, max_vertices = 1) out;
436         void main()
437         {
438         })";
439 
440     if (compile(shaderString))
441     {
442         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
443     }
444 }
445 
446 // Geometry Shaders don't allow multiple different 'invocations' declarations in different
447 // layouts.
TEST_F(GeometryShaderTest,RedeclareDifferentInvocationsAfterInvocationEqualsOne)448 TEST_F(GeometryShaderTest, RedeclareDifferentInvocationsAfterInvocationEqualsOne)
449 {
450     const std::string &shaderString =
451         R"(#version 310 es
452         #extension GL_EXT_geometry_shader : require
453         layout (points, invocations = 1) in;
454         layout (invocations = 5) in;
455         layout (points, max_vertices = 1) out;
456         void main()
457         {
458         })";
459 
460     if (compile(shaderString))
461     {
462         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
463     }
464 }
465 
466 // Geometry Shaders don't allow multiple different 'invocations' declarations in one layout.
TEST_F(GeometryShaderTest,RedeclareDifferentInvocationsInOneLayout)467 TEST_F(GeometryShaderTest, RedeclareDifferentInvocationsInOneLayout)
468 {
469     const std::string &shaderString =
470         R"(#version 310 es
471         #extension GL_EXT_geometry_shader : require
472         layout (points, invocations = 3, invocations = 5) in;
473         layout (points, max_vertices = 1) out;
474         void main()
475         {
476         })";
477 
478     if (compile(shaderString))
479     {
480         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
481     }
482 }
483 
484 // Geometry Shaders don't allow 'invocations' in out layouts.
TEST_F(GeometryShaderTest,DeclareInvocationsInOutLayout)485 TEST_F(GeometryShaderTest, DeclareInvocationsInOutLayout)
486 {
487     const std::string &shaderString =
488         R"(#version 310 es
489         #extension GL_EXT_geometry_shader : require
490         layout (points) in;
491         layout (points, invocations = 3, max_vertices = 1) out;
492         void main()
493         {
494         })";
495 
496     if (compile(shaderString))
497     {
498         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
499     }
500 }
501 
502 // Geometry Shaders don't allow 'invocations' in layouts without 'in' qualifier.
TEST_F(GeometryShaderTest,DeclareInvocationsInLayoutNoQualifier)503 TEST_F(GeometryShaderTest, DeclareInvocationsInLayoutNoQualifier)
504 {
505     const std::string &shaderString =
506         R"(#version 310 es
507         #extension GL_EXT_geometry_shader : require
508         layout (points) in;
509         layout (invocations = 3);
510         layout (points, max_vertices = 1) out;
511         void main()
512         {
513         })";
514 
515     if (compile(shaderString))
516     {
517         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
518     }
519 }
520 
521 // Geometry Shaders allow declaring output primitive before input primitive declaration.
TEST_F(GeometryShaderTest,DeclareOutputPrimitiveBeforeInputPrimitiveDeclare)522 TEST_F(GeometryShaderTest, DeclareOutputPrimitiveBeforeInputPrimitiveDeclare)
523 {
524     const std::string &shaderString =
525         R"(#version 310 es
526         #extension GL_EXT_geometry_shader : require
527         layout (points, max_vertices = 1) out;
528         layout (points) in;
529         void main()
530         {
531         })";
532 
533     if (!compile(shaderString))
534     {
535         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
536     }
537 }
538 
539 // Geometry Shaders allow declaring 'max_vertices' before output primitive in one output layout.
TEST_F(GeometryShaderTest,DeclareMaxVerticesBeforeOutputPrimitive)540 TEST_F(GeometryShaderTest, DeclareMaxVerticesBeforeOutputPrimitive)
541 {
542     const std::string &shaderString =
543         R"(#version 310 es
544         #extension GL_EXT_geometry_shader : require
545         layout (points) in;
546         layout (max_vertices = 1, points) out;
547         void main()
548         {
549         })";
550 
551     if (!compile(shaderString))
552     {
553         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
554     }
555 }
556 
557 // Missing the declaration of output primitive should be a link error instead of a compile error in
558 // a geometry shader.
TEST_F(GeometryShaderTest,NoOutputPrimitives)559 TEST_F(GeometryShaderTest, NoOutputPrimitives)
560 {
561     const std::string &shaderString =
562         R"(#version 310 es
563         #extension GL_EXT_geometry_shader : require
564         layout (points) in;
565         layout (max_vertices = 1) out;
566         void main()
567         {
568         })";
569 
570     if (!compile(shaderString))
571     {
572         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
573     }
574 }
575 
576 // Geometry Shaders can only support 3 kinds of output primitives, which cannot be used as input
577 // primitives except 'points'.
578 // Skip testing "points" as it can be used as both input and output primitives.
TEST_F(GeometryShaderTest,ValidateOutputPrimitives)579 TEST_F(GeometryShaderTest, ValidateOutputPrimitives)
580 {
581     const std::string outputPrimitives[] = {"line_strip", "triangle_strip"};
582 
583     for (const std::string &outPrimitive : outputPrimitives)
584     {
585         if (!compileGeometryShader(kInputLayout,
586                                    GetGeometryShaderLayout("out", outPrimitive, -1, 6)))
587         {
588             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
589         }
590 
591         if (compileGeometryShader(GetGeometryShaderLayout("in", outPrimitive, -1, -1),
592                                   kOutputLayout))
593         {
594             FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
595         }
596     }
597 }
598 
599 // Geometry Shaders allow duplicated output primitive declarations, but all of them must be same.
TEST_F(GeometryShaderTest,RedeclareOutputPrimitives)600 TEST_F(GeometryShaderTest, RedeclareOutputPrimitives)
601 {
602     const std::array<std::string, 3> outPrimitives = {{"points", "line_strip", "triangle_strip"}};
603 
604     for (GLuint i = 0; i < outPrimitives.size(); i++)
605     {
606         constexpr int maxVertices = 1;
607         const std::string &outputLayoutStr1 =
608             GetGeometryShaderLayout("out", outPrimitives[i], -1, maxVertices);
609         const std::string &outputLayoutStr2 =
610             GetGeometryShaderLayout("out", outPrimitives[i], -1, -1);
611         if (!compileGeometryShader(kInputLayout, outputLayoutStr1, outputLayoutStr2, ""))
612         {
613             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
614         }
615         for (GLuint j = i + 1; j < outPrimitives.size(); j++)
616         {
617             const std::string &outputLayoutStr3 =
618                 GetGeometryShaderLayout("out", outPrimitives[j], -1, -1);
619             if (compileGeometryShader(kInputLayout, outputLayoutStr1, outputLayoutStr3, ""))
620             {
621                 FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
622             }
623         }
624     }
625 }
626 
627 // Geometry Shaders don't allow declaring different output primitives in one layout.
TEST_F(GeometryShaderTest,RedeclareDifferentOutputPrimitivesInOneLayout)628 TEST_F(GeometryShaderTest, RedeclareDifferentOutputPrimitivesInOneLayout)
629 {
630     const std::string &shaderString =
631         R"(#version 310 es
632         #extension GL_EXT_geometry_shader : require
633         layout (points) in;
634         layout (points, max_vertices = 3, line_strip) out;
635         void main()
636         {
637         })";
638 
639     if (compile(shaderString))
640     {
641         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
642     }
643 }
644 
645 // Missing the declarations of output primitives and 'max_vertices' in a geometry shader should
646 // be a link error instead of a compile error.
TEST_F(GeometryShaderTest,NoOutLayouts)647 TEST_F(GeometryShaderTest, NoOutLayouts)
648 {
649     const std::string &shaderString =
650         R"(#version 310 es
651         #extension GL_EXT_geometry_shader : require
652         layout (points) in;
653         void main()
654         {
655         })";
656 
657     if (!compile(shaderString))
658     {
659         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
660     }
661 }
662 
663 // Missing the declarations of 'max_vertices' in a geometry shader should be a link error
664 // instead of a compile error.
TEST_F(GeometryShaderTest,NoMaxVertices)665 TEST_F(GeometryShaderTest, NoMaxVertices)
666 {
667     const std::string &shaderString =
668         R"(#version 310 es
669         #extension GL_EXT_geometry_shader : require
670         layout (points) in;
671         layout (points) out;
672         void main()
673         {
674         })";
675 
676     if (!compile(shaderString))
677     {
678         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
679     }
680 }
681 
682 // Geometry Shaders cannot declare a negative 'max_vertices'.
TEST_F(GeometryShaderTest,NegativeMaxVertices)683 TEST_F(GeometryShaderTest, NegativeMaxVertices)
684 {
685     const std::string &shaderString =
686         R"(#version 310 es
687         #extension GL_EXT_geometry_shader : require
688         layout (points) in;
689         layout (points, max_vertices = -1) out;
690         void main()
691         {
692         })";
693 
694     if (compile(shaderString))
695     {
696         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
697     }
698 }
699 
700 // Geometry Shaders allow max_vertices == 0.
TEST_F(GeometryShaderTest,ZeroMaxVertices)701 TEST_F(GeometryShaderTest, ZeroMaxVertices)
702 {
703     const std::string &shaderString =
704         R"(#version 310 es
705         #extension GL_EXT_geometry_shader : require
706         layout (points) in;
707         layout (points, max_vertices = 0) out;
708         void main()
709         {
710         })";
711 
712     if (!compile(shaderString))
713     {
714         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
715     }
716 }
717 
718 // Geometry Shaders cannot declare a 'max_vertices' that is greater than
719 // MAX_GEOMETRY_OUTPUT_VERTICES_EXT (256 in this test).
TEST_F(GeometryShaderTest,TooLargeMaxVertices)720 TEST_F(GeometryShaderTest, TooLargeMaxVertices)
721 {
722     const std::string &shaderString =
723         R"(#version 310 es
724         #extension GL_EXT_geometry_shader : require
725         layout (points) in;
726         layout (points, max_vertices = 257) out;
727         void main()
728         {
729         })";
730 
731     if (compile(shaderString))
732     {
733         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
734     }
735 }
736 
737 // Geometry Shaders can declare 'max_vertices' in an individual out layout.
TEST_F(GeometryShaderTest,MaxVerticesInIndividualLayout)738 TEST_F(GeometryShaderTest, MaxVerticesInIndividualLayout)
739 {
740     const std::string &shaderString =
741         R"(#version 310 es
742         #extension GL_EXT_geometry_shader : require
743         layout (points) in;
744         layout (points) out;
745         layout (max_vertices = 1) out;
746         void main()
747         {
748         })";
749 
750     if (!compile(shaderString))
751     {
752         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
753     }
754 }
755 
756 // Geometry Shaders allow duplicated 'max_vertices' declarations.
TEST_F(GeometryShaderTest,DuplicatedMaxVertices)757 TEST_F(GeometryShaderTest, DuplicatedMaxVertices)
758 {
759     const std::string &shaderString =
760         R"(#version 310 es
761         #extension GL_EXT_geometry_shader : require
762         layout (points) in;
763         layout (points, max_vertices = 1) out;
764         layout (max_vertices = 1) out;
765         void main()
766         {
767         })";
768 
769     if (!compile(shaderString))
770     {
771         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
772     }
773 }
774 
775 // Geometry Shaders don't allow declaring different 'max_vertices'.
TEST_F(GeometryShaderTest,RedeclareDifferentMaxVertices)776 TEST_F(GeometryShaderTest, RedeclareDifferentMaxVertices)
777 {
778     const std::string &shaderString =
779         R"(#version 310 es
780         #extension GL_EXT_geometry_shader : require
781         layout (points) in;
782         layout (points, max_vertices = 1) out;
783         layout (max_vertices = 2) out;
784         void main()
785         {
786         })";
787 
788     if (compile(shaderString))
789     {
790         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
791     }
792 }
793 
794 // Geometry Shaders don't allow declaring different 'max_vertices'.
TEST_F(GeometryShaderTest,RedeclareDifferentMaxVerticesInOneLayout)795 TEST_F(GeometryShaderTest, RedeclareDifferentMaxVerticesInOneLayout)
796 {
797     const std::string &shaderString =
798         R"(#version 310 es
799         #extension GL_EXT_geometry_shader : require
800         layout (points) in;
801         layout (points, max_vertices = 2, max_vertices = 1) out;
802         void main()
803         {
804         })";
805 
806     if (compile(shaderString))
807     {
808         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
809     }
810 }
811 
812 // Geometry Shaders don't allow 'location' declared with input/output primitives in one layout.
TEST_F(GeometryShaderTest,InvalidLocation)813 TEST_F(GeometryShaderTest, InvalidLocation)
814 {
815     const std::string &shaderString1 =
816         R"(#version 310 es
817         #extension GL_EXT_geometry_shader : require
818         layout (points, location = 1) in;
819         layout (points, max_vertices = 2) out;
820         void main()
821         {
822         })";
823 
824     const std::string &shaderString2 =
825         R"(#version 310 es
826         #extension GL_EXT_geometry_shader : require
827         layout (points) in;
828         layout (invocations = 2, location = 1) in;
829         layout (points, max_vertices = 2) out;
830         void main()
831         {
832         })";
833 
834     const std::string &shaderString3 =
835         R"(#version 310 es
836         #extension GL_EXT_geometry_shader : require
837         layout (points) in;
838         layout (points, location = 3, max_vertices = 2) out;
839         void main()
840         {
841         })";
842 
843     const std::string &shaderString4 =
844         R"(#version 310 es
845         #extension GL_EXT_geometry_shader : require
846         layout (points) in;
847         layout (points) out;
848         layout (max_vertices = 2, location = 3) out;
849         void main()
850         {
851         })";
852 
853     if (compile(shaderString1) || compile(shaderString2) || compile(shaderString3) ||
854         compile(shaderString4))
855     {
856         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
857     }
858 }
859 
860 // Geometry Shaders don't allow invalid layout qualifier declarations.
TEST_F(GeometryShaderTest,InvalidLayoutQualifiers)861 TEST_F(GeometryShaderTest, InvalidLayoutQualifiers)
862 {
863     const std::string &shaderString1 =
864         R"(#version 310 es
865         #extension GL_EXT_geometry_shader : require
866         layout (points, abc) in;
867         layout (points, max_vertices = 2) out;
868         void main()
869         {
870         })";
871 
872     const std::string &shaderString2 =
873         R"(#version 310 es
874         #extension GL_EXT_geometry_shader : require
875         layout (points) in;
876         layout (points, abc, max_vertices = 2) out;
877         void main()
878         {
879         })";
880 
881     const std::string &shaderString3 =
882         R"(#version 310 es
883         #extension GL_EXT_geometry_shader : require
884         layout (points, xyz = 2) in;
885         layout (points, max_vertices = 2) out;
886         void main()
887         {
888         })";
889 
890     const std::string &shaderString4 =
891         R"(#version 310 es
892         #extension GL_EXT_geometry_shader : require
893         layout (points) in;
894         layout (points) out;
895         layout (max_vertices = 2, xyz = 3) out;
896         void main()
897         {
898         })";
899 
900     if (compile(shaderString1) || compile(shaderString2) || compile(shaderString3) ||
901         compile(shaderString4))
902     {
903         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
904     }
905 }
906 
907 // Verify that indexing an array with a constant integer on gl_in is legal.
TEST_F(GeometryShaderTest,IndexGLInByConstantInteger)908 TEST_F(GeometryShaderTest, IndexGLInByConstantInteger)
909 {
910     const std::string &shaderString =
911         R"(#version 310 es
912         #extension GL_EXT_geometry_shader : require
913         layout (points) in;
914         layout (points, max_vertices = 2) out;
915         void main()
916         {
917             vec4 position;
918             position = gl_in[0].gl_Position;
919         })";
920 
921     if (!compile(shaderString))
922     {
923         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
924     }
925 }
926 
927 // Verify that indexing an array with an integer variable on gl_in is legal.
TEST_F(GeometryShaderTest,IndexGLInByVariable)928 TEST_F(GeometryShaderTest, IndexGLInByVariable)
929 {
930     const std::string &shaderString =
931         R"(#version 310 es
932         #extension GL_EXT_geometry_shader : require
933         layout (lines) in;
934         layout (points, max_vertices = 2) out;
935         void main()
936         {
937             vec4 position;
938             for (int i = 0; i < 2; i++)
939             {
940                 position = gl_in[i].gl_Position;
941             }
942         })";
943 
944     if (!compile(shaderString))
945     {
946         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
947     }
948 }
949 
950 // Verify that indexing an array on gl_in without input primitive declaration causes a compile
951 // error.
TEST_F(GeometryShaderTest,IndexGLInWithoutInputPrimitive)952 TEST_F(GeometryShaderTest, IndexGLInWithoutInputPrimitive)
953 {
954     const std::string &shaderString =
955         R"(#version 310 es
956         #extension GL_EXT_geometry_shader : require
957         layout (points, max_vertices = 2) out;
958         void main()
959         {
960             vec4 position = gl_in[0].gl_Position;
961         })";
962 
963     if (compile(shaderString))
964     {
965         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
966     }
967 }
968 
969 // Verify that using gl_in.length() without input primitive declaration causes a compile error.
TEST_F(GeometryShaderTest,UseGLInLengthWithoutInputPrimitive)970 TEST_F(GeometryShaderTest, UseGLInLengthWithoutInputPrimitive)
971 {
972     const std::string &shaderString =
973         R"(#version 310 es
974         #extension GL_EXT_geometry_shader : require
975         layout (points, max_vertices = 2) out;
976         void main()
977         {
978             int length = gl_in.length();
979         })";
980 
981     if (compile(shaderString))
982     {
983         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
984     }
985 }
986 
987 // Verify that using gl_in.length() with input primitive declaration can compile.
TEST_F(GeometryShaderTest,UseGLInLengthWithInputPrimitive)988 TEST_F(GeometryShaderTest, UseGLInLengthWithInputPrimitive)
989 {
990     const std::string &shaderString =
991         R"(#version 310 es
992         #extension GL_EXT_geometry_shader : require
993         layout (points) in;
994         layout (points, max_vertices = 2) out;
995         void main()
996         {
997             gl_Position = vec4(gl_in.length());
998             EmitVertex();
999         })";
1000 
1001     if (!compile(shaderString))
1002     {
1003         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1004     }
1005 }
1006 
1007 // Verify that gl_in[].gl_Position cannot be l-value.
TEST_F(GeometryShaderTest,AssignValueToGLIn)1008 TEST_F(GeometryShaderTest, AssignValueToGLIn)
1009 {
1010     const std::string &shaderString =
1011         R"(#version 310 es
1012         #extension GL_EXT_geometry_shader : require
1013         layout (points) in;
1014         layout (points, max_vertices = 2) out;
1015         void main()
1016         {
1017             gl_in[0].gl_Position = vec4(0, 0, 0, 1);
1018         })";
1019     if (compile(shaderString))
1020     {
1021         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1022     }
1023 }
1024 
1025 // Verify Geometry Shader supports all required built-in variables.
TEST_F(GeometryShaderTest,BuiltInVariables)1026 TEST_F(GeometryShaderTest, BuiltInVariables)
1027 {
1028     const std::string &shaderString =
1029         R"(#version 310 es
1030         #extension GL_EXT_geometry_shader : require
1031         layout (points, invocations = 2) in;
1032         layout (points, max_vertices = 2) out;
1033         void main()
1034         {
1035             gl_Position = gl_in[gl_InvocationID].gl_Position;
1036             int invocation = gl_InvocationID;
1037             gl_Layer = invocation;
1038             int primitiveIn = gl_PrimitiveIDIn;
1039             gl_PrimitiveID = primitiveIn;
1040         })";
1041     if (!compile(shaderString))
1042     {
1043         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1044     }
1045 }
1046 
1047 // Verify that gl_PrimitiveIDIn cannot be l-value.
TEST_F(GeometryShaderTest,AssignValueToGLPrimitiveIn)1048 TEST_F(GeometryShaderTest, AssignValueToGLPrimitiveIn)
1049 {
1050     const std::string &shaderString =
1051         R"(#version 310 es
1052         #extension GL_EXT_geometry_shader : require
1053         layout (points, invocations = 2) in;
1054         layout (points, max_vertices = 2) out;
1055         void main()
1056         {
1057             gl_PrimitiveIDIn = 1;
1058         })";
1059     if (compile(shaderString))
1060     {
1061         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1062     }
1063 }
1064 
1065 // Verify that gl_InvocationID cannot be l-value.
TEST_F(GeometryShaderTest,AssignValueToGLInvocations)1066 TEST_F(GeometryShaderTest, AssignValueToGLInvocations)
1067 {
1068     const std::string &shaderString =
1069         R"(#version 310 es
1070         #extension GL_EXT_geometry_shader : require
1071         layout (points, invocations = 2) in;
1072         layout (points, max_vertices = 2) out;
1073         void main()
1074         {
1075             gl_InvocationID = 1;
1076         })";
1077     if (compile(shaderString))
1078     {
1079         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1080     }
1081 }
1082 
1083 // Verify that both EmitVertex() and EndPrimitive() are supported in Geometry Shader.
TEST_F(GeometryShaderTest,GeometryShaderBuiltInFunctions)1084 TEST_F(GeometryShaderTest, GeometryShaderBuiltInFunctions)
1085 {
1086     const std::string &shaderString =
1087         R"(#version 310 es
1088         #extension GL_EXT_geometry_shader : require
1089         layout (points) in;
1090         layout (points, max_vertices = 2) out;
1091         void main()
1092         {
1093             gl_Position = gl_in[0].gl_Position;
1094             EmitVertex();
1095             EndPrimitive();
1096         })";
1097 
1098     if (!compile(shaderString))
1099     {
1100         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1101     }
1102 }
1103 
1104 // Verify that using EmitVertex() or EndPrimitive() without GL_EXT_geometry_shader declared causes a
1105 // compile error.
TEST_F(GeometryShaderTest,GeometryShaderBuiltInFunctionsWithoutExtension)1106 TEST_F(GeometryShaderTest, GeometryShaderBuiltInFunctionsWithoutExtension)
1107 {
1108     const std::string &shaderString1 =
1109         R"(#version 310 es
1110         void main()
1111         {
1112             EmitVertex();
1113         })";
1114 
1115     const std::string &shaderString2 =
1116         R"(#version 310 es
1117         void main()
1118         {
1119             EndPrimitive();
1120         })";
1121 
1122     if (compile(shaderString1) || compile(shaderString2))
1123     {
1124         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1125     }
1126 }
1127 
1128 // Verify that all required built-in constant values are supported in Geometry Shaders
TEST_F(GeometryShaderTest,GeometryShaderBuiltInConstants)1129 TEST_F(GeometryShaderTest, GeometryShaderBuiltInConstants)
1130 {
1131     const std::string &kShaderHeader =
1132         R"(#version 310 es
1133         #extension GL_EXT_geometry_shader : require
1134         layout (points) in;
1135         layout (points, max_vertices = 2) out;
1136         void main()
1137         {
1138             gl_Position.x = float()";
1139 
1140     const std::array<std::string, 9> kGeometryShaderBuiltinConstants = {{
1141         "gl_MaxGeometryInputComponents",
1142         "gl_MaxGeometryOutputComponents",
1143         "gl_MaxGeometryImageUniforms",
1144         "gl_MaxGeometryTextureImageUnits",
1145         "gl_MaxGeometryOutputVertices",
1146         "gl_MaxGeometryTotalOutputComponents",
1147         "gl_MaxGeometryUniformComponents",
1148         "gl_MaxGeometryAtomicCounters",
1149         "gl_MaxGeometryAtomicCounterBuffers",
1150     }};
1151 
1152     const std::string &kShaderTail =
1153         R"();
1154             EmitVertex();
1155         })";
1156 
1157     for (const std::string &kGSBuiltinConstant : kGeometryShaderBuiltinConstants)
1158     {
1159         std::ostringstream ostream;
1160         ostream << kShaderHeader << kGSBuiltinConstant << kShaderTail;
1161         if (!compile(ostream.str()))
1162         {
1163             FAIL() << "Shader compilation failed, expecting success: \n" << mInfoLog;
1164         }
1165     }
1166 }
1167 
1168 // Verify that using any Geometry Shader built-in constant values without GL_EXT_geometry_shader
1169 // declared causes a compile error.
TEST_F(GeometryShaderTest,GeometryShaderBuiltInConstantsWithoutExtension)1170 TEST_F(GeometryShaderTest, GeometryShaderBuiltInConstantsWithoutExtension)
1171 {
1172     const std::string &kShaderHeader =
1173         "#version 310 es\n"
1174         "void main()\n"
1175         "{\n"
1176         "    int val = ";
1177 
1178     const std::array<std::string, 9> kGeometryShaderBuiltinConstants = {{
1179         "gl_MaxGeometryInputComponents",
1180         "gl_MaxGeometryOutputComponents",
1181         "gl_MaxGeometryImageUniforms",
1182         "gl_MaxGeometryTextureImageUnits",
1183         "gl_MaxGeometryOutputVertices",
1184         "gl_MaxGeometryTotalOutputComponents",
1185         "gl_MaxGeometryUniformComponents",
1186         "gl_MaxGeometryAtomicCounters",
1187         "gl_MaxGeometryAtomicCounterBuffers",
1188     }};
1189 
1190     const std::string &kShaderTail =
1191         ";\n"
1192         "}\n";
1193 
1194     for (const std::string &kGSBuiltinConstant : kGeometryShaderBuiltinConstants)
1195     {
1196         std::ostringstream ostream;
1197         ostream << kShaderHeader << kGSBuiltinConstant << kShaderTail;
1198         if (compile(ostream.str()))
1199         {
1200             FAIL() << "Shader compilation succeeded, expecting failure: \n" << mInfoLog;
1201         }
1202     }
1203 }
1204 
1205 // Verify that Geometry Shaders cannot accept non-array inputs.
TEST_F(GeometryShaderTest,NonArrayInput)1206 TEST_F(GeometryShaderTest, NonArrayInput)
1207 {
1208     const std::string &shaderString =
1209         R"(#version 310 es
1210         #extension GL_EXT_geometry_shader : require
1211         layout (points) in;
1212         layout (points, max_vertices = 1) out;
1213         in vec4 texcoord;
1214         void main()
1215         {
1216         })";
1217 
1218     if (compile(shaderString))
1219     {
1220         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1221     }
1222 }
1223 
1224 // Verify that it is a compile error to declare an unsized Geometry Shader input before a valid
1225 // input primitive declaration.
TEST_F(GeometryShaderTest,DeclareUnsizedInputBeforeInputPrimitive)1226 TEST_F(GeometryShaderTest, DeclareUnsizedInputBeforeInputPrimitive)
1227 {
1228     const std::string &shaderString1 =
1229         R"(#version 310 es
1230         #extension GL_EXT_geometry_shader : require
1231         in vec4 texcoord[];
1232         layout (points) in;
1233         layout (points, max_vertices = 1) out;
1234         void main()
1235         {
1236             vec4 coord = texcoord[0];
1237             int length = texcoord.length();
1238         })";
1239 
1240     const std::string &shaderString2 =
1241         R"(#version 310 es
1242         #extension GL_EXT_geometry_shader : require
1243         in vec4 texcoord1[1];
1244         in vec4 texcoord2[];
1245         layout (points) in;
1246         layout (points, max_vertices = 1) out;
1247         void main()
1248         {
1249             vec4 coord = texcoord2[0];
1250             int length = texcoord2.length();
1251         })";
1252 
1253     if (compile(shaderString1) || compile(shaderString2))
1254     {
1255         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1256     }
1257 }
1258 
1259 // Verify that it is a compile error to declare an unsized Geometry Shader input without a valid
1260 // input primitive declaration.
TEST_F(GeometryShaderTest,DeclareUnsizedInputWithoutInputPrimitive)1261 TEST_F(GeometryShaderTest, DeclareUnsizedInputWithoutInputPrimitive)
1262 {
1263     const std::string &shaderString1 =
1264         R"(#version 310 es
1265         #extension GL_EXT_geometry_shader : require
1266         layout (points, max_vertices = 1) out;
1267         in vec4 texcoord[];
1268         void main()
1269         {
1270         })";
1271 
1272     const std::string &shaderString2 =
1273         R"(#version 310 es
1274         #extension GL_EXT_geometry_shader : require
1275         layout (points, max_vertices = 1) out;
1276         in vec4 texcoord1[1];
1277         in vec4 texcoord2[];
1278         void main()
1279         {
1280         })";
1281 
1282     if (compile(shaderString1) || compile(shaderString2))
1283     {
1284         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1285     }
1286 }
1287 
1288 // Verify that indexing an unsized Geometry Shader input which is declared after a
1289 // valid input primitive declaration can compile.
TEST_F(GeometryShaderTest,IndexingUnsizedInputDeclaredAfterInputPrimitive)1290 TEST_F(GeometryShaderTest, IndexingUnsizedInputDeclaredAfterInputPrimitive)
1291 {
1292     const std::string &shaderString =
1293         R"(#version 310 es
1294         #extension GL_EXT_geometry_shader : require
1295         layout (points) in;
1296         layout (points, max_vertices = 1) out;
1297         in vec4 texcoord[], texcoord2[];
1298         in vec4[] texcoord3, texcoord4;
1299         void main()
1300         {
1301             gl_Position = texcoord[0] + texcoord2[0] + texcoord3[0] + texcoord4[0];
1302             EmitVertex();
1303         })";
1304 
1305     if (!compile(shaderString))
1306     {
1307         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1308     }
1309 }
1310 
1311 // Verify that calling length() function on an unsized Geometry Shader input which
1312 // is declared before a valid input primitive declaration can compile.
TEST_F(GeometryShaderTest,CallingLengthOnUnsizedInputDeclaredAfterInputPrimitive)1313 TEST_F(GeometryShaderTest, CallingLengthOnUnsizedInputDeclaredAfterInputPrimitive)
1314 {
1315     const std::string &shaderString =
1316         R"(#version 310 es
1317         #extension GL_EXT_geometry_shader : require
1318         layout (points) in;
1319         layout (points, max_vertices = 1) out;
1320         in vec4 texcoord[];
1321         void main()
1322         {
1323             gl_Position = vec4(texcoord.length());
1324             EmitVertex();
1325         })";
1326 
1327     if (!compile(shaderString))
1328     {
1329         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1330     }
1331 }
1332 
1333 // Verify that assigning a value to the input of a geometry shader causes a compile error.
TEST_F(GeometryShaderTest,AssignValueToInput)1334 TEST_F(GeometryShaderTest, AssignValueToInput)
1335 {
1336     const std::string &shaderString =
1337         R"(#version 310 es
1338         #extension GL_EXT_geometry_shader : require
1339         layout (points) in;
1340         layout (points, max_vertices = 1) out;
1341         in vec4 texcoord[];
1342         void main()
1343         {
1344             texcoord[0] = vec4(1.0, 0.0, 0.0, 1.0);
1345         })";
1346 
1347     if (compile(shaderString))
1348     {
1349         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1350     }
1351 }
1352 
1353 // Geometry Shaders allow inputs with location qualifier.
TEST_F(GeometryShaderTest,InputWithLocations)1354 TEST_F(GeometryShaderTest, InputWithLocations)
1355 {
1356     const std::string &shaderString =
1357         R"(#version 310 es
1358         #extension GL_EXT_geometry_shader : require
1359         layout (triangles) in;
1360         layout (points, max_vertices = 1) out;
1361         layout (location = 0) in vec4 texcoord1[];
1362         layout (location = 1) in vec4 texcoord2[];
1363         void main()
1364         {
1365             int index = 0;
1366             vec4 coord1 = texcoord1[0];
1367             vec4 coord2 = texcoord2[index];
1368             gl_Position = coord1 + coord2;
1369         })";
1370 
1371     if (!compile(shaderString))
1372     {
1373         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1374     }
1375 }
1376 
1377 // Geometry Shaders allow inputs with explicit size declared before the declaration of the
1378 // input primitive, but they should have same size and match the declaration of the
1379 // following input primitive declarations.
TEST_F(GeometryShaderTest,InputWithSizeBeforeInputPrimitive)1380 TEST_F(GeometryShaderTest, InputWithSizeBeforeInputPrimitive)
1381 {
1382     for (auto &primitiveAndArraySize : kInputPrimitivesAndInputArraySizeMap)
1383     {
1384         const std::string &inputLayoutStr =
1385             GetGeometryShaderLayout("in", primitiveAndArraySize.first, -1, -1);
1386         const int inputSize = primitiveAndArraySize.second;
1387 
1388         const std::string &inputDeclaration1 = GetInputDeclaration("vec4 input1", inputSize);
1389         if (!compileGeometryShader(inputDeclaration1, "", inputLayoutStr, kOutputLayout))
1390         {
1391             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1392         }
1393 
1394         const std::string &inputDeclaration2 = GetInputDeclaration("vec4 input2", inputSize + 1);
1395         if (compileGeometryShader(inputDeclaration2, "", inputLayoutStr, kOutputLayout) ||
1396             compileGeometryShader(inputDeclaration1, inputDeclaration2, inputLayoutStr,
1397                                   kOutputLayout))
1398         {
1399             FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1400         }
1401     }
1402 }
1403 
1404 // Geometry shaders allow inputs with explicit size declared after the declaration of the
1405 // input primitive, but their sizes should match the previous input primitive declaration.
TEST_F(GeometryShaderTest,InputWithSizeAfterInputPrimitive)1406 TEST_F(GeometryShaderTest, InputWithSizeAfterInputPrimitive)
1407 {
1408     for (auto &primitiveAndArraySize : kInputPrimitivesAndInputArraySizeMap)
1409     {
1410         const std::string &inputLayoutStr =
1411             GetGeometryShaderLayout("in", primitiveAndArraySize.first, -1, -1);
1412         const int inputSize = primitiveAndArraySize.second;
1413 
1414         const std::string &inputDeclaration1 = GetInputDeclaration("vec4 input1", inputSize);
1415         if (!compileGeometryShader(inputLayoutStr, kOutputLayout, inputDeclaration1, ""))
1416         {
1417             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1418         }
1419 
1420         const std::string &inputDeclaration2 = GetInputDeclaration("vec4 input2", inputSize + 1);
1421         if (compileGeometryShader(inputLayoutStr, kOutputLayout, inputDeclaration2, ""))
1422         {
1423             FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1424         }
1425     }
1426 }
1427 
1428 // Verify that Geometry Shaders accept non-array outputs.
TEST_F(GeometryShaderTest,NonArrayOutputs)1429 TEST_F(GeometryShaderTest, NonArrayOutputs)
1430 {
1431     const std::string &shaderString =
1432         R"(#version 310 es
1433         #extension GL_EXT_geometry_shader : require
1434         layout (points) in;
1435         layout (points, max_vertices = 1) out;
1436         out vec4 color;
1437         void main()
1438         {
1439         })";
1440 
1441     if (!compile(shaderString))
1442     {
1443         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1444     }
1445 }
1446 
1447 // Verify that Geometry Shaders allow declaring outputs with 'location' layout qualifier.
TEST_F(GeometryShaderTest,OutputsWithLocation)1448 TEST_F(GeometryShaderTest, OutputsWithLocation)
1449 {
1450     const std::string &shaderString =
1451         R"(#version 310 es
1452         #extension GL_EXT_geometry_shader : require
1453         layout (triangles) in;
1454         layout (points, max_vertices = 1) out;
1455         layout (location = 0) out vec4 color1;
1456         layout (location = 1) out vec4 color2;
1457         void main()
1458         {
1459             color1 = vec4(0.0, 1.0, 0.0, 1.0);
1460             color2 = vec4(1.0, 0.0, 0.0, 1.0);
1461         })";
1462 
1463     if (!compile(shaderString))
1464     {
1465         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1466     }
1467 }
1468 
1469 // Geometry Shaders allow declaring sized array outputs.
TEST_F(GeometryShaderTest,SizedArrayOutputs)1470 TEST_F(GeometryShaderTest, SizedArrayOutputs)
1471 {
1472     const std::string &shaderString =
1473         R"(#version 310 es
1474         #extension GL_EXT_geometry_shader : require
1475         layout (triangles) in;
1476         layout (points, max_vertices = 1) out;
1477         out vec4 color[2];
1478         void main()
1479         {
1480             color[0] = vec4(0.0, 1.0, 0.0, 1.0);
1481             color[1] = vec4(1.0, 0.0, 0.0, 1.0);
1482         })";
1483 
1484     if (!compile(shaderString))
1485     {
1486         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1487     }
1488 }
1489 
1490 // Verify that Geometry Shader outputs cannot be declared as an unsized array.
TEST_F(GeometryShaderTest,UnsizedArrayOutputs)1491 TEST_F(GeometryShaderTest, UnsizedArrayOutputs)
1492 {
1493     const std::string &shaderString =
1494         R"(#version 310 es
1495         #extension GL_EXT_geometry_shader : require
1496         layout (triangles) in;
1497         layout (points, max_vertices = 1) out;
1498         out vec4 color[];
1499         void main()
1500         {
1501         })";
1502 
1503     if (compile(shaderString))
1504     {
1505         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1506     }
1507 }
1508 
1509 // Verify that Geometry Shader inputs can use interpolation qualifiers.
TEST_F(GeometryShaderTest,InputWithInterpolationQualifiers)1510 TEST_F(GeometryShaderTest, InputWithInterpolationQualifiers)
1511 {
1512     for (const std::string &qualifier : kInterpolationQualifiers)
1513     {
1514         std::ostringstream stream;
1515         stream << kHeader << kInputLayout << kOutputLayout << qualifier << " in vec4 texcoord[];\n"
1516                << kEmptyBody;
1517 
1518         if (!compile(stream.str()))
1519         {
1520             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1521         }
1522     }
1523 }
1524 
1525 // Verify that Geometry Shader outputs can use interpolation qualifiers.
TEST_F(GeometryShaderTest,OutputWithInterpolationQualifiers)1526 TEST_F(GeometryShaderTest, OutputWithInterpolationQualifiers)
1527 {
1528     for (const std::string &qualifier : kInterpolationQualifiers)
1529     {
1530         std::ostringstream stream;
1531         stream << kHeader << kInputLayout << kOutputLayout << qualifier << " out vec4 color;\n"
1532                << kEmptyBody;
1533 
1534         if (!compile(stream.str()))
1535         {
1536             FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1537         }
1538     }
1539 }
1540 
1541 // Verify that Geometry Shader outputs can use 'invariant' qualifier.
TEST_F(GeometryShaderTest,InvariantOutput)1542 TEST_F(GeometryShaderTest, InvariantOutput)
1543 {
1544     const std::string &shaderString =
1545         R"(#version 310 es
1546         #extension GL_EXT_geometry_shader : require
1547         layout (points) in;
1548         layout (points, max_vertices = 2) out;
1549         invariant out vec4 gs_output;
1550         void main()
1551         {
1552             gl_Position = gl_in[0].gl_Position;
1553         })";
1554 
1555     if (!compile(shaderString))
1556     {
1557         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1558     }
1559 }
1560 
1561 // Verify that the member of gl_in won't be incorrectly changed in the output shader string.
TEST_F(GeometryShaderOutputCodeTest,ValidateGLInMembersInOutputShaderString)1562 TEST_F(GeometryShaderOutputCodeTest, ValidateGLInMembersInOutputShaderString)
1563 {
1564     const std::string &shaderString1 =
1565         R"(#version 310 es
1566         #extension GL_EXT_geometry_shader : require
1567         layout (lines) in;
1568         layout (points, max_vertices = 2) out;
1569         void main()
1570         {
1571             vec4 position;
1572             for (int i = 0; i < 2; i++)
1573             {
1574                 position = gl_in[i].gl_Position;
1575             }
1576         })";
1577 
1578     compile(shaderString1);
1579     EXPECT_TRUE(foundInESSLCode("].gl_Position"));
1580 
1581     const std::string &shaderString2 =
1582         R"(#version 310 es
1583         #extension GL_EXT_geometry_shader : require
1584         layout (points) in;
1585         layout (points, max_vertices = 2) out;
1586         void main()
1587         {
1588             vec4 position;
1589             position = gl_in[0].gl_Position;
1590         })";
1591 
1592     compile(shaderString2);
1593     EXPECT_TRUE(foundInESSLCode("].gl_Position"));
1594 }
1595 
1596 // Verify that geometry shader inputs can be declared as struct arrays.
TEST_F(GeometryShaderTest,StructArrayInput)1597 TEST_F(GeometryShaderTest, StructArrayInput)
1598 {
1599     const std::string &shaderString =
1600         R"(#version 310 es
1601         #extension GL_EXT_geometry_shader : require
1602         layout (points) in;
1603         layout (points, max_vertices = 2) out;
1604         struct S
1605         {
1606             float value1;
1607             vec4 value2;
1608         };
1609         in S gs_input[];
1610         out S gs_output;
1611         void main()
1612         {
1613             gs_output = gs_input[0];
1614         })";
1615 
1616     if (!compile(shaderString))
1617     {
1618         FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
1619     }
1620 }
1621 
1622 // Verify that geometry shader outputs cannot be declared as struct arrays.
TEST_F(GeometryShaderTest,StructArrayOutput)1623 TEST_F(GeometryShaderTest, StructArrayOutput)
1624 {
1625     const std::string &shaderString =
1626         R"(#version 310 es
1627         #extension GL_EXT_geometry_shader : require
1628         layout (points) in;
1629         layout (points, max_vertices = 2) out;
1630         struct S
1631         {
1632             float value1;
1633             vec4 value2;
1634         };
1635         out S gs_output[1];
1636         void main()
1637         {
1638             gs_output[0].value1 = 1.0;
1639             gs_output[0].value2 = vec4(1.0, 0.0, 0.0, 1.0);
1640         })";
1641 
1642     if (compile(shaderString))
1643     {
1644         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
1645     }
1646 }
1647