blob: eefd653a533f40d95ffcf6ba659bbe02171b57a4 [file] [log] [blame]
Jiawei Shao89be29a2017-11-06 14:36:45 +08001//
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
11using namespace angle;
12
13namespace
14{
15
16class GeometryShaderTest : public ANGLETest
17{
Jiawei Shao4ed05da2018-02-02 14:26:15 +080018 protected:
19 static std::string CreateEmptyGeometryShader(const std::string &inputPrimitive,
20 const std::string &outputPrimitive,
21 int invocations,
22 int maxVertices)
23 {
24 std::ostringstream ostream;
25 ostream << "#version 310 es\n"
26 "#extension GL_EXT_geometry_shader : require\n";
27 if (!inputPrimitive.empty())
28 {
29 ostream << "layout (" << inputPrimitive << ") in;\n";
30 }
31 if (!outputPrimitive.empty())
32 {
33 ostream << "layout (" << outputPrimitive << ") out;\n";
34 }
35 if (invocations > 0)
36 {
37 ostream << "layout (invocations = " << invocations << ") in;\n";
38 }
39 if (maxVertices >= 0)
40 {
41 ostream << "layout (max_vertices = " << maxVertices << ") out;\n";
42 }
43 ostream << "void main()\n"
44 "{\n"
45 "}";
46 return ostream.str();
47 }
48
49 const std::string kDefaultVertexShader =
50 R"(#version 310 es
51 void main()
52 {
53 gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
54 })";
55
56 const std::string kDefaultFragmentShader =
57 R"(#version 310 es
58 precision mediump float;
59 layout (location = 0) out vec4 frag_out;
60 void main()
61 {
62 frag_out = vec4(1.0, 0.0, 0.0, 1.0);
63 })";
Jiawei Shao89be29a2017-11-06 14:36:45 +080064};
65
66class GeometryShaderTestES3 : public ANGLETest
67{
68};
69
70// Verify that Geometry Shader cannot be created in an OpenGL ES 3.0 context.
71TEST_P(GeometryShaderTestES3, CreateGeometryShaderInES3)
72{
73 EXPECT_TRUE(!extensionEnabled("GL_EXT_geometry_shader"));
74 GLuint geometryShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
75 EXPECT_EQ(0u, geometryShader);
76 EXPECT_GL_ERROR(GL_INVALID_ENUM);
77}
78
79// Verify that Geometry Shader can be created and attached to a program.
80TEST_P(GeometryShaderTest, CreateAndAttachGeometryShader)
81{
82 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
83
84 const std::string &geometryShaderSource =
85 R"(#version 310 es
86 #extension GL_EXT_geometry_shader : require
87 layout (invocations = 3, triangles) in;
88 layout (triangle_strip, max_vertices = 3) out;
89 in vec4 texcoord[];
90 out vec4 o_texcoord;
91 void main()
92 {
93 int n;
94 for (n = 0; n < gl_in.length(); n++)
95 {
96 gl_Position = gl_in[n].gl_Position;
97 gl_Layer = gl_InvocationID;
98 o_texcoord = texcoord[n];
99 EmitVertex();
100 }
101 EndPrimitive();
102 })";
103
104 GLuint geometryShader = CompileShader(GL_GEOMETRY_SHADER_EXT, geometryShaderSource);
105
106 EXPECT_NE(0u, geometryShader);
107
108 GLuint programID = glCreateProgram();
109 glAttachShader(programID, geometryShader);
110
111 glDetachShader(programID, geometryShader);
112 glDeleteShader(geometryShader);
113 glDeleteProgram(programID);
114
115 EXPECT_GL_NO_ERROR();
116}
117
Jiawei Shao361df072017-11-22 09:33:59 +0800118// Verify that all the implementation dependent geometry shader related resource limits meet the
119// requirement of GL_EXT_geometry_shader SPEC.
120TEST_P(GeometryShaderTest, GeometryShaderImplementationDependentLimits)
121{
122 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
123
124 const std::map<GLenum, int> limits = {{GL_MAX_FRAMEBUFFER_LAYERS_EXT, 256},
125 {GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT, 1024},
126 {GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT, 12},
127 {GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT, 64},
128 {GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT, 64},
129 {GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, 256},
130 {GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT, 1024},
131 {GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT, 16},
132 {GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT, 0},
133 {GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT, 0},
134 {GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT, 0},
135 {GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT, 0},
136 {GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT, 32}};
137
138 GLint value;
139 for (const auto &limit : limits)
140 {
141 value = 0;
142 glGetIntegerv(limit.first, &value);
143 EXPECT_GL_NO_ERROR();
144 EXPECT_GE(value, limit.second);
145 }
146
147 value = 0;
148 glGetIntegerv(GL_LAYER_PROVOKING_VERTEX_EXT, &value);
149 EXPECT_GL_NO_ERROR();
150 EXPECT_TRUE(value == GL_FIRST_VERTEX_CONVENTION_EXT || value == GL_LAST_VERTEX_CONVENTION_EXT ||
151 value == GL_UNDEFINED_VERTEX_EXT);
152}
153
154// Verify that all the combined resource limits meet the requirement of GL_EXT_geometry_shader SPEC.
155TEST_P(GeometryShaderTest, CombinedResourceLimits)
156{
157 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
158
159 // See http://anglebug.com/2261.
160 ANGLE_SKIP_TEST_IF(IsAndroid());
161
162 const std::map<GLenum, int> limits = {{GL_MAX_UNIFORM_BUFFER_BINDINGS, 48},
163 {GL_MAX_COMBINED_UNIFORM_BLOCKS, 36},
164 {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 64}};
165
166 GLint value;
167 for (const auto &limit : limits)
168 {
169 value = 0;
170 glGetIntegerv(limit.first, &value);
171 EXPECT_GL_NO_ERROR();
172 EXPECT_GE(value, limit.second);
173 }
174}
175
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800176// Verify that linking a program with an uncompiled geometry shader causes a link failure.
177TEST_P(GeometryShaderTest, LinkWithUncompiledGeoemtryShader)
178{
179 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
180
181 GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, kDefaultVertexShader);
182 GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, kDefaultFragmentShader);
183 ASSERT_NE(0u, vertexShader);
184 ASSERT_NE(0u, fragmentShader);
185
186 GLuint geometryShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
187
188 GLuint program = glCreateProgram();
189 glAttachShader(program, vertexShader);
190 glAttachShader(program, fragmentShader);
191 glAttachShader(program, geometryShader);
192 glDeleteShader(vertexShader);
193 glDeleteShader(fragmentShader);
194 glDeleteShader(geometryShader);
195
196 glLinkProgram(program);
197
198 GLint linkStatus;
199 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
200 EXPECT_EQ(0, linkStatus);
201
202 glDeleteProgram(program);
203 ASSERT_GL_NO_ERROR();
204}
205
206// Verify that linking a program with geometry shader whose version is different from other shaders
207// in this program causes a link error.
208TEST_P(GeometryShaderTest, LinkWhenShaderVersionMismatch)
209{
210 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
211
212 const std::string &kDefaultVertexShaderVersion300 =
213 R"(#version 300 es
214 void main()
215 {
216 gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
217 })";
218
219 const std::string kDefaultFragmentShaderVersion300 =
220 R"(#version 300 es
221 precision mediump float;
222 layout (location = 0) out vec4 frag_out;
223 void main()
224 {
225 frag_out = vec4(1.0, 0.0, 0.0, 1.0);
226 })";
227
228 const std::string &emptyGeometryShader = CreateEmptyGeometryShader("points", "points", 2, 1);
229
230 GLuint program = CompileProgramWithGS(kDefaultVertexShaderVersion300, emptyGeometryShader,
231 kDefaultFragmentShaderVersion300);
232 EXPECT_EQ(0u, program);
233}
234
235// Verify that linking a program with geometry shader that lacks input primitive,
236// output primitive, or declaration on 'max_vertices' causes a link failure.
237TEST_P(GeometryShaderTest, LinkValidationOnGeometryShaderLayouts)
238{
239 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
240
241 const std::string &gsWithoutInputPrimitive = CreateEmptyGeometryShader("", "points", 2, 1);
242 const std::string &gsWithoutOutputPrimitive = CreateEmptyGeometryShader("points", "", 2, 1);
243 const std::string &gsWithoutInvocations = CreateEmptyGeometryShader("points", "points", -1, 1);
244 const std::string &gsWithoutMaxVertices = CreateEmptyGeometryShader("points", "points", 2, -1);
245
246 // Linking a program with a geometry shader that only lacks 'invocations' should not cause a
247 // link failure.
248 GLuint program =
249 CompileProgramWithGS(kDefaultVertexShader, gsWithoutInvocations, kDefaultFragmentShader);
250 EXPECT_NE(0u, program);
251
252 glDeleteProgram(program);
253
254 // Linking a program with a geometry shader that lacks input primitive, output primitive or
255 // 'max_vertices' causes a link failure.
256 program =
257 CompileProgramWithGS(kDefaultVertexShader, gsWithoutInputPrimitive, kDefaultFragmentShader);
258 EXPECT_EQ(0u, program);
259
260 program = CompileProgramWithGS(kDefaultVertexShader, gsWithoutOutputPrimitive,
261 kDefaultFragmentShader);
262 EXPECT_EQ(0u, program);
263
264 program =
265 CompileProgramWithGS(kDefaultVertexShader, gsWithoutMaxVertices, kDefaultFragmentShader);
266 EXPECT_EQ(0u, program);
267
268 ASSERT_GL_NO_ERROR();
269}
270
Jiawei Shaod063aff2018-02-22 10:19:09 +0800271// Verify that an link error occurs when the vertex shader has an array output and there is a
272// geometry shader in the program.
273TEST_P(GeometryShaderTest, VertexShaderArrayOutput)
274{
275 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
276
277 const std::string &vertexShader =
278 R"(#version 310 es
279 in vec4 vertex_in;
280 out vec4 vertex_out[3];
281 void main()
282 {
283 gl_Position = vertex_in;
284 vertex_out[0] = vec4(1.0, 0.0, 0.0, 1.0);
285 vertex_out[1] = vec4(0.0, 1.0, 0.0, 1.0);
286 vertex_out[2] = vec4(0.0, 0.0, 1.0, 1.0);
287 })";
288
289 const std::string &geometryShader =
290 R"(#version 310 es
291 #extension GL_EXT_geometry_shader : require
292 layout (invocations = 3, triangles) in;
293 layout (points, max_vertices = 3) out;
294 in vec4 vertex_out[];
295 out vec4 geometry_color;
296 void main()
297 {
298 gl_Position = gl_in[0].gl_Position;
299 geometry_color = vertex_out[0];
300 EmitVertex();
301 })";
302
303 const std::string &fragmentShader =
304 R"(#version 310 es
305 precision mediump float;
306 in vec4 geometry_color;
307 layout (location = 0) out vec4 output_color;
308 void main()
309 {
310 output_color = geometry_color;
311 })";
312
313 GLuint program = CompileProgramWithGS(vertexShader, geometryShader, fragmentShader);
314 EXPECT_EQ(0u, program);
315
316 EXPECT_GL_NO_ERROR();
317}
318
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800319// Verify that an link error occurs when the definition of a unform in fragment shader is different
320// from those in a geometry shader.
321TEST_P(GeometryShaderTest, UniformMismatchBetweenGeometryAndFragmentShader)
322{
323 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
324
325 const std::string &vertexShader =
326 R"(#version 310 es
327 uniform highp vec4 uniform_value_vert;
328 in vec4 vertex_in;
329 out vec4 vertex_out;
330 void main()
331 {
332 gl_Position = vertex_in;
333 vertex_out = uniform_value_vert;
334 })";
335
336 const std::string &geometryShader =
337 R"(#version 310 es
338 #extension GL_EXT_geometry_shader : require
339 uniform vec4 uniform_value;
340 layout (invocations = 3, triangles) in;
341 layout (points, max_vertices = 3) out;
342 in vec4 vertex_out[];
343 out vec4 geometry_color;
344 void main()
345 {
346 gl_Position = gl_in[0].gl_Position;
347 geometry_color = vertex_out[0] + uniform_value;
348 EmitVertex();
349 })";
350
351 const std::string &fragmentShader =
352 R"(#version 310 es
353 precision highp float;
354 uniform float uniform_value;
355 in vec4 geometry_color;
356 layout (location = 0) out vec4 output_color;
357 void main()
358 {
359 output_color = vec4(geometry_color.rgb, uniform_value);
360 })";
361
362 GLuint program = CompileProgramWithGS(vertexShader, geometryShader, fragmentShader);
363 EXPECT_EQ(0u, program);
364
365 EXPECT_GL_NO_ERROR();
366}
367
Jiawei Shao89be29a2017-11-06 14:36:45 +0800368ANGLE_INSTANTIATE_TEST(GeometryShaderTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11());
369ANGLE_INSTANTIATE_TEST(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
370}