• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params[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, &params[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, &params[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, &params[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, &params[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