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