1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2016 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Negative Tessellation tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fNegativeTessellationTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "glwDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "tcuStringTemplate.hpp"
30
31 namespace deqp
32 {
33
34 using std::string;
35 using std::map;
36
37 namespace gles31
38 {
39 namespace Functional
40 {
41 namespace NegativeTestShared
42 {
43
44 using tcu::TestLog;
45 using namespace glw;
46
47 static const char* vertexShaderSource = "${GLSL_VERSION_STRING}\n"
48 "${GLSL_PER_VERTEX_OUT}\n"
49 "void main (void)\n"
50 "{\n"
51 " gl_Position = vec4(0.0);\n"
52 "}\n";
53
54 static const char* fragmentShaderSource = "${GLSL_VERSION_STRING}\n"
55 "precision mediump float;\n"
56 "layout(location = 0) out mediump vec4 fragColor;\n"
57 "\n"
58 "void main (void)\n"
59 "{\n"
60 " fragColor = vec4(1.0);\n"
61 "}\n";
62
63 static const char* tessControlShaderSource = "${GLSL_VERSION_STRING}\n"
64 "${GLSL_TESS_EXTENSION_STRING}\n"
65 "${GLSL_PER_VERTEX_IN_ARR}\n"
66 "${GLSL_PER_VERTEX_OUT_ARR}\n"
67 "layout (vertices=3) out;\n"
68 "\n"
69 "void main()\n"
70 "{\n"
71 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
72 "}\n";
73
74 static const char* tessEvalShaderSource = "${GLSL_VERSION_STRING}\n"
75 "${GLSL_TESS_EXTENSION_STRING}\n"
76 "${GLSL_PER_VERTEX_IN_ARR}\n"
77 "${GLSL_PER_VERTEX_OUT}\n"
78 "layout(triangles) in;\n"
79 "\n"
80 "void main()\n"
81 "{\n"
82 " gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position;\n"
83 "}\n";
84
checkExtensionSupport(NegativeTestContext & ctx,const char * extName)85 static void checkExtensionSupport (NegativeTestContext& ctx, const char* extName)
86 {
87 if (!ctx.getContextInfo().isExtensionSupported(extName))
88 throw tcu::NotSupportedError(string(extName) + " not supported");
89 }
90
checkTessellationSupport(NegativeTestContext & ctx)91 static void checkTessellationSupport (NegativeTestContext& ctx)
92 {
93 if (glu::isContextTypeES(ctx.getRenderContext().getType()))
94 checkExtensionSupport(ctx, "GL_EXT_tessellation_shader");
95 }
96
97 // Helper for constructing tessellation pipeline sources.
makeTessPipelineSources(const std::string & vertexSrc,const std::string & fragmentSrc,const std::string & tessCtrlSrc,const std::string & tessEvalSrc)98 static glu::ProgramSources makeTessPipelineSources (const std::string& vertexSrc, const std::string& fragmentSrc, const std::string& tessCtrlSrc, const std::string& tessEvalSrc)
99 {
100 glu::ProgramSources sources;
101 sources.sources[glu::SHADERTYPE_VERTEX].push_back(vertexSrc);
102 sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fragmentSrc);
103
104 if (!tessCtrlSrc.empty())
105 sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].push_back(tessCtrlSrc);
106
107 if (!tessEvalSrc.empty())
108 sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].push_back(tessEvalSrc);
109
110 return sources;
111 }
112
constructSpecializationMap(NegativeTestContext & ctx)113 map<string, string> constructSpecializationMap(NegativeTestContext& ctx)
114 {
115 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(ctx.getRenderContext().getType());
116 bool isES31 = (glslVersion == glu::GLSL_VERSION_310_ES);
117 string ext = isES31 ? "#extension GL_EXT_tessellation_shader : require" : "";
118 return
119 {
120 { "GLSL_VERSION_STRING", getGLSLVersionDeclaration(glslVersion) },
121 { "GLSL_TESS_EXTENSION_STRING", ext },
122 { "GLSL_PER_VERTEX_OUT", "" }, // needed for GL4.5
123 { "GLSL_PER_VERTEX_IN_ARR", "" },
124 { "GLSL_PER_VERTEX_OUT_ARR", "" }
125 };
126 }
127
128 // Incomplete active tess shaders
single_tessellation_stage(NegativeTestContext & ctx)129 void single_tessellation_stage (NegativeTestContext& ctx)
130 {
131 // this case does not apply to GL4.5
132 if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
133 return;
134
135 const bool requireTES = !ctx.getContextInfo().isExtensionSupported("GL_NV_gpu_shader5");
136 map<string, string> args = constructSpecializationMap(ctx);
137
138 checkTessellationSupport(ctx);
139
140 {
141 glu::ShaderProgram program(ctx.getRenderContext(),
142 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
143 tcu::StringTemplate(fragmentShaderSource).specialize(args),
144 tcu::StringTemplate(tessControlShaderSource).specialize(args),
145 "")); // missing tessEvalShaderSource
146 tcu::TestLog& log = ctx.getLog();
147 log << program;
148
149 ctx.beginSection("A link error is generated if a non-separable program has a tessellation control shader but no tessellation evaluation shader, unless GL_NV_gpu_shader5 is supported.");
150
151 if (requireTES && program.isOk())
152 ctx.fail("Program was not expected to link");
153 else if (!requireTES && !program.isOk())
154 ctx.fail("Program was expected to link");
155
156 ctx.endSection();
157 }
158
159 {
160 glu::ShaderProgram program(ctx.getRenderContext(),
161 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
162 tcu::StringTemplate(fragmentShaderSource).specialize(args),
163 tcu::StringTemplate(tessControlShaderSource).specialize(args),
164 "") // missing tessEvalShaderSource
165 << glu::ProgramSeparable(true));
166 tcu::TestLog& log = ctx.getLog();
167 log << program;
168
169 if (!program.isOk())
170 TCU_THROW(TestError, "failed to build program");
171
172 ctx.glUseProgram(program.getProgram());
173 ctx.expectError(GL_NO_ERROR);
174
175 ctx.beginSection("GL_INVALID_OPERATION is generated if current program state has tessellation control shader but no tessellation evaluation shader, unless GL_NV_gpu_shader5 is supported.");
176 ctx.glDrawArrays(GL_PATCHES, 0, 3);
177 ctx.expectError(requireTES ? GL_INVALID_OPERATION : GL_NO_ERROR);
178 ctx.endSection();
179
180 ctx.glUseProgram(0);
181 }
182
183 {
184 glu::ShaderProgram program(ctx.getRenderContext(),
185 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
186 tcu::StringTemplate(fragmentShaderSource).specialize(args),
187 "", // missing tessControlShaderSource
188 tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
189 tcu::TestLog& log = ctx.getLog();
190 log << program;
191
192 ctx.beginSection("A link error is generated if a non-separable program has a tessellation evaluation shader but no tessellation control shader.");
193
194 if (program.isOk())
195 ctx.fail("Program was not expected to link");
196
197 ctx.endSection();
198 }
199
200 {
201 glu::ShaderProgram program(ctx.getRenderContext(),
202 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
203 tcu::StringTemplate(fragmentShaderSource).specialize(args),
204 "", // missing tessControlShaderSource
205 tcu::StringTemplate(tessEvalShaderSource).specialize(args))
206 << glu::ProgramSeparable(true));
207 tcu::TestLog& log = ctx.getLog();
208 log << program;
209
210 if (!program.isOk())
211 TCU_THROW(TestError, "failed to build program");
212
213 ctx.glUseProgram(program.getProgram());
214 ctx.expectError(GL_NO_ERROR);
215
216 ctx.beginSection("GL_INVALID_OPERATION is generated if current program state has tessellation evaluation shader but no tessellation control shader.");
217 ctx.glDrawArrays(GL_PATCHES, 0, 3);
218 ctx.expectError(GL_INVALID_OPERATION);
219 ctx.endSection();
220
221 ctx.glUseProgram(0);
222 }
223 }
224
225 // Complete active tess shaders invalid primitive mode
invalid_primitive_mode(NegativeTestContext & ctx)226 void invalid_primitive_mode (NegativeTestContext& ctx)
227 {
228 checkTessellationSupport(ctx);
229
230 map<string, string> args = constructSpecializationMap(ctx);
231 glu::ShaderProgram program(ctx.getRenderContext(),
232 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
233 tcu::StringTemplate(fragmentShaderSource).specialize(args),
234 tcu::StringTemplate(tessControlShaderSource).specialize(args),
235 tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
236 tcu::TestLog& log = ctx.getLog();
237 log << program;
238
239 ctx.glUseProgram(program.getProgram());
240 ctx.expectError(GL_NO_ERROR);
241
242 ctx.beginSection("GL_INVALID_OPERATION is generated if tessellation is active and primitive mode is not GL_PATCHES.");
243 ctx.glDrawArrays(GL_TRIANGLES, 0, 3);
244 ctx.expectError(GL_INVALID_OPERATION);
245 ctx.endSection();
246
247 ctx.glUseProgram(0);
248 }
249
tessellation_not_active(NegativeTestContext & ctx)250 void tessellation_not_active (NegativeTestContext& ctx)
251 {
252 checkTessellationSupport(ctx);
253
254 const glw::GLenum tessErr = ctx.getContextInfo().isExtensionSupported("GL_NV_gpu_shader5") ? GL_NO_ERROR : GL_INVALID_OPERATION;
255 map<string, string> args = constructSpecializationMap(ctx);
256 glu::ShaderProgram program(ctx.getRenderContext(),
257 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
258 tcu::StringTemplate(fragmentShaderSource).specialize(args),
259 "", // missing tessControlShaderSource
260 "")); // missing tessEvalShaderSource
261 tcu::TestLog& log = ctx.getLog();
262 log << program;
263
264 GLuint vao = 0;
265 if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
266 {
267 ctx.glGenVertexArrays(1, &vao);
268 ctx.glBindVertexArray(vao);
269 }
270
271 ctx.glUseProgram(program.getProgram());
272 ctx.expectError(GL_NO_ERROR);
273
274 ctx.beginSection("GL_INVALID_OPERATION is generated if tessellation is not active and primitive mode is GL_PATCHES, unless GL_NV_gpu_shader5 is supported.");
275 ctx.glDrawArrays(GL_PATCHES, 0, 3);
276 ctx.expectError(tessErr);
277 ctx.endSection();
278
279 ctx.glUseProgram(0);
280
281 if (vao)
282 ctx.glDeleteVertexArrays(1, &vao);
283 }
284
invalid_program_state(NegativeTestContext & ctx)285 void invalid_program_state (NegativeTestContext& ctx)
286 {
287 checkTessellationSupport(ctx);
288
289 const glu::RenderContext& rc = ctx.getRenderContext();
290 map<string, string> args = constructSpecializationMap(ctx);
291
292 // for gl4.5 we need to add per vertex sections
293 if (!glu::isContextTypeES(rc.getType()))
294 {
295 args["GLSL_PER_VERTEX_OUT"] = "out gl_PerVertex { vec4 gl_Position; };\n";
296 args["GLSL_PER_VERTEX_IN_ARR"] = "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
297 args["GLSL_PER_VERTEX_OUT_ARR"] = "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
298 }
299
300 glu::FragmentSource frgSource(tcu::StringTemplate(fragmentShaderSource).specialize(args));
301 glu::TessellationControlSource tessCtrlSource(tcu::StringTemplate(tessControlShaderSource).specialize(args));
302 glu::TessellationEvaluationSource tessEvalSource(tcu::StringTemplate(tessEvalShaderSource).specialize(args));
303
304 glu::ProgramPipeline pipeline(rc);
305
306 glu::ShaderProgram fragProgram (rc, glu::ProgramSources() << glu::ProgramSeparable(true) << frgSource);
307 glu::ShaderProgram tessCtrlProgram (rc, glu::ProgramSources() << glu::ProgramSeparable(true) << tessCtrlSource);
308 glu::ShaderProgram tessEvalProgram (rc, glu::ProgramSources() << glu::ProgramSeparable(true) << tessEvalSource);
309
310 tcu::TestLog& log = ctx.getLog();
311 log << fragProgram << tessCtrlProgram << tessEvalProgram;
312
313 if (!fragProgram.isOk() || !tessCtrlProgram.isOk() || !tessEvalProgram.isOk())
314 throw tcu::TestError("failed to build program");
315
316 ctx.glBindProgramPipeline(pipeline.getPipeline());
317 ctx.expectError(GL_NO_ERROR);
318
319 ctx.glUseProgramStages(pipeline.getPipeline(), GL_FRAGMENT_SHADER_BIT, fragProgram.getProgram());
320 ctx.glUseProgramStages(pipeline.getPipeline(), GL_TESS_CONTROL_SHADER_BIT, tessCtrlProgram.getProgram());
321 ctx.glUseProgramStages(pipeline.getPipeline(), GL_TESS_EVALUATION_SHADER_BIT, tessEvalProgram.getProgram());
322 ctx.expectError(GL_NO_ERROR);
323
324 ctx.beginSection("GL_INVALID_OPERATION is generated if tessellation is active and vertex shader is missing.");
325 ctx.glDrawArrays(GL_PATCHES, 0, 3);
326 ctx.expectError(GL_INVALID_OPERATION);
327 ctx.endSection();
328
329 ctx.glBindProgramPipeline(0);
330 ctx.expectError(GL_NO_ERROR);
331 }
332
tessellation_control_invalid_vertex_count(NegativeTestContext & ctx)333 void tessellation_control_invalid_vertex_count (NegativeTestContext& ctx)
334 {
335 checkTessellationSupport(ctx);
336
337 const char* const tessControlVertLimitSource = "${GLSL_VERSION_STRING}\n"
338 "${GLSL_TESS_EXTENSION_STRING}\n"
339 "layout (vertices=${GL_MAX_PATCH_LIMIT}) out;\n"
340 "void main()\n"
341 "{\n"
342 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
343 "}\n";
344
345 map<string, string> args = constructSpecializationMap(ctx);
346 int maxPatchVertices= 0;
347
348 ctx.beginSection("Output vertex count exceeds GL_MAX_PATCH_VERTICES.");
349 ctx.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
350 ctx.expectError(GL_NO_ERROR);
351
352 std::ostringstream oss;
353 oss << (maxPatchVertices + 1);
354 args["GL_MAX_PATCH_LIMIT"] = oss.str();
355
356
357 glu::ShaderProgram program(ctx.getRenderContext(),
358 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
359 tcu::StringTemplate(fragmentShaderSource).specialize(args),
360 tcu::StringTemplate(tessControlVertLimitSource).specialize(args),
361 tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
362 tcu::TestLog& log = ctx.getLog();
363 log << program;
364
365 bool testFailed = program.getProgramInfo().linkOk;
366
367 if (testFailed)
368 ctx.fail("Program was not expected to link");
369
370 ctx.endSection();
371 }
372
invalid_get_programiv(NegativeTestContext & ctx)373 void invalid_get_programiv (NegativeTestContext& ctx)
374 {
375 checkTessellationSupport(ctx);
376
377 GLuint program = ctx.glCreateProgram();
378 GLint params[1] = { 0 };
379
380 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_CONTROL_OUTPUT_VERTICES is queried for a program which has not been linked properly.");
381 ctx.glGetProgramiv(program, GL_TESS_CONTROL_OUTPUT_VERTICES, ¶ms[0]);
382 ctx.expectError(GL_INVALID_OPERATION);
383 ctx.endSection();
384
385 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_MODE is queried for a program which has not been linked properly.");
386 ctx.glGetProgramiv(program, GL_TESS_GEN_MODE, ¶ms[0]);
387 ctx.expectError(GL_INVALID_OPERATION);
388 ctx.endSection();
389
390 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_SPACING is queried for a program which has not been linked properly.");
391 ctx.glGetProgramiv(program, GL_TESS_GEN_SPACING, ¶ms[0]);
392 ctx.expectError(GL_INVALID_OPERATION);
393 ctx.endSection();
394
395 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_VERTEX_ORDER is queried for a program which has not been linked properly.");
396 ctx.glGetProgramiv(program, GL_TESS_GEN_VERTEX_ORDER, ¶ms[0]);
397 ctx.expectError(GL_INVALID_OPERATION);
398 ctx.endSection();
399
400 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_POINT_MODE is queried for a program which has not been linked properly.");
401 ctx.glGetProgramiv(program, GL_TESS_GEN_POINT_MODE, ¶ms[0]);
402 ctx.expectError(GL_INVALID_OPERATION);
403 ctx.endSection();
404
405 ctx.glDeleteProgram(program);
406 }
407
invalid_patch_parameteri(NegativeTestContext & ctx)408 void invalid_patch_parameteri (NegativeTestContext& ctx)
409 {
410 checkTessellationSupport(ctx);
411
412 ctx.beginSection("GL_INVALID_ENUM is generated if pname is not GL_PATCH_VERTICES.");
413 ctx.glPatchParameteri(-1, 1);
414 ctx.expectError(GL_INVALID_ENUM);
415 ctx.endSection();
416
417 ctx.beginSection("GL_INVALID_VALUE is generated if value is less than or equal to zero.");
418 ctx.glPatchParameteri(GL_PATCH_VERTICES, 0);
419 ctx.expectError(GL_INVALID_VALUE);
420 ctx.endSection();
421
422 int maxPatchVertices= 0;
423 ctx.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
424 ctx.expectError(GL_NO_ERROR);
425
426 ctx.beginSection("GL_INVALID_VALUE is generated if value is greater than GL_MAX_PATCH_VERTICES.");
427 ctx.glPatchParameteri(GL_PATCH_VERTICES, maxPatchVertices + 1);
428 ctx.expectError(GL_INVALID_VALUE);
429 ctx.endSection();
430 }
431
getNegativeTessellationTestFunctions(void)432 std::vector<FunctionContainer> getNegativeTessellationTestFunctions (void)
433 {
434 const FunctionContainer funcs[] =
435 {
436 { single_tessellation_stage, "single_tessellation_stage", "Invalid program state with single tessellation stage" },
437 { invalid_primitive_mode, "invalid_primitive_mode", "Invalid primitive mode when tessellation is active" },
438 { tessellation_not_active, "tessellation_not_active", "Use of GL_PATCHES when tessellation is not active" },
439 { invalid_program_state, "invalid_program_state", "Invalid program state when tessellation active but no vertex shader present" },
440 { invalid_get_programiv, "get_programiv", "Invalid glGetProgramiv() usage" },
441 { invalid_patch_parameteri, "invalid_program_queries", "Invalid glPatchParameteri() usage" },
442 { tessellation_control_invalid_vertex_count, "tessellation_control_invalid_vertex_count", "Exceed vertex count limit in tessellation control shader" },
443 };
444
445 return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
446 }
447
448 } // NegativeTestShared
449 } // Functional
450 } // gles31
451 } // deqp
452