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