• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2015-2016 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 
24 /*!
25  * \file glcShaderNegativeTests.cpp
26  * \brief Negative tests for shaders and interface matching.
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "glcShaderNegativeTests.hpp"
30 #include "deString.h"
31 #include "deStringUtil.hpp"
32 #include "gluContextInfo.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "glw.h"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuTestLog.hpp"
37 
38 namespace deqp
39 {
40 
41 using tcu::TestLog;
42 using namespace glu;
43 
44 struct ShaderVariants
45 {
46 	GLSLVersion minimum_supported_version;
47 	const char* vertex_precision;
48 	const char* vertex_body;
49 	const char* frag_precision;
50 	const char* frag_body;
51 	bool		should_link;
52 };
53 
54 class ShaderUniformInitializeGlobalCase : public TestCase
55 {
56 public:
ShaderUniformInitializeGlobalCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)57 	ShaderUniformInitializeGlobalCase(Context& context, const char* name, const char* description,
58 									  GLSLVersion glslVersion)
59 		: TestCase(context, name, description), m_glslVersion(glslVersion)
60 	{
61 	}
62 
~ShaderUniformInitializeGlobalCase()63 	~ShaderUniformInitializeGlobalCase()
64 	{
65 		// empty
66 	}
67 
iterate()68 	IterateResult iterate()
69 	{
70 		qpTestResult result = QP_TEST_RESULT_PASS;
71 
72 		static const char vertex_source_template[] =
73 			"${VERSION_DECL}\n"
74 			"precision mediump float;\n"
75 			"uniform vec4 nonconstantexpression;\n"
76 			"vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
77 			"vec4 globalconstant1 = nonconstantexpression;\n"
78 			"\n"
79 			"void main(void) { gl_Position = globalconstant0+globalconstant1; }\n";
80 		static const char fragment_source_template[] = "${VERSION_DECL}\n"
81 													   "precision mediump float;\n"
82 													   "uniform vec4 nonconstantexpression;\n"
83 													   "vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
84 													   "vec4 globalconstant1 = nonconstantexpression;\n"
85 													   "\n"
86 													   "void main(void) { }\n";
87 
88 		std::map<std::string, std::string> args;
89 		args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
90 
91 		std::string vertex_code   = tcu::StringTemplate(vertex_source_template).specialize(args);
92 		std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
93 
94 		// Setup program.
95 		ShaderProgram program(m_context.getRenderContext(),
96 							  makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
97 
98 		// GLSL ES does not allow initialization of global variables with non-constant
99 		// expressions, but GLSL does.
100 		// Check that either compilation or linking fails for ES, and that everything
101 		// succeeds for GL.
102 		bool vertexOk   = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
103 		bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
104 		bool linkOk		= program.getProgramInfo().linkOk;
105 
106 		if (glslVersionIsES(m_glslVersion))
107 		{
108 			if (vertexOk && fragmentOk && linkOk)
109 				result = QP_TEST_RESULT_FAIL;
110 		}
111 		else
112 		{
113 			if (!vertexOk && !fragmentOk && !linkOk)
114 				result = QP_TEST_RESULT_FAIL;
115 		}
116 
117 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
118 
119 		return STOP;
120 	}
121 
122 protected:
123 	GLSLVersion m_glslVersion;
124 };
125 
126 class ShaderUniformPrecisionLinkCase : public TestCase
127 {
128 public:
ShaderUniformPrecisionLinkCase(Context & context,const char * name,const char * description,const ShaderVariants * shaderVariants,unsigned int shaderVariantsCount,GLSLVersion glslVersion)129 	ShaderUniformPrecisionLinkCase(Context& context, const char* name, const char* description,
130 								   const ShaderVariants* shaderVariants, unsigned int shaderVariantsCount,
131 								   GLSLVersion glslVersion)
132 		: TestCase(context, name, description)
133 		, m_glslVersion(glslVersion)
134 		, m_shaderVariants(shaderVariants)
135 		, m_shaderVariantsCount(shaderVariantsCount)
136 	{
137 	}
138 
~ShaderUniformPrecisionLinkCase()139 	~ShaderUniformPrecisionLinkCase()
140 	{
141 		// empty
142 	}
143 
iterate()144 	IterateResult iterate()
145 	{
146 		TestLog&	 log	= m_testCtx.getLog();
147 		qpTestResult result = QP_TEST_RESULT_PASS;
148 
149 		static const char vertex_source_template[] = "${VERSION_DECL}\n"
150 													 "uniform ${PREC_QUALIFIER} vec4 value;\n"
151 													 "\n"
152 													 "void main(void) { ${BODY} }\n";
153 
154 		static const char fragment_source_template[] = "${VERSION_DECL}\n"
155 													   "out highp vec4 result;\n"
156 													   "uniform ${PREC_QUALIFIER} vec4 value;\n"
157 													   "\n"
158 													   "void main(void) { ${BODY} }\n";
159 
160 		for (unsigned int i = 0; i < m_shaderVariantsCount; i++)
161 		{
162 			std::map<std::string, std::string> args;
163 
164 			if (m_glslVersion <= m_shaderVariants[i].minimum_supported_version)
165 			{
166 				continue;
167 			}
168 
169 			args["VERSION_DECL"]   = getGLSLVersionDeclaration(m_glslVersion);
170 			args["PREC_QUALIFIER"] = m_shaderVariants[i].vertex_precision;
171 			args["BODY"]		   = m_shaderVariants[i].vertex_body;
172 			std::string vcode	  = tcu::StringTemplate(vertex_source_template).specialize(args);
173 
174 			args["PREC_QUALIFIER"] = m_shaderVariants[i].frag_precision;
175 			args["BODY"]		   = m_shaderVariants[i].frag_body;
176 			std::string fcode	  = tcu::StringTemplate(fragment_source_template).specialize(args);
177 
178 			// Setup program.
179 			ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vcode.c_str(), fcode.c_str()));
180 
181 			// Check that compile/link results are what we expect.
182 			bool		vertexOk   = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
183 			bool		fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
184 			bool		linkOk	 = program.getProgramInfo().linkOk;
185 			const char* failReason = DE_NULL;
186 
187 			if (!vertexOk || !fragmentOk)
188 			{
189 				failReason = "expected shaders to compile, but failed.";
190 			}
191 			else if (m_shaderVariants[i].should_link && !linkOk)
192 			{
193 				failReason = "expected shaders to link, but failed.";
194 			}
195 			else if (!m_shaderVariants[i].should_link && linkOk)
196 			{
197 				failReason = "expected shaders to fail linking, but succeeded.";
198 			}
199 
200 			if (failReason != DE_NULL)
201 			{
202 				log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
203 				result = QP_TEST_RESULT_FAIL;
204 			}
205 		}
206 
207 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
208 
209 		return STOP;
210 	}
211 
212 protected:
213 	GLSLVersion			  m_glslVersion;
214 	const ShaderVariants* m_shaderVariants;
215 	unsigned int		  m_shaderVariantsCount;
216 };
217 
218 class ShaderConstantSequenceExpressionCase : public TestCase
219 {
220 public:
ShaderConstantSequenceExpressionCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)221 	ShaderConstantSequenceExpressionCase(Context& context, const char* name, const char* description,
222 										 GLSLVersion glslVersion)
223 		: TestCase(context, name, description), m_glslVersion(glslVersion)
224 	{
225 	}
226 
~ShaderConstantSequenceExpressionCase()227 	~ShaderConstantSequenceExpressionCase()
228 	{
229 		// empty
230 	}
231 
iterate()232 	IterateResult iterate()
233 	{
234 		qpTestResult result = QP_TEST_RESULT_PASS;
235 
236 		static const char vertex_source_template[] = "${VERSION_DECL}\n"
237 													 "precision mediump float;\n"
238 													 "const int test = (1, 2);\n"
239 													 "\n"
240 													 "void main(void) { gl_Position = vec4(test); }\n";
241 
242 		static const char fragment_source_template[] = "${VERSION_DECL}\n"
243 													   "precision mediump float;\n"
244 													   "\n"
245 													   "void main(void) { }\n";
246 
247 		std::map<std::string, std::string> args;
248 		args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
249 
250 		std::string vertex_code   = tcu::StringTemplate(vertex_source_template).specialize(args);
251 		std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
252 
253 		// Setup program.
254 		ShaderProgram program(m_context.getRenderContext(),
255 							  makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
256 
257 		// GLSL does not allow the sequence operator in a constant expression
258 		// Check that either compilation or linking fails
259 		bool vertexOk   = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
260 		bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
261 		bool linkOk		= program.getProgramInfo().linkOk;
262 
263 		bool run_test_es	  = (glslVersionIsES(m_glslVersion) && m_glslVersion > GLSL_VERSION_100_ES);
264 		bool run_test_desktop = (m_glslVersion > GLSL_VERSION_420);
265 		if (run_test_es || run_test_desktop)
266 		{
267 			if (vertexOk && fragmentOk && linkOk)
268 				result = QP_TEST_RESULT_FAIL;
269 		}
270 
271 		m_testCtx.setTestResult(result, qpGetTestResultName(result));
272 
273 		return STOP;
274 	}
275 
276 protected:
277 	GLSLVersion m_glslVersion;
278 };
279 
280 class ShaderNonPrecisionQualifiersStructCase : public TestCase
281 {
282 public:
ShaderNonPrecisionQualifiersStructCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)283 	ShaderNonPrecisionQualifiersStructCase(Context& context, const char* name, const char* description,
284 										 GLSLVersion glslVersion)
285 		: TestCase(context, name, description), m_glslVersion(glslVersion)
286 	{
287 	}
288 
~ShaderNonPrecisionQualifiersStructCase()289 	~ShaderNonPrecisionQualifiersStructCase()
290 	{
291 		// empty
292 	}
293 
iterate()294 	IterateResult iterate()
295 	{
296 		static const char* qualifier_values[] =
297 		{
298 			// Storage Qualifiers
299 			"const",
300 			"in",
301 			"out",
302 			"attribute",
303 			"uniform",
304 			"varying",
305 			"buffer",
306 			"shared",
307 
308 			// Interpolation Qualifiers
309 			"smooth in",
310 			"flat in",
311 			"noperspective in",
312 			"smooth out",
313 			"flat out",
314 			"noperspective out",
315 
316 			// Invariant Qualifier
317 			"invariant",
318 
319 			// Precise Qualifier
320 			"precise",
321 
322 			// Memory Qualifiers
323 			"coherent",
324 			"volatile",
325 			"restrict",
326 			"readonly",
327 			"writeonly",
328 		};
329 		static const unsigned qualifier_count = sizeof(qualifier_values) / sizeof(qualifier_values[0]);
330 
331 		static const char* layout_values[] =
332 		{
333 			"(shared)",
334 			"(packed)",
335 			"(std140)",
336 			"(std430)",
337 
338 			"(row_major)",
339 			"(column_major)",
340 		};
341 		static const unsigned layout_count = sizeof(layout_values) / sizeof(layout_values[0]);
342 
343 		const std::string layout_str = "layout";
344 
345 		std::map<std::string, std::string> args;
346 		args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
347 
348 		// Vertex and fragment shaders
349 		{
350 			// Layout qualifier test
351 			args["QUALIFIER"] = layout_str;
352 			for (unsigned i = 0; i < layout_count; ++i)
353 			{
354 				args["LAYOUT_VALUE"] = layout_values[i];
355 				if (testVertexFragment(args, layout_str + layout_values[i]))
356 					return STOP;
357 			}
358 
359 			// Remaining qualifier tests
360 			args["LAYOUT_VALUE"] = "";
361 			for (unsigned i = 0; i < qualifier_count; ++i)
362 			{
363 				args["QUALIFIER"] = qualifier_values[i];
364 				if (testVertexFragment(args, qualifier_values[i]))
365 					return STOP;
366 			}
367 		}
368 
369 		// Compute shader, not available for GLES2 and GLES3
370 		if (!glslVersionIsES(m_glslVersion) || m_glslVersion >= GLSL_VERSION_310_ES)
371 		{
372 			// Layout qualifier test
373 			args["QUALIFIER"] = layout_str;
374 			for (unsigned i = 0; i < layout_count; ++i)
375 			{
376 				args["LAYOUT_VALUE"] = layout_values[i];
377 				if (testCompute(args, layout_str + layout_values[i]))
378 					return STOP;
379 			}
380 
381 			// Remaining qualifier tests
382 			args["LAYOUT_VALUE"] = "";
383 			for (unsigned i = 0; i < qualifier_count; ++i)
384 			{
385 				args["QUALIFIER"] = qualifier_values[i];
386 				if (testCompute(args, qualifier_values[i]))
387 					return STOP;
388 			}
389 		}
390 
391 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
392 
393 		return STOP;
394 	}
395 
396 protected:
testVertexFragment(const std::map<std::string,std::string> & args,const std::string & qualifier_name)397 	bool testVertexFragment(const std::map<std::string, std::string>& args, const std::string& qualifier_name)
398 	{
399 		static const char* vertex_source_template = "${VERSION_DECL}\n"
400 													"precision mediump float;\n"
401 													"struct Base\n"
402 													"{\n"
403 													"  ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
404 													"};\n"
405 													"\n"
406 													"void main(void)\n"
407 													"{\n"
408 													"  gl_Position = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
409 													"}\n";
410 
411 		static const char* fragment_source_template = "${VERSION_DECL}\n"
412 													  "precision mediump float;\n"
413 													  "struct Base\n"
414 													  "{\n"
415 													  "  ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
416 													  "};\n"
417 													  "\n"
418 													  "void main(void) { }\n";
419 
420 		std::string vertex_code   = tcu::StringTemplate(vertex_source_template).specialize(args);
421 		std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
422 		ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
423 		if (program.getShaderInfo(SHADERTYPE_VERTEX).compileOk || program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk)
424 		{
425 			m_testCtx.getLog() << TestLog::Message << "ERROR: expected shaders not to compile, but failed with \'"
426 							   << qualifier_name << "\' qualifier." << TestLog::EndMessage;
427 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
428 			return true;
429 		}
430 		return false;
431 	}
432 
testCompute(const std::map<std::string,std::string> & args,const std::string & qualifier_name)433 	bool testCompute(const std::map<std::string, std::string>& args, const std::string& qualifier_name)
434 	{
435 		static const char* compute_source_template = "${VERSION_DECL}\n"
436 													 "precision mediump float;\n"
437 													 "struct Base\n"
438 													 "{\n"
439 													 "  ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
440 													 "};\n"
441 													 "\n"
442 													 "void main(void) { }\n";
443 
444 		std::string compute_code   = tcu::StringTemplate(compute_source_template).specialize(args);
445 		ProgramSources sources;
446 		sources.sources[SHADERTYPE_COMPUTE].emplace_back(compute_code);
447 		ShaderProgram program(m_context.getRenderContext(), sources);
448 		if (program.getShaderInfo(SHADERTYPE_COMPUTE).compileOk)
449 		{
450 			m_testCtx.getLog() << TestLog::Message << "ERROR: expected compute shader not to compile, but failed with \'"
451 							   << qualifier_name << "\' qualifier." << TestLog::EndMessage;
452 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
453 			return true;
454 		}
455 		return false;
456 	}
457 
458 	GLSLVersion m_glslVersion;
459 };
460 
ShaderNegativeTests(Context & context,GLSLVersion glslVersion)461 ShaderNegativeTests::ShaderNegativeTests(Context& context, GLSLVersion glslVersion)
462 	: TestCaseGroup(context, "negative", "Shader Negative tests"), m_glslVersion(glslVersion)
463 {
464 	// empty
465 }
466 
~ShaderNegativeTests()467 ShaderNegativeTests::~ShaderNegativeTests()
468 {
469 	// empty
470 }
471 
init(void)472 void ShaderNegativeTests::init(void)
473 {
474 	addChild(new ShaderUniformInitializeGlobalCase(
475 		m_context, "initialize", "Verify initialization of globals with non-constant expressions fails on ES.",
476 		m_glslVersion));
477 
478 	addChild(new ShaderConstantSequenceExpressionCase(
479 		m_context, "constant_sequence", "Verify that the sequence operator cannot be used as a constant expression.",
480 		m_glslVersion));
481 
482 	addChild(new ShaderNonPrecisionQualifiersStructCase(
483 		m_context, "non_precision_qualifiers_in_struct_members", "Verify non-precision qualifiers in struct members are not allowed.",
484 		m_glslVersion));
485 
486 	if (isGLSLVersionSupported(m_context.getRenderContext().getType(), GLSL_VERSION_320_ES))
487 	{
488 		static const ShaderVariants used_variables_variants[] = {
489 			/* These variants should pass since the precision qualifiers match.
490 			 * These variants require highp to be supported, so will not be run for GLSL_VERSION_100_ES.
491 			 */
492 			{ GLSL_VERSION_300_ES, "", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true },
493 			{ GLSL_VERSION_300_ES, "highp", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true },
494 
495 			/* Use highp in vertex shaders, mediump in fragment shaders. Check variations as above.
496 			 * These variants should fail since the precision qualifiers do not match, and matching is done
497 			 * based on declaration - independent of static use.
498 			 */
499 			{ GLSL_VERSION_100_ES, "", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false },
500 			{ GLSL_VERSION_100_ES, "highp", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false },
501 		};
502 		unsigned int used_variables_variants_count = sizeof(used_variables_variants) / sizeof(ShaderVariants);
503 
504 		addChild(new ShaderUniformPrecisionLinkCase(
505 			m_context, "used_uniform_precision_matching",
506 			"Verify that linking fails if precision qualifiers on default uniform do not match",
507 			used_variables_variants, used_variables_variants_count, m_glslVersion));
508 	}
509 }
510 
511 } // deqp
512