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::map;
35 using std::string;
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 =
64 "${GLSL_VERSION_STRING}\n"
65 "${GLSL_TESS_EXTENSION_STRING}\n"
66 "${GLSL_PER_VERTEX_IN_ARR}\n"
67 "${GLSL_PER_VERTEX_OUT_ARR}\n"
68 "layout (vertices=3) out;\n"
69 "\n"
70 "void main()\n"
71 "{\n"
72 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
73 "}\n";
74
75 static const char *tessEvalShaderSource = "${GLSL_VERSION_STRING}\n"
76 "${GLSL_TESS_EXTENSION_STRING}\n"
77 "${GLSL_PER_VERTEX_IN_ARR}\n"
78 "${GLSL_PER_VERTEX_OUT}\n"
79 "layout(triangles) in;\n"
80 "\n"
81 "void main()\n"
82 "{\n"
83 " gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position;\n"
84 "}\n";
85
checkExtensionSupport(NegativeTestContext & ctx,const char * extName)86 static void checkExtensionSupport(NegativeTestContext &ctx, const char *extName)
87 {
88 if (!ctx.getContextInfo().isExtensionSupported(extName))
89 throw tcu::NotSupportedError(string(extName) + " not supported");
90 }
91
checkTessellationSupport(NegativeTestContext & ctx)92 static void checkTessellationSupport(NegativeTestContext &ctx)
93 {
94 if (glu::isContextTypeES(ctx.getRenderContext().getType()))
95 checkExtensionSupport(ctx, "GL_EXT_tessellation_shader");
96 }
97
98 // Helper for constructing tessellation pipeline sources.
makeTessPipelineSources(const std::string & vertexSrc,const std::string & fragmentSrc,const std::string & tessCtrlSrc,const std::string & tessEvalSrc)99 static glu::ProgramSources makeTessPipelineSources(const std::string &vertexSrc, const std::string &fragmentSrc,
100 const std::string &tessCtrlSrc, const std::string &tessEvalSrc)
101 {
102 glu::ProgramSources sources;
103 sources.sources[glu::SHADERTYPE_VERTEX].push_back(vertexSrc);
104 sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fragmentSrc);
105
106 if (!tessCtrlSrc.empty())
107 sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].push_back(tessCtrlSrc);
108
109 if (!tessEvalSrc.empty())
110 sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].push_back(tessEvalSrc);
111
112 return sources;
113 }
114
constructSpecializationMap(NegativeTestContext & ctx)115 map<string, string> constructSpecializationMap(NegativeTestContext &ctx)
116 {
117 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(ctx.getRenderContext().getType());
118 bool isES31 = (glslVersion == glu::GLSL_VERSION_310_ES);
119 string ext = isES31 ? "#extension GL_EXT_tessellation_shader : require" : "";
120 return {{"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 // Incomplete active tess shaders
single_tessellation_stage(NegativeTestContext & ctx)128 void single_tessellation_stage(NegativeTestContext &ctx)
129 {
130 // this case does not apply to GL4.5
131 if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
132 return;
133
134 const bool requireTES = !ctx.getContextInfo().isExtensionSupported("GL_NV_gpu_shader5");
135 map<string, string> args = constructSpecializationMap(ctx);
136
137 checkTessellationSupport(ctx);
138
139 {
140 glu::ShaderProgram program(
141 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 "
150 "no tessellation evaluation shader, unless GL_NV_gpu_shader5 is supported.");
151
152 if (requireTES && program.isOk())
153 ctx.fail("Program was not expected to link");
154 else if (!requireTES && !program.isOk())
155 ctx.fail("Program was expected to link");
156
157 ctx.endSection();
158 }
159
160 {
161 glu::ShaderProgram program(
162 ctx.getRenderContext(),
163 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
164 tcu::StringTemplate(fragmentShaderSource).specialize(args),
165 tcu::StringTemplate(tessControlShaderSource).specialize(args),
166 "") // missing tessEvalShaderSource
167 << glu::ProgramSeparable(true));
168 tcu::TestLog &log = ctx.getLog();
169 log << program;
170
171 if (!program.isOk())
172 TCU_THROW(TestError, "failed to build program");
173
174 ctx.glUseProgram(program.getProgram());
175 ctx.expectError(GL_NO_ERROR);
176
177 ctx.beginSection("GL_INVALID_OPERATION is generated if current program state has tessellation control shader "
178 "but no tessellation evaluation shader, unless GL_NV_gpu_shader5 is supported.");
179 ctx.glDrawArrays(GL_PATCHES, 0, 3);
180 ctx.expectError(requireTES ? GL_INVALID_OPERATION : GL_NO_ERROR);
181 ctx.endSection();
182
183 ctx.glUseProgram(0);
184 }
185
186 {
187 glu::ShaderProgram program(ctx.getRenderContext(),
188 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
189 tcu::StringTemplate(fragmentShaderSource).specialize(args),
190 "", // missing tessControlShaderSource
191 tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
192 tcu::TestLog &log = ctx.getLog();
193 log << program;
194
195 ctx.beginSection("A link error is generated if a non-separable program has a tessellation evaluation shader "
196 "but no tessellation control shader.");
197
198 if (program.isOk())
199 ctx.fail("Program was not expected to link");
200
201 ctx.endSection();
202 }
203
204 {
205 glu::ShaderProgram program(ctx.getRenderContext(),
206 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
207 tcu::StringTemplate(fragmentShaderSource).specialize(args),
208 "", // missing tessControlShaderSource
209 tcu::StringTemplate(tessEvalShaderSource).specialize(args))
210 << glu::ProgramSeparable(true));
211 tcu::TestLog &log = ctx.getLog();
212 log << program;
213
214 if (!program.isOk())
215 TCU_THROW(TestError, "failed to build program");
216
217 ctx.glUseProgram(program.getProgram());
218 ctx.expectError(GL_NO_ERROR);
219
220 ctx.beginSection("GL_INVALID_OPERATION is generated if current program state has tessellation evaluation "
221 "shader but no tessellation control shader.");
222 ctx.glDrawArrays(GL_PATCHES, 0, 3);
223 ctx.expectError(GL_INVALID_OPERATION);
224 ctx.endSection();
225
226 ctx.glUseProgram(0);
227 }
228 }
229
230 // Complete active tess shaders invalid primitive mode
invalid_primitive_mode(NegativeTestContext & ctx)231 void invalid_primitive_mode(NegativeTestContext &ctx)
232 {
233 checkTessellationSupport(ctx);
234
235 map<string, string> args = constructSpecializationMap(ctx);
236 glu::ShaderProgram program(ctx.getRenderContext(),
237 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
238 tcu::StringTemplate(fragmentShaderSource).specialize(args),
239 tcu::StringTemplate(tessControlShaderSource).specialize(args),
240 tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
241 tcu::TestLog &log = ctx.getLog();
242 log << program;
243
244 ctx.glUseProgram(program.getProgram());
245 ctx.expectError(GL_NO_ERROR);
246
247 ctx.beginSection(
248 "GL_INVALID_OPERATION is generated if tessellation is active and primitive mode is not GL_PATCHES.");
249 ctx.glDrawArrays(GL_TRIANGLES, 0, 3);
250 ctx.expectError(GL_INVALID_OPERATION);
251 ctx.endSection();
252
253 ctx.glUseProgram(0);
254 }
255
tessellation_not_active(NegativeTestContext & ctx)256 void tessellation_not_active(NegativeTestContext &ctx)
257 {
258 checkTessellationSupport(ctx);
259
260 const glw::GLenum tessErr =
261 ctx.getContextInfo().isExtensionSupported("GL_NV_gpu_shader5") ? GL_NO_ERROR : GL_INVALID_OPERATION;
262 map<string, string> args = constructSpecializationMap(ctx);
263 glu::ShaderProgram program(ctx.getRenderContext(),
264 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
265 tcu::StringTemplate(fragmentShaderSource).specialize(args),
266 "", // missing tessControlShaderSource
267 "")); // missing tessEvalShaderSource
268 tcu::TestLog &log = ctx.getLog();
269 log << program;
270
271 GLuint vao = 0;
272 if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
273 {
274 ctx.glGenVertexArrays(1, &vao);
275 ctx.glBindVertexArray(vao);
276 }
277
278 ctx.glUseProgram(program.getProgram());
279 ctx.expectError(GL_NO_ERROR);
280
281 ctx.beginSection("GL_INVALID_OPERATION is generated if tessellation is not active and primitive mode is "
282 "GL_PATCHES, unless GL_NV_gpu_shader5 is supported.");
283 ctx.glDrawArrays(GL_PATCHES, 0, 3);
284 ctx.expectError(tessErr);
285 ctx.endSection();
286
287 ctx.glUseProgram(0);
288
289 if (vao)
290 ctx.glDeleteVertexArrays(1, &vao);
291 }
292
invalid_program_state(NegativeTestContext & ctx)293 void invalid_program_state(NegativeTestContext &ctx)
294 {
295 checkTessellationSupport(ctx);
296
297 const glu::RenderContext &rc = ctx.getRenderContext();
298 map<string, string> args = constructSpecializationMap(ctx);
299
300 // for gl4.5 we need to add per vertex sections
301 if (!glu::isContextTypeES(rc.getType()))
302 {
303 args["GLSL_PER_VERTEX_OUT"] = "out gl_PerVertex { vec4 gl_Position; };\n";
304 args["GLSL_PER_VERTEX_IN_ARR"] = "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
305 args["GLSL_PER_VERTEX_OUT_ARR"] = "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
306 }
307
308 glu::FragmentSource frgSource(tcu::StringTemplate(fragmentShaderSource).specialize(args));
309 glu::TessellationControlSource tessCtrlSource(tcu::StringTemplate(tessControlShaderSource).specialize(args));
310 glu::TessellationEvaluationSource tessEvalSource(tcu::StringTemplate(tessEvalShaderSource).specialize(args));
311
312 glu::ProgramPipeline pipeline(rc);
313
314 glu::ShaderProgram fragProgram(rc, glu::ProgramSources() << glu::ProgramSeparable(true) << frgSource);
315 glu::ShaderProgram tessCtrlProgram(rc, glu::ProgramSources() << glu::ProgramSeparable(true) << tessCtrlSource);
316 glu::ShaderProgram tessEvalProgram(rc, glu::ProgramSources() << glu::ProgramSeparable(true) << tessEvalSource);
317
318 tcu::TestLog &log = ctx.getLog();
319 log << fragProgram << tessCtrlProgram << tessEvalProgram;
320
321 if (!fragProgram.isOk() || !tessCtrlProgram.isOk() || !tessEvalProgram.isOk())
322 throw tcu::TestError("failed to build program");
323
324 ctx.glBindProgramPipeline(pipeline.getPipeline());
325 ctx.expectError(GL_NO_ERROR);
326
327 ctx.glUseProgramStages(pipeline.getPipeline(), GL_FRAGMENT_SHADER_BIT, fragProgram.getProgram());
328 ctx.glUseProgramStages(pipeline.getPipeline(), GL_TESS_CONTROL_SHADER_BIT, tessCtrlProgram.getProgram());
329 ctx.glUseProgramStages(pipeline.getPipeline(), GL_TESS_EVALUATION_SHADER_BIT, tessEvalProgram.getProgram());
330 ctx.expectError(GL_NO_ERROR);
331
332 ctx.beginSection("GL_INVALID_OPERATION is generated if tessellation is active and vertex shader is missing.");
333 ctx.glDrawArrays(GL_PATCHES, 0, 3);
334 ctx.expectError(GL_INVALID_OPERATION);
335 ctx.endSection();
336
337 ctx.glBindProgramPipeline(0);
338 ctx.expectError(GL_NO_ERROR);
339 }
340
tessellation_control_invalid_vertex_count(NegativeTestContext & ctx)341 void tessellation_control_invalid_vertex_count(NegativeTestContext &ctx)
342 {
343 checkTessellationSupport(ctx);
344
345 const char *const tessControlVertLimitSource =
346 "${GLSL_VERSION_STRING}\n"
347 "${GLSL_TESS_EXTENSION_STRING}\n"
348 "layout (vertices=${GL_MAX_PATCH_LIMIT}) out;\n"
349 "void main()\n"
350 "{\n"
351 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
352 "}\n";
353
354 map<string, string> args = constructSpecializationMap(ctx);
355 int maxPatchVertices = 0;
356
357 ctx.beginSection("Output vertex count exceeds GL_MAX_PATCH_VERTICES.");
358 ctx.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
359 ctx.expectError(GL_NO_ERROR);
360
361 std::ostringstream oss;
362 oss << (maxPatchVertices + 1);
363 args["GL_MAX_PATCH_LIMIT"] = oss.str();
364
365 glu::ShaderProgram program(ctx.getRenderContext(),
366 makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
367 tcu::StringTemplate(fragmentShaderSource).specialize(args),
368 tcu::StringTemplate(tessControlVertLimitSource).specialize(args),
369 tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
370 tcu::TestLog &log = ctx.getLog();
371 log << program;
372
373 bool testFailed = program.getProgramInfo().linkOk;
374
375 if (testFailed)
376 ctx.fail("Program was not expected to link");
377
378 ctx.endSection();
379 }
380
invalid_get_programiv(NegativeTestContext & ctx)381 void invalid_get_programiv(NegativeTestContext &ctx)
382 {
383 checkTessellationSupport(ctx);
384
385 GLuint program = ctx.glCreateProgram();
386 GLint params[1] = {0};
387
388 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_CONTROL_OUTPUT_VERTICES is queried for a program "
389 "which has not been linked properly.");
390 ctx.glGetProgramiv(program, GL_TESS_CONTROL_OUTPUT_VERTICES, ¶ms[0]);
391 ctx.expectError(GL_INVALID_OPERATION);
392 ctx.endSection();
393
394 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_MODE is queried for a program which has not "
395 "been linked properly.");
396 ctx.glGetProgramiv(program, GL_TESS_GEN_MODE, ¶ms[0]);
397 ctx.expectError(GL_INVALID_OPERATION);
398 ctx.endSection();
399
400 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_SPACING is queried for a program which has not "
401 "been linked properly.");
402 ctx.glGetProgramiv(program, GL_TESS_GEN_SPACING, ¶ms[0]);
403 ctx.expectError(GL_INVALID_OPERATION);
404 ctx.endSection();
405
406 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_VERTEX_ORDER is queried for a program which has "
407 "not been linked properly.");
408 ctx.glGetProgramiv(program, GL_TESS_GEN_VERTEX_ORDER, ¶ms[0]);
409 ctx.expectError(GL_INVALID_OPERATION);
410 ctx.endSection();
411
412 ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_POINT_MODE is queried for a program which has "
413 "not been linked properly.");
414 ctx.glGetProgramiv(program, GL_TESS_GEN_POINT_MODE, ¶ms[0]);
415 ctx.expectError(GL_INVALID_OPERATION);
416 ctx.endSection();
417
418 ctx.glDeleteProgram(program);
419 }
420
invalid_patch_parameteri(NegativeTestContext & ctx)421 void invalid_patch_parameteri(NegativeTestContext &ctx)
422 {
423 checkTessellationSupport(ctx);
424
425 ctx.beginSection("GL_INVALID_ENUM is generated if pname is not GL_PATCH_VERTICES.");
426 ctx.glPatchParameteri(-1, 1);
427 ctx.expectError(GL_INVALID_ENUM);
428 ctx.endSection();
429
430 ctx.beginSection("GL_INVALID_VALUE is generated if value is less than or equal to zero.");
431 ctx.glPatchParameteri(GL_PATCH_VERTICES, 0);
432 ctx.expectError(GL_INVALID_VALUE);
433 ctx.endSection();
434
435 int maxPatchVertices = 0;
436 ctx.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
437 ctx.expectError(GL_NO_ERROR);
438
439 ctx.beginSection("GL_INVALID_VALUE is generated if value is greater than GL_MAX_PATCH_VERTICES.");
440 ctx.glPatchParameteri(GL_PATCH_VERTICES, maxPatchVertices + 1);
441 ctx.expectError(GL_INVALID_VALUE);
442 ctx.endSection();
443 }
444
getNegativeTessellationTestFunctions(void)445 std::vector<FunctionContainer> getNegativeTessellationTestFunctions(void)
446 {
447 const FunctionContainer funcs[] = {
448 {single_tessellation_stage, "single_tessellation_stage",
449 "Invalid program state with single tessellation stage"},
450 {invalid_primitive_mode, "invalid_primitive_mode", "Invalid primitive mode when tessellation is active"},
451 {tessellation_not_active, "tessellation_not_active", "Use of GL_PATCHES when tessellation is not active"},
452 {invalid_program_state, "invalid_program_state",
453 "Invalid program state when tessellation active but no vertex shader present"},
454 {invalid_get_programiv, "get_programiv", "Invalid glGetProgramiv() usage"},
455 {invalid_patch_parameteri, "invalid_program_queries", "Invalid glPatchParameteri() usage"},
456 {tessellation_control_invalid_vertex_count, "tessellation_control_invalid_vertex_count",
457 "Exceed vertex count limit in tessellation control shader"},
458 };
459
460 return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
461 }
462
463 } // namespace NegativeTestShared
464 } // namespace Functional
465 } // namespace gles31
466 } // namespace deqp
467