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