1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2016 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Negative Tessellation tests.
22 *//*--------------------------------------------------------------------*/
24 #include "es31fNegativeTessellationTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "glwDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "tcuStringTemplate.hpp"
41 namespace NegativeTestShared
47 static const char* vertexShaderSource = "${GLSL_VERSION_STRING}\n"
48 "${GLSL_PER_VERTEX_OUT}\n"
51 " gl_Position = vec4(0.0);\n"
54 static const char* fragmentShaderSource = "${GLSL_VERSION_STRING}\n"
55 "precision mediump float;\n"
56 "layout(location = 0) out mediump vec4 fragColor;\n"
60 " fragColor = vec4(1.0);\n"
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"
71 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
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"
82 " gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position;\n"
85 static void checkExtensionSupport (NegativeTestContext& ctx, const char* extName)
87 if (!ctx.getContextInfo().isExtensionSupported(extName))
88 throw tcu::NotSupportedError(string(extName) + " not supported");
91 static void checkTessellationSupport (NegativeTestContext& ctx)
93 if (glu::isContextTypeES(ctx.getRenderContext().getType()))
94 checkExtensionSupport(ctx, "GL_EXT_tessellation_shader");
97 // Helper for constructing tessellation pipeline sources.
98 static glu::ProgramSources makeTessPipelineSources (const std::string& vertexSrc, const std::string& fragmentSrc, const std::string& tessCtrlSrc, const std::string& tessEvalSrc)
100 glu::ProgramSources sources;
101 sources.sources[glu::SHADERTYPE_VERTEX].push_back(vertexSrc);
102 sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fragmentSrc);
104 if (!tessCtrlSrc.empty())
105 sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].push_back(tessCtrlSrc);
107 if (!tessEvalSrc.empty())
108 sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].push_back(tessEvalSrc);
113 map<string, string> constructSpecializationMap(NegativeTestContext& ctx)
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" : "";
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", "" }
128 // Incomplete active tess shaders
129 void single_tessellation_stage (NegativeTestContext& ctx)
131 // this case does not apply to GL4.5
132 if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
135 const bool requireTES = !ctx.getContextInfo().isExtensionSupported("GL_NV_gpu_shader5");
136 map<string, string> args = constructSpecializationMap(ctx);
138 checkTessellationSupport(ctx);
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();
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.");
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");
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();
170 TCU_THROW(TestError, "failed to build program");
172 ctx.glUseProgram(program.getProgram());
173 ctx.expectError(GL_NO_ERROR);
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);
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();
192 ctx.beginSection("A link error is generated if a non-separable program has a tessellation evaluation shader but no tessellation control shader.");
195 ctx.fail("Program was not expected to link");
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();
211 TCU_THROW(TestError, "failed to build program");
213 ctx.glUseProgram(program.getProgram());
214 ctx.expectError(GL_NO_ERROR);
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);
225 // Complete active tess shaders invalid primitive mode
226 void invalid_primitive_mode (NegativeTestContext& ctx)
228 checkTessellationSupport(ctx);
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();
239 ctx.glUseProgram(program.getProgram());
240 ctx.expectError(GL_NO_ERROR);
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);
250 void tessellation_not_active (NegativeTestContext& ctx)
252 checkTessellationSupport(ctx);
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();
265 if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
267 ctx.glGenVertexArrays(1, &vao);
268 ctx.glBindVertexArray(vao);
271 ctx.glUseProgram(program.getProgram());
272 ctx.expectError(GL_NO_ERROR);
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);
282 ctx.glDeleteVertexArrays(1, &vao);
285 void invalid_program_state (NegativeTestContext& ctx)
287 checkTessellationSupport(ctx);
289 const glu::RenderContext& rc = ctx.getRenderContext();
290 map<string, string> args = constructSpecializationMap(ctx);
292 // for gl4.5 we need to add per vertex sections
293 if (!glu::isContextTypeES(rc.getType()))
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";
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));
304 glu::ProgramPipeline pipeline(rc);
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);
310 tcu::TestLog& log = ctx.getLog();
311 log << fragProgram << tessCtrlProgram << tessEvalProgram;
313 if (!fragProgram.isOk() || !tessCtrlProgram.isOk() || !tessEvalProgram.isOk())
314 throw tcu::TestError("failed to build program");
316 ctx.glBindProgramPipeline(pipeline.getPipeline());
317 ctx.expectError(GL_NO_ERROR);
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);
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);
329 ctx.glBindProgramPipeline(0);
330 ctx.expectError(GL_NO_ERROR);
333 void tessellation_control_invalid_vertex_count (NegativeTestContext& ctx)
335 checkTessellationSupport(ctx);
337 const char* const tessControlVertLimitSource = "${GLSL_VERSION_STRING}\n"
338 "${GLSL_TESS_EXTENSION_STRING}\n"
339 "layout (vertices=${GL_MAX_PATCH_LIMIT}) out;\n"
342 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
345 map<string, string> args = constructSpecializationMap(ctx);
346 int maxPatchVertices= 0;
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);
352 std::ostringstream oss;
353 oss << (maxPatchVertices + 1);
354 args["GL_MAX_PATCH_LIMIT"] = oss.str();
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();
365 bool testFailed = program.getProgramInfo().linkOk;
368 ctx.fail("Program was not expected to link");
373 void invalid_get_programiv (NegativeTestContext& ctx)
375 checkTessellationSupport(ctx);
377 GLuint program = ctx.glCreateProgram();
378 GLint params[1] = { 0 };
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);
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);
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);
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);
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);
405 ctx.glDeleteProgram(program);
408 void invalid_patch_parameteri (NegativeTestContext& ctx)
410 checkTessellationSupport(ctx);
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);
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);
422 int maxPatchVertices= 0;
423 ctx.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
424 ctx.expectError(GL_NO_ERROR);
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);
432 std::vector<FunctionContainer> getNegativeTessellationTestFunctions (void)
434 const FunctionContainer funcs[] =
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" },
445 return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
448 } // NegativeTestShared