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
38namespace deqp
39{
40
41using tcu::TestLog;
42using namespace glu;
43
44struct 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
54class ShaderUniformInitializeGlobalCase : public TestCase
55{
56public:
57	ShaderUniformInitializeGlobalCase(Context& context, const char* name, const char* description,
58									  GLSLVersion glslVersion)
59		: TestCase(context, name, description), m_glslVersion(glslVersion)
60	{
61	}
62
63	~ShaderUniformInitializeGlobalCase()
64	{
65		// empty
66	}
67
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
122protected:
123	GLSLVersion m_glslVersion;
124};
125
126class ShaderUniformPrecisionLinkCase : public TestCase
127{
128public:
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
139	~ShaderUniformPrecisionLinkCase()
140	{
141		// empty
142	}
143
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
212protected:
213	GLSLVersion			  m_glslVersion;
214	const ShaderVariants* m_shaderVariants;
215	unsigned int		  m_shaderVariantsCount;
216};
217
218class ShaderConstantSequenceExpressionCase : public TestCase
219{
220public:
221	ShaderConstantSequenceExpressionCase(Context& context, const char* name, const char* description,
222										 GLSLVersion glslVersion)
223		: TestCase(context, name, description), m_glslVersion(glslVersion)
224	{
225	}
226
227	~ShaderConstantSequenceExpressionCase()
228	{
229		// empty
230	}
231
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
276protected:
277	GLSLVersion m_glslVersion;
278};
279
280class ShaderNonPrecisionQualifiersStructCase : public TestCase
281{
282public:
283	ShaderNonPrecisionQualifiersStructCase(Context& context, const char* name, const char* description,
284										 GLSLVersion glslVersion)
285		: TestCase(context, name, description), m_glslVersion(glslVersion)
286	{
287	}
288
289	~ShaderNonPrecisionQualifiersStructCase()
290	{
291		// empty
292	}
293
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
396protected:
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
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
461ShaderNegativeTests::ShaderNegativeTests(Context& context, GLSLVersion glslVersion)
462	: TestCaseGroup(context, "negative", "Shader Negative tests"), m_glslVersion(glslVersion)
463{
464	// empty
465}
466
467ShaderNegativeTests::~ShaderNegativeTests()
468{
469	// empty
470}
471
472void 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