• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // GeometryShaderTest.cpp : Tests of the implementation of geometry shader
8 
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 
12 using namespace angle;
13 
14 namespace
15 {
16 
17 class GeometryShaderTest : public ANGLETest
18 {
19   protected:
CreateEmptyGeometryShader(const std::string & inputPrimitive,const std::string & outputPrimitive,int invocations,int maxVertices)20     static std::string CreateEmptyGeometryShader(const std::string &inputPrimitive,
21                                                  const std::string &outputPrimitive,
22                                                  int invocations,
23                                                  int maxVertices)
24     {
25         std::ostringstream ostream;
26         ostream << "#version 310 es\n"
27                    "#extension GL_EXT_geometry_shader : require\n";
28         if (!inputPrimitive.empty())
29         {
30             ostream << "layout (" << inputPrimitive << ") in;\n";
31         }
32         if (!outputPrimitive.empty())
33         {
34             ostream << "layout (" << outputPrimitive << ") out;\n";
35         }
36         if (invocations > 0)
37         {
38             ostream << "layout (invocations = " << invocations << ") in;\n";
39         }
40         if (maxVertices >= 0)
41         {
42             ostream << "layout (max_vertices = " << maxVertices << ") out;\n";
43         }
44         ostream << "void main()\n"
45                    "{\n"
46                    "}";
47         return ostream.str();
48     }
49 };
50 
51 class GeometryShaderTestES3 : public ANGLETest
52 {};
53 
54 // Verify that Geometry Shader cannot be created in an OpenGL ES 3.0 context.
TEST_P(GeometryShaderTestES3,CreateGeometryShaderInES3)55 TEST_P(GeometryShaderTestES3, CreateGeometryShaderInES3)
56 {
57     EXPECT_TRUE(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
58     GLuint geometryShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
59     EXPECT_EQ(0u, geometryShader);
60     EXPECT_GL_ERROR(GL_INVALID_ENUM);
61 }
62 
63 // Verify that Geometry Shader can be created and attached to a program.
TEST_P(GeometryShaderTest,CreateAndAttachGeometryShader)64 TEST_P(GeometryShaderTest, CreateAndAttachGeometryShader)
65 {
66     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
67 
68     constexpr char kGS[] = R"(#version 310 es
69 #extension GL_EXT_geometry_shader : require
70 layout (invocations = 3, triangles) in;
71 layout (triangle_strip, max_vertices = 3) out;
72 in vec4 texcoord[];
73 out vec4 o_texcoord;
74 void main()
75 {
76     int n;
77     for (n = 0; n < gl_in.length(); n++)
78     {
79         gl_Position = gl_in[n].gl_Position;
80         gl_Layer   = gl_InvocationID;
81         o_texcoord = texcoord[n];
82         EmitVertex();
83     }
84     EndPrimitive();
85 })";
86 
87     GLuint geometryShader = CompileShader(GL_GEOMETRY_SHADER_EXT, kGS);
88 
89     EXPECT_NE(0u, geometryShader);
90 
91     GLuint programID = glCreateProgram();
92     glAttachShader(programID, geometryShader);
93 
94     glDetachShader(programID, geometryShader);
95     glDeleteShader(geometryShader);
96     glDeleteProgram(programID);
97 
98     EXPECT_GL_NO_ERROR();
99 }
100 
101 // Verify that all the implementation dependent geometry shader related resource limits meet the
102 // requirement of GL_EXT_geometry_shader SPEC.
TEST_P(GeometryShaderTest,GeometryShaderImplementationDependentLimits)103 TEST_P(GeometryShaderTest, GeometryShaderImplementationDependentLimits)
104 {
105     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
106 
107     const std::map<GLenum, int> limits = {{GL_MAX_FRAMEBUFFER_LAYERS_EXT, 256},
108                                           {GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT, 1024},
109                                           {GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT, 12},
110                                           {GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT, 64},
111                                           {GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT, 64},
112                                           {GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, 256},
113                                           {GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT, 1024},
114                                           {GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT, 16},
115                                           {GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT, 0},
116                                           {GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT, 0},
117                                           {GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT, 0},
118                                           {GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT, 0},
119                                           {GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT, 32}};
120 
121     GLint value;
122     for (const auto &limit : limits)
123     {
124         value = 0;
125         glGetIntegerv(limit.first, &value);
126         EXPECT_GL_NO_ERROR();
127         EXPECT_GE(value, limit.second);
128     }
129 
130     value = 0;
131     glGetIntegerv(GL_LAYER_PROVOKING_VERTEX_EXT, &value);
132     EXPECT_GL_NO_ERROR();
133     EXPECT_TRUE(value == GL_FIRST_VERTEX_CONVENTION_EXT || value == GL_LAST_VERTEX_CONVENTION_EXT ||
134                 value == GL_UNDEFINED_VERTEX_EXT);
135 }
136 
137 // Verify that all the combined resource limits meet the requirement of GL_EXT_geometry_shader SPEC.
TEST_P(GeometryShaderTest,CombinedResourceLimits)138 TEST_P(GeometryShaderTest, CombinedResourceLimits)
139 {
140     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
141 
142     // See http://anglebug.com/2261.
143     ANGLE_SKIP_TEST_IF(IsAndroid());
144 
145     const std::map<GLenum, int> limits = {{GL_MAX_UNIFORM_BUFFER_BINDINGS, 48},
146                                           {GL_MAX_COMBINED_UNIFORM_BLOCKS, 36},
147                                           {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 64}};
148 
149     GLint value;
150     for (const auto &limit : limits)
151     {
152         value = 0;
153         glGetIntegerv(limit.first, &value);
154         EXPECT_GL_NO_ERROR();
155         EXPECT_GE(value, limit.second);
156     }
157 }
158 
159 // Verify that linking a program with an uncompiled geometry shader causes a link failure.
TEST_P(GeometryShaderTest,LinkWithUncompiledGeometryShader)160 TEST_P(GeometryShaderTest, LinkWithUncompiledGeometryShader)
161 {
162     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
163 
164     GLuint vertexShader   = CompileShader(GL_VERTEX_SHADER, essl31_shaders::vs::Simple());
165     GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, essl31_shaders::fs::Red());
166     ASSERT_NE(0u, vertexShader);
167     ASSERT_NE(0u, fragmentShader);
168 
169     GLuint geometryShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
170 
171     GLuint program = glCreateProgram();
172     glAttachShader(program, vertexShader);
173     glAttachShader(program, fragmentShader);
174     glAttachShader(program, geometryShader);
175     glDeleteShader(vertexShader);
176     glDeleteShader(fragmentShader);
177     glDeleteShader(geometryShader);
178 
179     glLinkProgram(program);
180 
181     GLint linkStatus;
182     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
183     EXPECT_EQ(0, linkStatus);
184 
185     glDeleteProgram(program);
186     ASSERT_GL_NO_ERROR();
187 }
188 
189 // Verify that linking a program with geometry shader whose version is different from other shaders
190 // in this program causes a link error.
TEST_P(GeometryShaderTest,LinkWhenShaderVersionMismatch)191 TEST_P(GeometryShaderTest, LinkWhenShaderVersionMismatch)
192 {
193     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
194 
195     const std::string &emptyGeometryShader = CreateEmptyGeometryShader("points", "points", 2, 1);
196 
197     GLuint program = CompileProgramWithGS(essl3_shaders::vs::Simple(), emptyGeometryShader.c_str(),
198                                           essl3_shaders::fs::Red());
199     EXPECT_EQ(0u, program);
200 }
201 
202 // Verify that linking a program with geometry shader that lacks input primitive,
203 // output primitive, or declaration on 'max_vertices' causes a link failure.
TEST_P(GeometryShaderTest,LinkValidationOnGeometryShaderLayouts)204 TEST_P(GeometryShaderTest, LinkValidationOnGeometryShaderLayouts)
205 {
206     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
207 
208     const std::string gsWithoutInputPrimitive  = CreateEmptyGeometryShader("", "points", 2, 1);
209     const std::string gsWithoutOutputPrimitive = CreateEmptyGeometryShader("points", "", 2, 1);
210     const std::string gsWithoutInvocations = CreateEmptyGeometryShader("points", "points", -1, 1);
211     const std::string gsWithoutMaxVertices = CreateEmptyGeometryShader("points", "points", 2, -1);
212 
213     // Linking a program with a geometry shader that only lacks 'invocations' should not cause a
214     // link failure.
215     GLuint program = CompileProgramWithGS(essl31_shaders::vs::Simple(),
216                                           gsWithoutInvocations.c_str(), essl31_shaders::fs::Red());
217     EXPECT_NE(0u, program);
218 
219     glDeleteProgram(program);
220 
221     // Linking a program with a geometry shader that lacks input primitive, output primitive or
222     // 'max_vertices' causes a link failure.
223     program = CompileProgramWithGS(essl31_shaders::vs::Simple(), gsWithoutInputPrimitive.c_str(),
224                                    essl31_shaders::fs::Red());
225     EXPECT_EQ(0u, program);
226 
227     program = CompileProgramWithGS(essl31_shaders::vs::Simple(), gsWithoutOutputPrimitive.c_str(),
228                                    essl31_shaders::fs::Red());
229     EXPECT_EQ(0u, program);
230 
231     program = CompileProgramWithGS(essl31_shaders::vs::Simple(), gsWithoutMaxVertices.c_str(),
232                                    essl31_shaders::fs::Red());
233     EXPECT_EQ(0u, program);
234 
235     ASSERT_GL_NO_ERROR();
236 }
237 
238 // Verify that an link error occurs when the vertex shader has an array output and there is a
239 // geometry shader in the program.
TEST_P(GeometryShaderTest,VertexShaderArrayOutput)240 TEST_P(GeometryShaderTest, VertexShaderArrayOutput)
241 {
242     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
243 
244     constexpr char kVS[] = R"(#version 310 es
245 in vec4 vertex_in;
246 out vec4 vertex_out[3];
247 void main()
248 {
249     gl_Position = vertex_in;
250     vertex_out[0] = vec4(1.0, 0.0, 0.0, 1.0);
251     vertex_out[1] = vec4(0.0, 1.0, 0.0, 1.0);
252     vertex_out[2] = vec4(0.0, 0.0, 1.0, 1.0);
253 })";
254 
255     constexpr char kGS[] = R"(#version 310 es
256 #extension GL_EXT_geometry_shader : require
257 layout (invocations = 3, triangles) in;
258 layout (points, max_vertices = 3) out;
259 in vec4 vertex_out[];
260 out vec4 geometry_color;
261 void main()
262 {
263     gl_Position = gl_in[0].gl_Position;
264     geometry_color = vertex_out[0];
265     EmitVertex();
266 })";
267 
268     constexpr char kFS[] = R"(#version 310 es
269 precision mediump float;
270 in vec4 geometry_color;
271 layout (location = 0) out vec4 output_color;
272 void main()
273 {
274     output_color = geometry_color;
275 })";
276 
277     GLuint program = CompileProgramWithGS(kVS, kGS, kFS);
278     EXPECT_EQ(0u, program);
279 
280     EXPECT_GL_NO_ERROR();
281 }
282 
283 // Verify that an link error occurs when the definition of a unform in fragment shader is different
284 // from those in a geometry shader.
TEST_P(GeometryShaderTest,UniformMismatchBetweenGeometryAndFragmentShader)285 TEST_P(GeometryShaderTest, UniformMismatchBetweenGeometryAndFragmentShader)
286 {
287     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
288 
289     constexpr char kVS[] = R"(#version 310 es
290 uniform highp vec4 uniform_value_vert;
291 in vec4 vertex_in;
292 out vec4 vertex_out;
293 void main()
294 {
295     gl_Position = vertex_in;
296     vertex_out = uniform_value_vert;
297 })";
298 
299     constexpr char kGS[] = R"(#version 310 es
300 #extension GL_EXT_geometry_shader : require
301 uniform vec4 uniform_value;
302 layout (invocations = 3, triangles) in;
303 layout (points, max_vertices = 3) out;
304 in vec4 vertex_out[];
305 out vec4 geometry_color;
306 void main()
307 {
308     gl_Position = gl_in[0].gl_Position;
309     geometry_color = vertex_out[0] + uniform_value;
310     EmitVertex();
311 })";
312 
313     constexpr char kFS[] = R"(#version 310 es
314 precision highp float;
315 uniform float uniform_value;
316 in vec4 geometry_color;
317 layout (location = 0) out vec4 output_color;
318 void main()
319 {
320     output_color = vec4(geometry_color.rgb, uniform_value);
321 })";
322 
323     GLuint program = CompileProgramWithGS(kVS, kGS, kFS);
324     EXPECT_EQ(0u, program);
325 
326     EXPECT_GL_NO_ERROR();
327 }
328 
329 // Verify that an link error occurs when the number of uniform blocks in a geometry shader exceeds
330 // MAX_GEOMETRY_UNIFORM_BLOCKS_EXT.
TEST_P(GeometryShaderTest,TooManyUniformBlocks)331 TEST_P(GeometryShaderTest, TooManyUniformBlocks)
332 {
333     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
334 
335     GLint maxGeometryUniformBlocks = 0;
336     glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT, &maxGeometryUniformBlocks);
337 
338     GLint numUniformBlocks = maxGeometryUniformBlocks + 1;
339     std::ostringstream stream;
340     stream << "#version 310 es\n"
341               "#extension GL_EXT_geometry_shader : require\n"
342               "uniform ubo\n"
343               "{\n"
344               "    vec4 value1;\n"
345               "} block0["
346            << numUniformBlocks
347            << "];\n"
348               "layout (triangles) in;\n"
349               "layout (points, max_vertices = 1) out;\n"
350               "void main()\n"
351               "{\n"
352               "    gl_Position = gl_in[0].gl_Position;\n";
353 
354     for (GLint i = 0; i < numUniformBlocks; ++i)
355     {
356         stream << "    gl_Position += block0[" << i << "].value1;\n";
357     }
358     stream << "    EmitVertex();\n"
359               "}\n";
360 
361     GLuint program = CompileProgramWithGS(essl31_shaders::vs::Simple(), stream.str().c_str(),
362                                           essl31_shaders::fs::Red());
363     EXPECT_EQ(0u, program);
364 
365     EXPECT_GL_NO_ERROR();
366 }
367 
368 // Verify that an link error occurs when the number of shader storage blocks in a geometry shader
369 // exceeds MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT.
TEST_P(GeometryShaderTest,TooManyShaderStorageBlocks)370 TEST_P(GeometryShaderTest, TooManyShaderStorageBlocks)
371 {
372     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
373 
374     GLint maxGeometryShaderStorageBlocks = 0;
375     glGetIntegerv(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT, &maxGeometryShaderStorageBlocks);
376 
377     GLint numSSBOs = maxGeometryShaderStorageBlocks + 1;
378     std::ostringstream stream;
379     stream << "#version 310 es\n"
380               "#extension GL_EXT_geometry_shader : require\n"
381               "buffer ssbo\n"
382               "{\n"
383               "    vec4 value1;\n"
384               "} block0["
385            << numSSBOs
386            << "];\n"
387               "layout (triangles) in;\n"
388               "layout (points, max_vertices = 1) out;\n"
389               "void main()\n"
390               "{\n"
391               "    gl_Position = gl_in[0].gl_Position;\n";
392 
393     for (GLint i = 0; i < numSSBOs; ++i)
394     {
395         stream << "    gl_Position += block0[" << i << "].value1;\n";
396     }
397     stream << "    EmitVertex();\n"
398               "}\n";
399 
400     GLuint program = CompileProgramWithGS(essl31_shaders::vs::Simple(), stream.str().c_str(),
401                                           essl31_shaders::fs::Red());
402     EXPECT_EQ(0u, program);
403 
404     EXPECT_GL_NO_ERROR();
405 }
406 
407 // Verify that an link error occurs when the definition of a unform block in the vertex shader is
408 // different from that in a geometry shader.
TEST_P(GeometryShaderTest,UniformBlockMismatchBetweenVertexAndGeometryShader)409 TEST_P(GeometryShaderTest, UniformBlockMismatchBetweenVertexAndGeometryShader)
410 {
411     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
412 
413     constexpr char kVS[] = R"(#version 310 es
414 uniform ubo
415 {
416     vec4 uniform_value_vert;
417 } block0;
418 in vec4 vertex_in;
419 out vec4 vertex_out;
420 void main()
421 {
422     gl_Position = vertex_in;
423     vertex_out = block0.uniform_value_vert;
424 })";
425 
426     constexpr char kGS[] = R"(#version 310 es
427 #extension GL_EXT_geometry_shader : require
428 uniform ubo
429 {
430     vec4 uniform_value_geom;
431 } block0;
432 layout (triangles) in;
433 layout (points, max_vertices = 1) out;
434 in vec4 vertex_out[];
435 void main()
436 {
437     gl_Position = gl_in[0].gl_Position + vertex_out[0];
438     gl_Position += block0.uniform_value_geom;
439     EmitVertex();
440 })";
441 
442     GLuint program = CompileProgramWithGS(kVS, kGS, essl31_shaders::fs::Red());
443     EXPECT_EQ(0u, program);
444 
445     EXPECT_GL_NO_ERROR();
446 }
447 
448 // Verify that an link error occurs when the definition of a shader storage block in the geometry
449 // shader is different from that in a fragment shader.
TEST_P(GeometryShaderTest,ShaderStorageBlockMismatchBetweenGeometryAndFragmentShader)450 TEST_P(GeometryShaderTest, ShaderStorageBlockMismatchBetweenGeometryAndFragmentShader)
451 {
452     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
453 
454     GLint maxGeometryShaderStorageBlocks = 0;
455     glGetIntegerv(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT, &maxGeometryShaderStorageBlocks);
456 
457     // The minimun value of MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT can be 0.
458     // [EXT_geometry_shader] Table 20.43gs
459     ANGLE_SKIP_TEST_IF(maxGeometryShaderStorageBlocks == 0);
460 
461     GLint maxFragmentShaderStorageBlocks = 0;
462     glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
463 
464     // The minimun value of MAX_FRAGMENT_SHADER_STORAGE_BLOCKS can be 0.
465     // [OpenGL ES 3.1] Table 20.44
466     ANGLE_SKIP_TEST_IF(maxFragmentShaderStorageBlocks == 0);
467 
468     constexpr char kGS[] = R"(#version 310 es
469 #extension GL_EXT_geometry_shader : require
470 buffer ssbo
471 {
472     vec4 ssbo_value;
473 } block0;
474 layout (triangles) in;
475 layout (points, max_vertices = 1) out;
476 void main()
477 {
478     gl_Position = gl_in[0].gl_Position + block0.ssbo_value;
479     EmitVertex();
480 })";
481 
482     constexpr char kFS[] = R"(#version 310 es
483 precision highp float;
484 buffer ssbo
485 {
486     vec3 ssbo_value;
487 } block0;
488 layout (location = 0) out vec4 output_color;
489 void main()
490 {
491     output_color = vec4(block0.ssbo_value, 1);
492 })";
493 
494     GLuint program = CompileProgramWithGS(essl31_shaders::vs::Simple(), kGS, kFS);
495     EXPECT_EQ(0u, program);
496 
497     EXPECT_GL_NO_ERROR();
498 }
499 
500 // Verify GL_REFERENCED_BY_GEOMETRY_SHADER_EXT cannot be used on platforms that don't support
501 // EXT_geometry_shader, or we will get an INVALID_ENUM error.
TEST_P(GeometryShaderTest,ReferencedByGeometryShaderWithoutExtensionEnabled)502 TEST_P(GeometryShaderTest, ReferencedByGeometryShaderWithoutExtensionEnabled)
503 {
504     ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_EXT_geometry_shader"));
505 
506     constexpr char kFS[] = R"(#version 310 es
507 precision highp float;
508 uniform vec4 color;
509 layout(location = 0) out vec4 oColor;
510 void main()
511 {
512     oColor = color;
513 })";
514 
515     ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
516 
517     const GLuint index = glGetProgramResourceIndex(program, GL_UNIFORM, "color");
518     ASSERT_GL_NO_ERROR();
519     ASSERT_NE(GL_INVALID_INDEX, index);
520 
521     constexpr GLenum kProps[]    = {GL_REFERENCED_BY_GEOMETRY_SHADER_EXT};
522     constexpr GLsizei kPropCount = static_cast<GLsizei>(ArraySize(kProps));
523     GLint params[ArraySize(kProps)];
524     GLsizei length;
525 
526     glGetProgramResourceiv(program, GL_UNIFORM, index, kPropCount, kProps, kPropCount, &length,
527                            params);
528     EXPECT_GL_ERROR(GL_INVALID_ENUM);
529 }
530 
531 // Verify GL_REFERENCED_BY_GEOMETRY_SHADER_EXT can work correctly on platforms that support
532 // EXT_geometry_shader.
TEST_P(GeometryShaderTest,ReferencedByGeometryShader)533 TEST_P(GeometryShaderTest, ReferencedByGeometryShader)
534 {
535     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
536 
537     constexpr char kVS[] = R"(#version 310 es
538 precision highp float;
539 layout(location = 0) in highp vec4 position;
540 void main()
541 {
542     gl_Position = position;
543 })";
544 
545     constexpr char kGS[] = R"(#version 310 es
546 #extension GL_EXT_geometry_shader : require
547 layout (binding = 3) uniform ubo0
548 {
549     vec4 ubo0_location;
550 } block0;
551 layout (binding = 4) uniform ubo1
552 {
553     vec4 ubo1_location;
554 } block1;
555 uniform vec4 u_color;
556 layout (triangles) in;
557 layout (points, max_vertices = 1) out;
558 out vec4 gs_out;
559 void main()
560 {
561     gl_Position = gl_in[0].gl_Position;
562     gl_Position += block0.ubo0_location + block1.ubo1_location;
563     gs_out = u_color;
564     EmitVertex();
565 })";
566 
567     constexpr char kFS[] = R"(#version 310 es
568 precision highp float;
569 in vec4 gs_out;
570 layout(location = 0) out vec4 oColor;
571 void main()
572 {
573     oColor = gs_out;
574 })";
575 
576     ANGLE_GL_PROGRAM_WITH_GS(program, kVS, kGS, kFS);
577 
578     constexpr GLenum kProps[]    = {GL_REFERENCED_BY_GEOMETRY_SHADER_EXT};
579     constexpr GLsizei kPropCount = static_cast<GLsizei>(ArraySize(kProps));
580     std::array<GLint, ArraySize(kProps)> params;
581     GLsizei length;
582 
583     params.fill(1);
584     GLuint index = glGetProgramResourceIndex(program, GL_PROGRAM_INPUT, "position");
585     glGetProgramResourceiv(program, GL_PROGRAM_INPUT, index, kPropCount, kProps, kPropCount,
586                            &length, params.data());
587     EXPECT_GL_NO_ERROR();
588     EXPECT_EQ(0, params[0]);
589 
590     params.fill(1);
591     index = glGetProgramResourceIndex(program, GL_PROGRAM_OUTPUT, "oColor");
592     glGetProgramResourceiv(program, GL_PROGRAM_OUTPUT, index, kPropCount, kProps, kPropCount,
593                            &length, params.data());
594     EXPECT_GL_NO_ERROR();
595     EXPECT_EQ(0, params[0]);
596 
597     index = glGetProgramResourceIndex(program, GL_UNIFORM, "u_color");
598     glGetProgramResourceiv(program, GL_UNIFORM, index, kPropCount, kProps, kPropCount, &length,
599                            params.data());
600     EXPECT_GL_NO_ERROR();
601     EXPECT_EQ(1, params[0]);
602 
603     params.fill(0);
604     index = glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, "ubo1");
605     glGetProgramResourceiv(program, GL_UNIFORM_BLOCK, index, kPropCount, kProps, kPropCount,
606                            &length, params.data());
607     EXPECT_GL_NO_ERROR();
608     EXPECT_EQ(1, params[0]);
609 
610     GLint maxGeometryShaderStorageBlocks = 0;
611     glGetIntegerv(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT, &maxGeometryShaderStorageBlocks);
612     // The maximum number of shader storage blocks in a geometry shader can be 0.
613     // [EXT_geometry_shader] Table 20.43gs
614     if (maxGeometryShaderStorageBlocks > 0)
615     {
616         constexpr char kGSWithSSBO[] = R"(#version 310 es
617 #extension GL_EXT_geometry_shader : require
618 layout (binding = 2) buffer ssbo
619 {
620     vec4 ssbo_value;
621 } block0;
622 layout (triangles) in;
623 layout (points, max_vertices = 1) out;
624 out vec4 gs_out;
625 void main()
626 {
627     gl_Position = gl_in[0].gl_Position + block0.ssbo_value;
628     gs_out = block0.ssbo_value;
629     EmitVertex();
630 })";
631 
632         ANGLE_GL_PROGRAM_WITH_GS(programWithSSBO, kVS, kGSWithSSBO, kFS);
633 
634         params.fill(0);
635         index = glGetProgramResourceIndex(programWithSSBO, GL_SHADER_STORAGE_BLOCK, "ssbo");
636         glGetProgramResourceiv(programWithSSBO, GL_SHADER_STORAGE_BLOCK, index, kPropCount, kProps,
637                                kPropCount, &length, params.data());
638         EXPECT_GL_NO_ERROR();
639         EXPECT_EQ(1, params[0]);
640 
641         params.fill(0);
642         index = glGetProgramResourceIndex(programWithSSBO, GL_BUFFER_VARIABLE, "ssbo.ssbo_value");
643         glGetProgramResourceiv(programWithSSBO, GL_BUFFER_VARIABLE, index, kPropCount, kProps,
644                                kPropCount, &length, params.data());
645         EXPECT_GL_NO_ERROR();
646         EXPECT_EQ(1, params[0]);
647     }
648 
649     GLint maxGeometryAtomicCounterBuffers = 0;
650     glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT, &maxGeometryAtomicCounterBuffers);
651     // The maximum number of atomic counter buffers in a geometry shader can be 0.
652     // [EXT_geometry_shader] Table 20.43gs
653     if (maxGeometryAtomicCounterBuffers > 0)
654     {
655         constexpr char kGSWithAtomicCounters[] = R"(#version 310 es
656 #extension GL_EXT_geometry_shader : require
657 layout(binding = 1, offset = 0) uniform atomic_uint gs_counter;
658 layout (triangles) in;
659 layout (points, max_vertices = 1) out;
660 out vec4 gs_out;
661 void main()
662 {
663     atomicCounterIncrement(gs_counter);
664     gl_Position = gl_in[0].gl_Position;
665     gs_out = vec4(1.0, 0.0, 0.0, 1.0);
666     EmitVertex();
667 })";
668 
669         ANGLE_GL_PROGRAM_WITH_GS(programWithAtomicCounter, kVS, kGSWithAtomicCounters, kFS);
670 
671         params.fill(0);
672         index = glGetProgramResourceIndex(programWithAtomicCounter, GL_UNIFORM, "gs_counter");
673         EXPECT_GL_NO_ERROR();
674         glGetProgramResourceiv(programWithAtomicCounter, GL_ATOMIC_COUNTER_BUFFER, index,
675                                kPropCount, kProps, kPropCount, &length, params.data());
676         EXPECT_GL_NO_ERROR();
677         EXPECT_EQ(1, params[0]);
678     }
679 }
680 
681 // Verify correct errors can be reported when we use illegal parameters on FramebufferTextureEXT.
TEST_P(GeometryShaderTest,NegativeFramebufferTextureEXT)682 TEST_P(GeometryShaderTest, NegativeFramebufferTextureEXT)
683 {
684     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
685 
686     GLFramebuffer fbo;
687     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
688 
689     GLTexture tex;
690     glBindTexture(GL_TEXTURE_3D, tex);
691     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
692 
693     // [EXT_geometry_shader] Section 9.2.8, "Attaching Texture Images to a Framebuffer"
694     // An INVALID_ENUM error is generated if <target> is not DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or
695     // FRAMEBUFFER.
696     glFramebufferTextureEXT(GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0, tex, 0);
697     EXPECT_GL_ERROR(GL_INVALID_ENUM);
698 
699     // An INVALID_ENUM error is generated if <attachment> is not one of the attachments in Table
700     // 9.1.
701     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_TEXTURE_2D, tex, 0);
702     EXPECT_GL_ERROR(GL_INVALID_ENUM);
703 
704     // An INVALID_OPERATION error is generated if zero is bound to <target>.
705     glBindFramebuffer(GL_FRAMEBUFFER, 0);
706     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
707     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
708 
709     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
710 
711     // An INVALID_VALUE error is generated if <texture> is not the name of a texture object, or if
712     // <level> is not a supported texture level for <texture>.
713     GLuint tex2;
714     glGenTextures(1, &tex2);
715     glDeleteTextures(1, &tex2);
716     ASSERT_FALSE(glIsTexture(tex2));
717     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2, 0);
718     EXPECT_GL_ERROR(GL_INVALID_VALUE);
719 
720     GLint max3DSize;
721     glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DSize);
722     GLint max3DLevel = static_cast<GLint>(std::log2(max3DSize));
723     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, max3DLevel + 1);
724     EXPECT_GL_ERROR(GL_INVALID_VALUE);
725 }
726 
727 // Verify CheckFramebufferStatus can work correctly on layered depth and stencil attachments.
TEST_P(GeometryShaderTest,LayeredFramebufferCompletenessWithDepthAttachment)728 TEST_P(GeometryShaderTest, LayeredFramebufferCompletenessWithDepthAttachment)
729 {
730     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
731 
732     GLint maxFramebufferLayers;
733     glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS_EXT, &maxFramebufferLayers);
734 
735     constexpr GLint kTexLayers = 2;
736     ASSERT_LT(kTexLayers, maxFramebufferLayers);
737 
738     GLTexture layeredColorTex;
739     glBindTexture(GL_TEXTURE_3D, layeredColorTex);
740     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, kTexLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE,
741                  nullptr);
742 
743     // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
744     // If any framebuffer attachment is layered, all populated attachments must be layered.
745     // {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
746     GLTexture layeredDepthStencilTex;
747     glBindTexture(GL_TEXTURE_2D_ARRAY, layeredDepthStencilTex);
748     glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH24_STENCIL8, 32, 32, kTexLayers, 0,
749                  GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
750 
751     // 1. Color attachment is layered, while depth attachment is not layered.
752     GLFramebuffer fbo1;
753     glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
754     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, layeredColorTex, 0);
755     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, layeredDepthStencilTex, 0, 0);
756     GLenum status1 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
757     ASSERT_GL_NO_ERROR();
758     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT, status1);
759 
760     // 2. Color attachment is not layered, while depth attachment is layered.
761     GLFramebuffer fbo2;
762     glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
763     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, layeredColorTex, 0, 0);
764     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, layeredDepthStencilTex, 0);
765     GLenum status2 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
766     ASSERT_GL_NO_ERROR();
767     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT, status2);
768 
769     // 3. Color attachment is not layered, while stencil attachment is layered.
770     GLFramebuffer fbo3;
771     glBindFramebuffer(GL_FRAMEBUFFER, fbo3);
772     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, layeredColorTex, 0, 0);
773     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, layeredDepthStencilTex, 0);
774     GLenum status3 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
775     ASSERT_GL_NO_ERROR();
776     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT, status3);
777 
778     // [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
779     // If <image> is a three-dimensional texture or a two-dimensional array texture and the
780     // attachment is layered, the depth or layer count, respectively, of the texture is less than or
781     // equal to the value of MAX_FRAMEBUFFER_LAYERS_EXT.
782     GLint maxArrayTextureLayers;
783     glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArrayTextureLayers);
784     GLint depthTexLayer4 = maxFramebufferLayers + 1;
785     ANGLE_SKIP_TEST_IF(maxArrayTextureLayers < depthTexLayer4);
786 
787     // Use a depth attachment whose layer count exceeds MAX_FRAMEBUFFER_LAYERS
788     GLTexture depthTex4;
789     glBindTexture(GL_TEXTURE_2D_ARRAY, depthTex4);
790     glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH24_STENCIL8, 32, 32, depthTexLayer4, 0,
791                  GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
792     GLFramebuffer fbo4;
793     glBindFramebuffer(GL_FRAMEBUFFER, fbo4);
794     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTex4, 0);
795     GLenum status4 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
796     ASSERT_GL_NO_ERROR();
797     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, status4);
798 }
799 
800 // Verify correct errors can be reported when we use layered cube map attachments on a framebuffer.
TEST_P(GeometryShaderTest,NegativeLayeredFramebufferCompletenessWithCubeMapTextures)801 TEST_P(GeometryShaderTest, NegativeLayeredFramebufferCompletenessWithCubeMapTextures)
802 {
803     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
804 
805     GLTexture tex;
806     glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
807 
808     GLFramebuffer fbo;
809     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
810     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
811     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
812     ASSERT_GL_NO_ERROR();
813     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, status);
814 
815     glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE,
816                  nullptr);
817     glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
818     ASSERT_GL_NO_ERROR();
819     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, status);
820 }
821 
822 ANGLE_INSTANTIATE_TEST_ES3(GeometryShaderTestES3);
823 ANGLE_INSTANTIATE_TEST_ES31(GeometryShaderTest);
824 }  // namespace
825