• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES Utilities
3  * ------------------------------------------------
4  *
5  * Copyright 2015 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 Shader .test file utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "gluShaderLibrary.hpp"
25 
26 #include "tcuStringTemplate.hpp"
27 #include "tcuResource.hpp"
28 #include "tcuTestLog.hpp"
29 
30 #include "deStringUtil.hpp"
31 #include "deUniquePtr.hpp"
32 #include "deFilePath.hpp"
33 
34 #include "glwEnums.hpp"
35 
36 #include <sstream>
37 #include <map>
38 #include <cstdlib>
39 
40 #if 0
41 #	define PARSE_DBG(X) printf X
42 #else
43 #	define PARSE_DBG(X) DE_NULL_STATEMENT
44 #endif
45 
46 namespace glu
47 {
48 namespace sl
49 {
50 
51 using namespace tcu;
52 
53 using std::vector;
54 using std::string;
55 using std::map;
56 using std::ostringstream;
57 using std::pair;
58 using de::UniquePtr;
59 
60 // Specification
61 
isValid(const ValueBlock & block)62 bool isValid (const ValueBlock& block)
63 {
64 	for (size_t storageNdx = 0; storageNdx < 3; ++storageNdx)
65 	{
66 		const vector<Value>&	values		= storageNdx == 0 ? block.inputs	:
67 											  storageNdx == 1 ? block.outputs	:
68 																block.uniforms;
69 		const size_t			refArrayLen	= values.empty() ? 0 : (values[0].elements.size() / (size_t)values[0].type.getScalarSize());
70 
71 		for (size_t valNdx = 0; valNdx < values.size(); ++valNdx)
72 		{
73 			const Value&	value	= values[valNdx];
74 
75 			if (!value.type.isBasicType())
76 			{
77 				print("ERROR: Value '%s' is of unsupported type!\n", value.name.c_str());
78 				return false;
79 			}
80 
81 			if (value.elements.size() != refArrayLen*(size_t)value.type.getScalarSize())
82 			{
83 				print("ERROR: Value '%s' has invalid number of scalars!\n", value.name.c_str());
84 				return false;
85 			}
86 		}
87 	}
88 
89 	return true;
90 }
91 
isValid(const ShaderCaseSpecification & spec)92 bool isValid (const ShaderCaseSpecification& spec)
93 {
94 	const deUint32	vtxFragMask			= (1u << SHADERTYPE_VERTEX)
95 										| (1u << SHADERTYPE_FRAGMENT);
96 	const deUint32	tessCtrlEvalMask	= (1u << SHADERTYPE_TESSELLATION_CONTROL)
97 										| (1u << SHADERTYPE_TESSELLATION_EVALUATION);
98 	const deUint32	supportedStageMask	= vtxFragMask | tessCtrlEvalMask
99 										| (1u << SHADERTYPE_GEOMETRY);
100 	const bool		isSeparable			= !spec.programs.empty() && spec.programs[0].sources.separable;
101 
102 	if (spec.programs.empty())
103 	{
104 		print("ERROR: No programs specified!\n");
105 		return false;
106 	}
107 
108 	if (spec.fullGLSLES100Required)
109 	{
110 		if (spec.targetVersion != GLSL_VERSION_100_ES)
111 		{
112 			print("ERROR: Full GLSL ES 1.00 support requested for other GLSL version!\n");
113 			return false;
114 		}
115 
116 		if (spec.expectResult != EXPECT_PASS			&&
117 			spec.expectResult != EXPECT_VALIDATION_FAIL	&&
118 			spec.expectResult != EXPECT_BUILD_SUCCESSFUL)
119 		{
120 			print("ERROR: Full GLSL ES 1.00 support doesn't make sense when expecting compile/link failure!\n");
121 			return false;
122 		}
123 	}
124 
125 	if (!de::inBounds(spec.caseType, (CaseType)0, CASETYPE_LAST))
126 	{
127 		print("ERROR: Invalid case type!\n");
128 		return false;
129 	}
130 
131 	if (!de::inBounds(spec.expectResult, (ExpectResult)0, EXPECT_LAST))
132 	{
133 		print("ERROR: Invalid expected result!\n");
134 		return false;
135 	}
136 
137 	if (!isValid(spec.values))
138 		return false;
139 
140 	if (!spec.values.inputs.empty() && !spec.values.outputs.empty() &&
141 		spec.values.inputs[0].elements.size() / spec.values.inputs[0].type.getScalarSize() != spec.values.outputs[0].elements.size() / spec.values.outputs[0].type.getScalarSize())
142 	{
143 		print("ERROR: Number of input and output elements don't match!\n");
144 		return false;
145 	}
146 
147 	if (isSeparable)
148 	{
149 		deUint32	usedStageMask	= 0u;
150 
151 		if (spec.caseType != CASETYPE_COMPLETE)
152 		{
153 			print("ERROR: Separable shaders supported only for complete cases!\n");
154 			return false;
155 		}
156 
157 		for (size_t progNdx = 0; progNdx < spec.programs.size(); ++progNdx)
158 		{
159 			for (int shaderStageNdx = 0; shaderStageNdx < SHADERTYPE_LAST; ++shaderStageNdx)
160 			{
161 				const deUint32	curStageMask	= (1u << shaderStageNdx);
162 
163 				if (supportedStageMask & curStageMask)
164 				{
165 					const bool		hasShader	= !spec.programs[progNdx].sources.sources[shaderStageNdx].empty();
166 					const bool		isEnabled	= (spec.programs[progNdx].activeStages & curStageMask) != 0;
167 
168 					if (hasShader != isEnabled)
169 					{
170 						print("ERROR: Inconsistent source/enable for shader stage %s!\n", getShaderTypeName((ShaderType)shaderStageNdx));
171 						return false;
172 					}
173 
174 					if (hasShader && (usedStageMask & curStageMask) != 0)
175 					{
176 						print("ERROR: Stage %s enabled on multiple programs!\n", getShaderTypeName((ShaderType)shaderStageNdx));
177 						return false;
178 					}
179 
180 					if (isEnabled)
181 						usedStageMask |= curStageMask;
182 				}
183 				else if (!spec.programs[progNdx].sources.sources[shaderStageNdx].empty())
184 				{
185 					print("ERROR: Source specified for unsupported shader stage %s!\n", getShaderTypeName((ShaderType)shaderStageNdx));
186 					return false;
187 				}
188 			}
189 		}
190 
191 		if ((usedStageMask & vtxFragMask) != vtxFragMask)
192 		{
193 			print("ERROR: Vertex and fragment shaders are mandatory!\n");
194 			return false;
195 		}
196 
197 		if ((usedStageMask & tessCtrlEvalMask) != 0 && (usedStageMask & tessCtrlEvalMask) != tessCtrlEvalMask)
198 		{
199 			print("ERROR: Both tessellation control and eval shaders must be either enabled or disabled!\n");
200 			return false;
201 		}
202 	}
203 	else
204 	{
205 		const bool	hasVertex		= !spec.programs[0].sources.sources[SHADERTYPE_VERTEX].empty();
206 		const bool	hasFragment		= !spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].empty();
207 
208 		if (spec.programs.size() != 1)
209 		{
210 			print("ERROR: Only cases using separable programs can have multiple programs!\n");
211 			return false;
212 		}
213 
214 		if (spec.caseType == CASETYPE_VERTEX_ONLY && (!hasVertex || hasFragment))
215 		{
216 			print("ERROR: Vertex-only case must have only vertex shader!\n");
217 			return false;
218 		}
219 
220 		if (spec.caseType == CASETYPE_FRAGMENT_ONLY && (hasVertex || !hasFragment))
221 		{
222 			print("ERROR: Fragment-only case must have only fragment shader!\n");
223 			return false;
224 		}
225 
226 		if (spec.caseType == CASETYPE_COMPLETE && (!hasVertex || !hasFragment))
227 		{
228 			print("ERROR: Complete case must have at least vertex and fragment shaders\n");
229 			return false;
230 		}
231 	}
232 
233 	return true;
234 }
235 
236 // Parser
237 
238 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES;
239 
isWhitespace(char c)240 DE_INLINE deBool isWhitespace (char c)
241 {
242 	return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
243 }
244 
isEOL(char c)245 DE_INLINE deBool isEOL (char c)
246 {
247 	return (c == '\r') || (c == '\n');
248 }
249 
isNumeric(char c)250 DE_INLINE deBool isNumeric (char c)
251 {
252 	return deInRange32(c, '0', '9');
253 }
254 
isAlpha(char c)255 DE_INLINE deBool isAlpha (char c)
256 {
257 	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
258 }
259 
isCaseNameChar(char c)260 DE_INLINE deBool isCaseNameChar (char c)
261 {
262 	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') || (c == '-') || (c == '.');
263 }
264 
265 struct CaseRequirement
266 {
267 	enum Type
268 	{
269 		TYPE_EXTENSION = 0,
270 		TYPE_FULL_GLSL_ES_100_SUPPORT,
271 		TYPE_IMPLEMENTATION_LIMIT,
272 
273 		TYPE_LAST
274 	};
275 
276 	Type					type;
277 
278 	// TYPE_EXTENSION:
279 	RequiredExtension		extension;
280 
281 	// TYPE_IMPLEMENTATION_LIMIT
282 	RequiredCapability		requiredCap;
283 
CaseRequirementglu::sl::CaseRequirement284 	CaseRequirement (void) : type(TYPE_LAST) {}
285 
createFullGLSLES100SpecificationRequirementglu::sl::CaseRequirement286 	static CaseRequirement createFullGLSLES100SpecificationRequirement (void)
287 	{
288 		CaseRequirement req;
289 		req.type		= TYPE_FULL_GLSL_ES_100_SUPPORT;
290 		return req;
291 	}
292 
createAnyExtensionRequirementglu::sl::CaseRequirement293 	static CaseRequirement createAnyExtensionRequirement (const vector<string>& alternatives, deUint32 effectiveStages)
294 	{
295 		CaseRequirement req;
296 		req.type		= TYPE_EXTENSION;
297 		req.extension	= RequiredExtension(alternatives, effectiveStages);
298 		return req;
299 	}
300 
createLimitRequirementglu::sl::CaseRequirement301 	static CaseRequirement createLimitRequirement (deUint32 enumName, int referenceValue)
302 	{
303 		CaseRequirement req;
304 		req.type		= TYPE_IMPLEMENTATION_LIMIT;
305 		req.requiredCap	= RequiredCapability(enumName, referenceValue);
306 		return req;
307 	}
308 };
309 
310 class ShaderParser
311 {
312 public:
313 							ShaderParser			(const tcu::Archive& archive, const std::string& filename, ShaderCaseFactory* caseFactory);
314 							~ShaderParser			(void);
315 
316 	vector<tcu::TestNode*>	parse					(void);
317 
318 private:
319 	enum Token
320 	{
321 		TOKEN_INVALID = 0,
322 		TOKEN_EOF,
323 		TOKEN_STRING,
324 		TOKEN_SHADER_SOURCE,
325 
326 		TOKEN_INT_LITERAL,
327 		TOKEN_FLOAT_LITERAL,
328 
329 		// identifiers
330 		TOKEN_IDENTIFIER,
331 		TOKEN_TRUE,
332 		TOKEN_FALSE,
333 		TOKEN_DESC,
334 		TOKEN_EXPECT,
335 		TOKEN_GROUP,
336 		TOKEN_CASE,
337 		TOKEN_END,
338 		TOKEN_VALUES,
339 		TOKEN_BOTH,
340 		TOKEN_VERTEX,
341 		TOKEN_FRAGMENT,
342 		TOKEN_UNIFORM,
343 		TOKEN_INPUT,
344 		TOKEN_OUTPUT,
345 		TOKEN_FLOAT,
346 		TOKEN_FLOAT_VEC2,
347 		TOKEN_FLOAT_VEC3,
348 		TOKEN_FLOAT_VEC4,
349 		TOKEN_FLOAT_MAT2,
350 		TOKEN_FLOAT_MAT2X3,
351 		TOKEN_FLOAT_MAT2X4,
352 		TOKEN_FLOAT_MAT3X2,
353 		TOKEN_FLOAT_MAT3,
354 		TOKEN_FLOAT_MAT3X4,
355 		TOKEN_FLOAT_MAT4X2,
356 		TOKEN_FLOAT_MAT4X3,
357 		TOKEN_FLOAT_MAT4,
358 		TOKEN_INT,
359 		TOKEN_INT_VEC2,
360 		TOKEN_INT_VEC3,
361 		TOKEN_INT_VEC4,
362 		TOKEN_UINT,
363 		TOKEN_UINT_VEC2,
364 		TOKEN_UINT_VEC3,
365 		TOKEN_UINT_VEC4,
366 		TOKEN_BOOL,
367 		TOKEN_BOOL_VEC2,
368 		TOKEN_BOOL_VEC3,
369 		TOKEN_BOOL_VEC4,
370 		TOKEN_VERSION,
371 		TOKEN_TESSELLATION_CONTROL,
372 		TOKEN_TESSELLATION_EVALUATION,
373 		TOKEN_GEOMETRY,
374 		TOKEN_REQUIRE,
375 		TOKEN_IN,
376 		TOKEN_IMPORT,
377 		TOKEN_PIPELINE_PROGRAM,
378 		TOKEN_ACTIVE_STAGES,
379 
380 		// symbols
381 		TOKEN_ASSIGN,
382 		TOKEN_PLUS,
383 		TOKEN_MINUS,
384 		TOKEN_COMMA,
385 		TOKEN_VERTICAL_BAR,
386 		TOKEN_SEMI_COLON,
387 		TOKEN_LEFT_PAREN,
388 		TOKEN_RIGHT_PAREN,
389 		TOKEN_LEFT_BRACKET,
390 		TOKEN_RIGHT_BRACKET,
391 		TOKEN_LEFT_BRACE,
392 		TOKEN_RIGHT_BRACE,
393 		TOKEN_GREATER,
394 
395 		TOKEN_LAST
396 	};
397 
398 	void						parseError					(const std::string& errorStr);
399 	float						parseFloatLiteral			(const char* str);
400 	int							parseIntLiteral				(const char* str);
401 	string						parseStringLiteral			(const char* str);
402 	string						parseShaderSource			(const char* str);
403 	void						advanceToken				(void);
404 	void						advanceToken				(Token assumed);
405 	void						assumeToken					(Token token);
406 	DataType					mapDataTypeToken			(Token token);
407 	const char*					getTokenName				(Token token);
408 	deUint32					getShaderStageLiteralFlag	(void);
409 	deUint32					getGLEnumFromName			(const std::string& enumName);
410 
411 	void						parseValueElement			(DataType dataType, Value& result);
412 	void						parseValue					(ValueBlock& valueBlock);
413 	void						parseValueBlock				(ValueBlock& valueBlock);
414 	deUint32					parseShaderStageList		(void);
415 	void						parseRequirement			(CaseRequirement& valueBlock);
416 	void						parseExpectResult			(ExpectResult& expectResult);
417 	void						parseGLSLVersion			(glu::GLSLVersion& version);
418 	void						parsePipelineProgram		(ProgramSpecification& program);
419 	void						parseShaderCase				(vector<tcu::TestNode*>& shaderNodeList);
420 	void						parseShaderGroup			(vector<tcu::TestNode*>& shaderNodeList);
421 	void						parseImport					(vector<tcu::TestNode*>& shaderNodeList);
422 
423 	const tcu::Archive&			m_archive;
424 	const string				m_filename;
425 	ShaderCaseFactory* const	m_caseFactory;
426 
427 	UniquePtr<tcu::Resource>	m_resource;
428 	vector<char>				m_input;
429 
430 	const char*					m_curPtr;
431 	Token						m_curToken;
432 	std::string					m_curTokenStr;
433 };
434 
ShaderParser(const tcu::Archive & archive,const string & filename,ShaderCaseFactory * caseFactroy)435 ShaderParser::ShaderParser (const tcu::Archive& archive, const string& filename, ShaderCaseFactory* caseFactroy)
436 	: m_archive			(archive)
437 	, m_filename		(filename)
438 	, m_caseFactory		(caseFactroy)
439 	, m_resource		(archive.getResource(m_filename.c_str()))
440 	, m_curPtr			(DE_NULL)
441 	, m_curToken		(TOKEN_LAST)
442 {
443 }
444 
~ShaderParser(void)445 ShaderParser::~ShaderParser (void)
446 {
447 }
448 
parseError(const std::string & errorStr)449 void ShaderParser::parseError (const std::string& errorStr)
450 {
451 	string atStr = string(m_curPtr, 80);
452 	throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), DE_NULL, __FILE__, __LINE__);
453 }
454 
parseFloatLiteral(const char * str)455 float ShaderParser::parseFloatLiteral (const char* str)
456 {
457 	return (float)atof(str);
458 }
459 
parseIntLiteral(const char * str)460 int ShaderParser::parseIntLiteral (const char* str)
461 {
462 	return atoi(str);
463 }
464 
parseStringLiteral(const char * str)465 string ShaderParser::parseStringLiteral (const char* str)
466 {
467 	const char*		p		= str;
468 	char			endChar = *p++;
469 	ostringstream	o;
470 
471 	while (*p != endChar && *p)
472 	{
473 		if (*p == '\\')
474 		{
475 			switch (p[1])
476 			{
477 				case 0:		DE_ASSERT(DE_FALSE);	break;
478 				case 'n':	o << '\n';				break;
479 				case 't':	o << '\t';				break;
480 				default:	o << p[1];				break;
481 			}
482 
483 			p += 2;
484 		}
485 		else
486 			o << *p++;
487 	}
488 
489 	return o.str();
490 }
491 
removeExtraIndentation(const string & source)492 static string removeExtraIndentation (const string& source)
493 {
494 	// Detect indentation from first line.
495 	int numIndentChars = 0;
496 	for (int ndx = 0; ndx < (int)source.length() && isWhitespace(source[ndx]); ndx++)
497 		numIndentChars += source[ndx] == '\t' ? 4 : 1;
498 
499 	// Process all lines and remove preceding indentation.
500 	ostringstream processed;
501 	{
502 		bool	atLineStart			= true;
503 		int		indentCharsOmitted	= 0;
504 
505 		for (int pos = 0; pos < (int)source.length(); pos++)
506 		{
507 			char c = source[pos];
508 
509 			if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t'))
510 			{
511 				indentCharsOmitted += c == '\t' ? 4 : 1;
512 			}
513 			else if (isEOL(c))
514 			{
515 				if (source[pos] == '\r' && source[pos+1] == '\n')
516 				{
517 					pos += 1;
518 					processed << '\n';
519 				}
520 				else
521 					processed << c;
522 
523 				atLineStart			= true;
524 				indentCharsOmitted	= 0;
525 			}
526 			else
527 			{
528 				processed << c;
529 				atLineStart = false;
530 			}
531 		}
532 	}
533 
534 	return processed.str();
535 }
536 
parseShaderSource(const char * str)537 string ShaderParser::parseShaderSource (const char* str)
538 {
539 	const char*		p = str+2;
540 	ostringstream	o;
541 
542 	// Eat first empty line from beginning.
543 	while (*p == ' ') p++;
544 	if (*p == '\r') p++;
545 	if (*p == '\n') p++;
546 
547 	while ((p[0] != '"') || (p[1] != '"'))
548 	{
549 		if (*p == '\\')
550 		{
551 			switch (p[1])
552 			{
553 				case 0:		DE_ASSERT(DE_FALSE);	break;
554 				case 'n':	o << '\n';				break;
555 				case 't':	o << '\t';				break;
556 				default:	o << p[1];				break;
557 			}
558 
559 			p += 2;
560 		}
561 		else
562 			o << *p++;
563 	}
564 
565 	return removeExtraIndentation(o.str());
566 }
567 
advanceToken(void)568 void ShaderParser::advanceToken (void)
569 {
570 	// Skip old token.
571 	m_curPtr += m_curTokenStr.length();
572 
573 	// Reset token (for safety).
574 	m_curToken		= TOKEN_INVALID;
575 	m_curTokenStr	= "";
576 
577 	// Eat whitespace & comments while they last.
578 	for (;;)
579 	{
580 		while (isWhitespace(*m_curPtr))
581 			m_curPtr++;
582 
583 		// Check for EOL comment.
584 		if (*m_curPtr == '#')
585 		{
586 			while (*m_curPtr && !isEOL(*m_curPtr))
587 				m_curPtr++;
588 		}
589 		else
590 			break;
591 	}
592 
593 	if (!*m_curPtr)
594 	{
595 		m_curToken = TOKEN_EOF;
596 		m_curTokenStr = "<EOF>";
597 	}
598 	else if (isAlpha(*m_curPtr))
599 	{
600 		struct Named
601 		{
602 			const char*		str;
603 			Token			token;
604 		};
605 
606 		static const Named s_named[] =
607 		{
608 			{ "true",						TOKEN_TRUE						},
609 			{ "false",						TOKEN_FALSE						},
610 			{ "desc",						TOKEN_DESC						},
611 			{ "expect",						TOKEN_EXPECT					},
612 			{ "group",						TOKEN_GROUP						},
613 			{ "case",						TOKEN_CASE						},
614 			{ "end",						TOKEN_END						},
615 			{ "values",						TOKEN_VALUES					},
616 			{ "both",						TOKEN_BOTH						},
617 			{ "vertex",						TOKEN_VERTEX					},
618 			{ "fragment",					TOKEN_FRAGMENT					},
619 			{ "uniform",					TOKEN_UNIFORM					},
620 			{ "input",						TOKEN_INPUT						},
621 			{ "output",						TOKEN_OUTPUT					},
622 			{ "float",						TOKEN_FLOAT						},
623 			{ "vec2",						TOKEN_FLOAT_VEC2				},
624 			{ "vec3",						TOKEN_FLOAT_VEC3				},
625 			{ "vec4",						TOKEN_FLOAT_VEC4				},
626 			{ "mat2",						TOKEN_FLOAT_MAT2				},
627 			{ "mat2x3",						TOKEN_FLOAT_MAT2X3				},
628 			{ "mat2x4",						TOKEN_FLOAT_MAT2X4				},
629 			{ "mat3x2",						TOKEN_FLOAT_MAT3X2				},
630 			{ "mat3",						TOKEN_FLOAT_MAT3				},
631 			{ "mat3x4",						TOKEN_FLOAT_MAT3X4				},
632 			{ "mat4x2",						TOKEN_FLOAT_MAT4X2				},
633 			{ "mat4x3",						TOKEN_FLOAT_MAT4X3				},
634 			{ "mat4",						TOKEN_FLOAT_MAT4				},
635 			{ "int",						TOKEN_INT						},
636 			{ "ivec2",						TOKEN_INT_VEC2					},
637 			{ "ivec3",						TOKEN_INT_VEC3					},
638 			{ "ivec4",						TOKEN_INT_VEC4					},
639 			{ "uint",						TOKEN_UINT						},
640 			{ "uvec2",						TOKEN_UINT_VEC2					},
641 			{ "uvec3",						TOKEN_UINT_VEC3					},
642 			{ "uvec4",						TOKEN_UINT_VEC4					},
643 			{ "bool",						TOKEN_BOOL						},
644 			{ "bvec2",						TOKEN_BOOL_VEC2					},
645 			{ "bvec3",						TOKEN_BOOL_VEC3					},
646 			{ "bvec4",						TOKEN_BOOL_VEC4					},
647 			{ "version",					TOKEN_VERSION					},
648 			{ "tessellation_control",		TOKEN_TESSELLATION_CONTROL		},
649 			{ "tessellation_evaluation",	TOKEN_TESSELLATION_EVALUATION	},
650 			{ "geometry",					TOKEN_GEOMETRY					},
651 			{ "require",					TOKEN_REQUIRE					},
652 			{ "in",							TOKEN_IN						},
653 			{ "import",						TOKEN_IMPORT					},
654 			{ "pipeline_program",			TOKEN_PIPELINE_PROGRAM			},
655 			{ "active_stages",				TOKEN_ACTIVE_STAGES				},
656 		};
657 
658 		const char* end = m_curPtr + 1;
659 		while (isCaseNameChar(*end))
660 			end++;
661 		m_curTokenStr = string(m_curPtr, end - m_curPtr);
662 
663 		m_curToken = TOKEN_IDENTIFIER;
664 
665 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++)
666 		{
667 			if (m_curTokenStr == s_named[ndx].str)
668 			{
669 				m_curToken = s_named[ndx].token;
670 				break;
671 			}
672 		}
673 	}
674 	else if (isNumeric(*m_curPtr))
675 	{
676 		/* \todo [2010-03-31 petri] Hex? */
677 		const char* p = m_curPtr;
678 		while (isNumeric(*p))
679 			p++;
680 		if (*p == '.')
681 		{
682 			p++;
683 			while (isNumeric(*p))
684 				p++;
685 
686 			if (*p == 'e' || *p == 'E')
687 			{
688 				p++;
689 				if (*p == '+' || *p == '-')
690 					p++;
691 				DE_ASSERT(isNumeric(*p));
692 				while (isNumeric(*p))
693 					p++;
694 			}
695 
696 			m_curToken = TOKEN_FLOAT_LITERAL;
697 			m_curTokenStr = string(m_curPtr, p - m_curPtr);
698 		}
699 		else
700 		{
701 			m_curToken = TOKEN_INT_LITERAL;
702 			m_curTokenStr = string(m_curPtr, p - m_curPtr);
703 		}
704 	}
705 	else if (*m_curPtr == '"' && m_curPtr[1] == '"')
706 	{
707 		const char*	p = m_curPtr + 2;
708 
709 		while ((p[0] != '"') || (p[1] != '"'))
710 		{
711 			DE_ASSERT(*p);
712 			if (*p == '\\')
713 			{
714 				DE_ASSERT(p[1] != 0);
715 				p += 2;
716 			}
717 			else
718 				p++;
719 		}
720 		p += 2;
721 
722 		m_curToken		= TOKEN_SHADER_SOURCE;
723 		m_curTokenStr	= string(m_curPtr, (int)(p - m_curPtr));
724 	}
725 	else if (*m_curPtr == '"' || *m_curPtr == '\'')
726 	{
727 		char		endChar = *m_curPtr;
728 		const char*	p		= m_curPtr + 1;
729 
730 		while (*p != endChar)
731 		{
732 			DE_ASSERT(*p);
733 			if (*p == '\\')
734 			{
735 				DE_ASSERT(p[1] != 0);
736 				p += 2;
737 			}
738 			else
739 				p++;
740 		}
741 		p++;
742 
743 		m_curToken		= TOKEN_STRING;
744 		m_curTokenStr	= string(m_curPtr, (int)(p - m_curPtr));
745 	}
746 	else
747 	{
748 		struct SimpleToken
749 		{
750 			const char*		str;
751 			Token			token;
752 		};
753 
754 		static const SimpleToken s_simple[] =
755 		{
756 			{ "=",			TOKEN_ASSIGN		},
757 			{ "+",			TOKEN_PLUS			},
758 			{ "-",			TOKEN_MINUS			},
759 			{ ",",			TOKEN_COMMA			},
760 			{ "|",			TOKEN_VERTICAL_BAR	},
761 			{ ";",			TOKEN_SEMI_COLON	},
762 			{ "(",			TOKEN_LEFT_PAREN	},
763 			{ ")",			TOKEN_RIGHT_PAREN	},
764 			{ "[",			TOKEN_LEFT_BRACKET	},
765 			{ "]",			TOKEN_RIGHT_BRACKET },
766 			{ "{",			TOKEN_LEFT_BRACE	},
767 			{ "}",			TOKEN_RIGHT_BRACE	},
768 			{ ">",			TOKEN_GREATER		},
769 		};
770 
771 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++)
772 		{
773 			if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0)
774 			{
775 				m_curToken		= s_simple[ndx].token;
776 				m_curTokenStr	= s_simple[ndx].str;
777 				return;
778 			}
779 		}
780 
781 		// Otherwise invalid token.
782 		m_curToken = TOKEN_INVALID;
783 		m_curTokenStr = *m_curPtr;
784 	}
785 }
786 
advanceToken(Token assumed)787 void ShaderParser::advanceToken (Token assumed)
788 {
789 	assumeToken(assumed);
790 	advanceToken();
791 }
792 
assumeToken(Token token)793 void ShaderParser::assumeToken (Token token)
794 {
795 	if (m_curToken != token)
796 		parseError((string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str());
797 	DE_TEST_ASSERT(m_curToken == token);
798 }
799 
mapDataTypeToken(Token token)800 DataType ShaderParser::mapDataTypeToken (Token token)
801 {
802 	switch (token)
803 	{
804 		case TOKEN_FLOAT:			return TYPE_FLOAT;
805 		case TOKEN_FLOAT_VEC2:		return TYPE_FLOAT_VEC2;
806 		case TOKEN_FLOAT_VEC3:		return TYPE_FLOAT_VEC3;
807 		case TOKEN_FLOAT_VEC4:		return TYPE_FLOAT_VEC4;
808 		case TOKEN_FLOAT_MAT2:		return TYPE_FLOAT_MAT2;
809 		case TOKEN_FLOAT_MAT2X3:	return TYPE_FLOAT_MAT2X3;
810 		case TOKEN_FLOAT_MAT2X4:	return TYPE_FLOAT_MAT2X4;
811 		case TOKEN_FLOAT_MAT3X2:	return TYPE_FLOAT_MAT3X2;
812 		case TOKEN_FLOAT_MAT3:		return TYPE_FLOAT_MAT3;
813 		case TOKEN_FLOAT_MAT3X4:	return TYPE_FLOAT_MAT3X4;
814 		case TOKEN_FLOAT_MAT4X2:	return TYPE_FLOAT_MAT4X2;
815 		case TOKEN_FLOAT_MAT4X3:	return TYPE_FLOAT_MAT4X3;
816 		case TOKEN_FLOAT_MAT4:		return TYPE_FLOAT_MAT4;
817 		case TOKEN_INT:				return TYPE_INT;
818 		case TOKEN_INT_VEC2:		return TYPE_INT_VEC2;
819 		case TOKEN_INT_VEC3:		return TYPE_INT_VEC3;
820 		case TOKEN_INT_VEC4:		return TYPE_INT_VEC4;
821 		case TOKEN_UINT:			return TYPE_UINT;
822 		case TOKEN_UINT_VEC2:		return TYPE_UINT_VEC2;
823 		case TOKEN_UINT_VEC3:		return TYPE_UINT_VEC3;
824 		case TOKEN_UINT_VEC4:		return TYPE_UINT_VEC4;
825 		case TOKEN_BOOL:			return TYPE_BOOL;
826 		case TOKEN_BOOL_VEC2:		return TYPE_BOOL_VEC2;
827 		case TOKEN_BOOL_VEC3:		return TYPE_BOOL_VEC3;
828 		case TOKEN_BOOL_VEC4:		return TYPE_BOOL_VEC4;
829 		default:					return TYPE_INVALID;
830 	}
831 }
832 
getTokenName(Token token)833 const char* ShaderParser::getTokenName (Token token)
834 {
835 	switch (token)
836 	{
837 		case TOKEN_INVALID:					return "<invalid>";
838 		case TOKEN_EOF:						return "<eof>";
839 		case TOKEN_STRING:					return "<string>";
840 		case TOKEN_SHADER_SOURCE:			return "source";
841 
842 		case TOKEN_INT_LITERAL:				return "<int>";
843 		case TOKEN_FLOAT_LITERAL:			return "<float>";
844 
845 		// identifiers
846 		case TOKEN_IDENTIFIER:				return "<identifier>";
847 		case TOKEN_TRUE:					return "true";
848 		case TOKEN_FALSE:					return "false";
849 		case TOKEN_DESC:					return "desc";
850 		case TOKEN_EXPECT:					return "expect";
851 		case TOKEN_GROUP:					return "group";
852 		case TOKEN_CASE:					return "case";
853 		case TOKEN_END:						return "end";
854 		case TOKEN_VALUES:					return "values";
855 		case TOKEN_BOTH:					return "both";
856 		case TOKEN_VERTEX:					return "vertex";
857 		case TOKEN_FRAGMENT:				return "fragment";
858 		case TOKEN_TESSELLATION_CONTROL:	return "tessellation_control";
859 		case TOKEN_TESSELLATION_EVALUATION:	return "tessellation_evaluation";
860 		case TOKEN_GEOMETRY:				return "geometry";
861 		case TOKEN_REQUIRE:					return "require";
862 		case TOKEN_UNIFORM:					return "uniform";
863 		case TOKEN_INPUT:					return "input";
864 		case TOKEN_OUTPUT:					return "output";
865 		case TOKEN_FLOAT:					return "float";
866 		case TOKEN_FLOAT_VEC2:				return "vec2";
867 		case TOKEN_FLOAT_VEC3:				return "vec3";
868 		case TOKEN_FLOAT_VEC4:				return "vec4";
869 		case TOKEN_FLOAT_MAT2:				return "mat2";
870 		case TOKEN_FLOAT_MAT2X3:			return "mat2x3";
871 		case TOKEN_FLOAT_MAT2X4:			return "mat2x4";
872 		case TOKEN_FLOAT_MAT3X2:			return "mat3x2";
873 		case TOKEN_FLOAT_MAT3:				return "mat3";
874 		case TOKEN_FLOAT_MAT3X4:			return "mat3x4";
875 		case TOKEN_FLOAT_MAT4X2:			return "mat4x2";
876 		case TOKEN_FLOAT_MAT4X3:			return "mat4x3";
877 		case TOKEN_FLOAT_MAT4:				return "mat4";
878 		case TOKEN_INT:						return "int";
879 		case TOKEN_INT_VEC2:				return "ivec2";
880 		case TOKEN_INT_VEC3:				return "ivec3";
881 		case TOKEN_INT_VEC4:				return "ivec4";
882 		case TOKEN_UINT:					return "uint";
883 		case TOKEN_UINT_VEC2:				return "uvec2";
884 		case TOKEN_UINT_VEC3:				return "uvec3";
885 		case TOKEN_UINT_VEC4:				return "uvec4";
886 		case TOKEN_BOOL:					return "bool";
887 		case TOKEN_BOOL_VEC2:				return "bvec2";
888 		case TOKEN_BOOL_VEC3:				return "bvec3";
889 		case TOKEN_BOOL_VEC4:				return "bvec4";
890 		case TOKEN_IN:						return "in";
891 		case TOKEN_IMPORT:					return "import";
892 		case TOKEN_PIPELINE_PROGRAM:		return "pipeline_program";
893 		case TOKEN_ACTIVE_STAGES:			return "active_stages";
894 
895 		case TOKEN_ASSIGN:					return "=";
896 		case TOKEN_PLUS:					return "+";
897 		case TOKEN_MINUS:					return "-";
898 		case TOKEN_COMMA:					return ",";
899 		case TOKEN_VERTICAL_BAR:			return "|";
900 		case TOKEN_SEMI_COLON:				return ";";
901 		case TOKEN_LEFT_PAREN:				return "(";
902 		case TOKEN_RIGHT_PAREN:				return ")";
903 		case TOKEN_LEFT_BRACKET:			return "[";
904 		case TOKEN_RIGHT_BRACKET:			return "]";
905 		case TOKEN_LEFT_BRACE:				return "{";
906 		case TOKEN_RIGHT_BRACE:				return "}";
907 		case TOKEN_GREATER:					return ">";
908 
909 		default:							return "<unknown>";
910 	}
911 }
912 
getShaderStageLiteralFlag(void)913 deUint32 ShaderParser::getShaderStageLiteralFlag (void)
914 {
915 	switch (m_curToken)
916 	{
917 		case TOKEN_VERTEX:					return (1 << glu::SHADERTYPE_VERTEX);
918 		case TOKEN_FRAGMENT:				return (1 << glu::SHADERTYPE_FRAGMENT);
919 		case TOKEN_GEOMETRY:				return (1 << glu::SHADERTYPE_GEOMETRY);
920 		case TOKEN_TESSELLATION_CONTROL:	return (1 << glu::SHADERTYPE_TESSELLATION_CONTROL);
921 		case TOKEN_TESSELLATION_EVALUATION:	return (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
922 
923 		default:
924 			parseError(std::string() + "invalid shader stage name, got " + m_curTokenStr);
925 			return 0;
926 	}
927 }
928 
getGLEnumFromName(const std::string & enumName)929 deUint32 ShaderParser::getGLEnumFromName (const std::string& enumName)
930 {
931 	static const struct
932 	{
933 		const char*	name;
934 		deUint32	value;
935 	} names[] =
936 	{
937 		{ "GL_MAX_VERTEX_IMAGE_UNIFORMS",			GL_MAX_VERTEX_IMAGE_UNIFORMS			},
938 		{ "GL_MAX_VERTEX_ATOMIC_COUNTERS",			GL_MAX_VERTEX_ATOMIC_COUNTERS			},
939 		{ "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS",	GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS		},
940 		{ "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS",	GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS	},
941 	};
942 
943 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(names); ++ndx)
944 		if (names[ndx].name == enumName)
945 			return names[ndx].value;
946 
947 	parseError(std::string() + "unknown enum name, got " + enumName);
948 	return 0;
949 }
950 
parseValueElement(DataType expectedDataType,Value & result)951 void ShaderParser::parseValueElement (DataType expectedDataType, Value& result)
952 {
953 	DataType	scalarType	= getDataTypeScalarType(expectedDataType);
954 	int			scalarSize	= getDataTypeScalarSize(expectedDataType);
955 
956 	/* \todo [2010-04-19 petri] Support arrays. */
957 	Value::Element elems[16];
958 
959 	if (scalarSize > 1)
960 	{
961 		DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType);
962 		advanceToken(); // data type (float, vec2, etc.)
963 		advanceToken(TOKEN_LEFT_PAREN);
964 	}
965 
966 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
967 	{
968 		if (scalarType == TYPE_FLOAT)
969 		{
970 			float signMult = 1.0f;
971 			if (m_curToken == TOKEN_MINUS)
972 			{
973 				signMult = -1.0f;
974 				advanceToken();
975 			}
976 
977 			assumeToken(TOKEN_FLOAT_LITERAL);
978 			elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str());
979 			advanceToken(TOKEN_FLOAT_LITERAL);
980 		}
981 		else if (scalarType == TYPE_INT || scalarType == TYPE_UINT)
982 		{
983 			int signMult = 1;
984 			if (m_curToken == TOKEN_MINUS)
985 			{
986 				signMult = -1;
987 				advanceToken();
988 			}
989 
990 			assumeToken(TOKEN_INT_LITERAL);
991 			elems[scalarNdx].int32 = signMult * parseIntLiteral(m_curTokenStr.c_str());
992 			advanceToken(TOKEN_INT_LITERAL);
993 		}
994 		else
995 		{
996 			DE_ASSERT(scalarType == TYPE_BOOL);
997 			elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE);
998 			if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE)
999 				parseError(string("unexpected token, expecting bool: " + m_curTokenStr));
1000 			advanceToken(); // true/false
1001 		}
1002 
1003 		if (scalarNdx != (scalarSize - 1))
1004 			advanceToken(TOKEN_COMMA);
1005 	}
1006 
1007 	if (scalarSize > 1)
1008 		advanceToken(TOKEN_RIGHT_PAREN);
1009 
1010 	// Store results.
1011 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1012 		result.elements.push_back(elems[scalarNdx]);
1013 }
1014 
parseValue(ValueBlock & valueBlock)1015 void ShaderParser::parseValue (ValueBlock& valueBlock)
1016 {
1017 	PARSE_DBG(("      parseValue()\n"));
1018 
1019 	// Parsed results.
1020 	vector<Value>*	dstBlock	= DE_NULL;
1021 	DataType		basicType	= TYPE_LAST;
1022 	std::string		valueName;
1023 
1024 	// Parse storage.
1025 	if (m_curToken == TOKEN_UNIFORM)
1026 		dstBlock = &valueBlock.uniforms;
1027 	else if (m_curToken == TOKEN_INPUT)
1028 		dstBlock = &valueBlock.inputs;
1029 	else if (m_curToken == TOKEN_OUTPUT)
1030 		dstBlock = &valueBlock.outputs;
1031 	else
1032 		parseError(string("unexpected token encountered when parsing value classifier"));
1033 	advanceToken();
1034 
1035 	// Parse data type.
1036 	basicType = mapDataTypeToken(m_curToken);
1037 	if (basicType == TYPE_INVALID)
1038 		parseError(string("unexpected token when parsing value data type: " + m_curTokenStr));
1039 	advanceToken();
1040 
1041 	// Parse value name.
1042 	if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING)
1043 	{
1044 		if (m_curToken == TOKEN_IDENTIFIER)
1045 			valueName = m_curTokenStr;
1046 		else
1047 			valueName = parseStringLiteral(m_curTokenStr.c_str());
1048 	}
1049 	else
1050 		parseError(string("unexpected token when parsing value name: " + m_curTokenStr));
1051 	advanceToken();
1052 
1053 	// Parse assignment operator.
1054 	advanceToken(TOKEN_ASSIGN);
1055 
1056 	{
1057 		Value value;
1058 		value.name	= valueName;
1059 		value.type	= VarType(basicType, PRECISION_LAST);
1060 		dstBlock->push_back(value);
1061 	}
1062 
1063 	// Parse actual value.
1064 	if (m_curToken == TOKEN_LEFT_BRACKET) // value list
1065 	{
1066 		int	arrayLength	= 0; // \todo [2015-08-03 pyry] Currently unused
1067 
1068 		advanceToken(TOKEN_LEFT_BRACKET);
1069 
1070 		for (;;)
1071 		{
1072 			parseValueElement(basicType, dstBlock->back());
1073 			arrayLength++;
1074 
1075 			if (m_curToken == TOKEN_RIGHT_BRACKET)
1076 				break;
1077 			else if (m_curToken == TOKEN_VERTICAL_BAR)
1078 			{
1079 				advanceToken();
1080 				continue;
1081 			}
1082 			else
1083 				parseError(string("unexpected token in value element array: " + m_curTokenStr));
1084 		}
1085 
1086 		advanceToken(TOKEN_RIGHT_BRACKET);
1087 	}
1088 	else //  single elements
1089 	{
1090 		parseValueElement(basicType, dstBlock->back());
1091 	}
1092 
1093 	advanceToken(TOKEN_SEMI_COLON); // end of declaration
1094 }
1095 
parseValueBlock(ValueBlock & valueBlock)1096 void ShaderParser::parseValueBlock (ValueBlock& valueBlock)
1097 {
1098 	PARSE_DBG(("    parseValueBlock()\n"));
1099 	advanceToken(TOKEN_VALUES);
1100 	advanceToken(TOKEN_LEFT_BRACE);
1101 
1102 	for (;;)
1103 	{
1104 		if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT)
1105 			parseValue(valueBlock);
1106 		else if (m_curToken == TOKEN_RIGHT_BRACE)
1107 			break;
1108 		else
1109 			parseError(string("unexpected token when parsing a value block: " + m_curTokenStr));
1110 	}
1111 
1112 	advanceToken(TOKEN_RIGHT_BRACE);
1113 }
1114 
parseShaderStageList(void)1115 deUint32 ShaderParser::parseShaderStageList (void)
1116 {
1117 	deUint32 mask = 0;
1118 
1119 	assumeToken(TOKEN_LEFT_BRACE);
1120 
1121 	// don't allow 0-sized lists
1122 	advanceToken();
1123 	mask |= getShaderStageLiteralFlag();
1124 	advanceToken();
1125 
1126 	for (;;)
1127 	{
1128 		if (m_curToken == TOKEN_RIGHT_BRACE)
1129 			break;
1130 		else if (m_curToken == TOKEN_COMMA)
1131 		{
1132 			deUint32 stageFlag;
1133 			advanceToken();
1134 
1135 			stageFlag = getShaderStageLiteralFlag();
1136 			if (stageFlag & mask)
1137 				parseError(string("stage already set in the shader stage set: " + m_curTokenStr));
1138 
1139 			mask |= stageFlag;
1140 			advanceToken();
1141 		}
1142 		else
1143 			parseError(string("invalid shader stage set token: " + m_curTokenStr));
1144 	}
1145 	advanceToken(TOKEN_RIGHT_BRACE);
1146 
1147 	return mask;
1148 }
1149 
parseRequirement(CaseRequirement & valueBlock)1150 void ShaderParser::parseRequirement (CaseRequirement& valueBlock)
1151 {
1152 	PARSE_DBG(("    parseRequirement()\n"));
1153 
1154 	advanceToken();
1155 	assumeToken(TOKEN_IDENTIFIER);
1156 
1157 	if (m_curTokenStr == "extension")
1158 	{
1159 		std::vector<std::string>	anyExtensionStringList;
1160 		deUint32					affectedCasesFlags		= -1; // by default all stages
1161 
1162 		advanceToken();
1163 		assumeToken(TOKEN_LEFT_BRACE);
1164 
1165 		advanceToken();
1166 		assumeToken(TOKEN_STRING);
1167 
1168 		anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
1169 		advanceToken();
1170 
1171 		for (;;)
1172 		{
1173 			if (m_curToken == TOKEN_RIGHT_BRACE)
1174 				break;
1175 			else if (m_curToken == TOKEN_VERTICAL_BAR)
1176 			{
1177 				advanceToken();
1178 				assumeToken(TOKEN_STRING);
1179 
1180 				anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
1181 				advanceToken();
1182 			}
1183 			else
1184 				parseError(string("invalid extension list token: " + m_curTokenStr));
1185 		}
1186 		advanceToken(TOKEN_RIGHT_BRACE);
1187 
1188 		if (m_curToken == TOKEN_IN)
1189 		{
1190 			advanceToken();
1191 			affectedCasesFlags = parseShaderStageList();
1192 		}
1193 
1194 		valueBlock = CaseRequirement::createAnyExtensionRequirement(anyExtensionStringList, affectedCasesFlags);
1195 	}
1196 	else if (m_curTokenStr == "limit")
1197 	{
1198 		deUint32	limitEnum;
1199 		int			limitValue;
1200 
1201 		advanceToken();
1202 
1203 		assumeToken(TOKEN_STRING);
1204 		limitEnum = getGLEnumFromName(parseStringLiteral(m_curTokenStr.c_str()));
1205 		advanceToken();
1206 
1207 		assumeToken(TOKEN_GREATER);
1208 		advanceToken();
1209 
1210 		assumeToken(TOKEN_INT_LITERAL);
1211 		limitValue = parseIntLiteral(m_curTokenStr.c_str());
1212 		advanceToken();
1213 
1214 		valueBlock = CaseRequirement::createLimitRequirement(limitEnum, limitValue);
1215 	}
1216 	else if (m_curTokenStr == "full_glsl_es_100_support")
1217 	{
1218 		advanceToken();
1219 
1220 		valueBlock = CaseRequirement::createFullGLSLES100SpecificationRequirement();
1221 	}
1222 	else
1223 		parseError(string("invalid requirement value: " + m_curTokenStr));
1224 }
1225 
parseExpectResult(ExpectResult & expectResult)1226 void ShaderParser::parseExpectResult (ExpectResult& expectResult)
1227 {
1228 	assumeToken(TOKEN_IDENTIFIER);
1229 
1230 	if (m_curTokenStr == "pass")
1231 		expectResult = EXPECT_PASS;
1232 	else if (m_curTokenStr == "compile_fail")
1233 		expectResult = EXPECT_COMPILE_FAIL;
1234 	else if (m_curTokenStr == "link_fail")
1235 		expectResult = EXPECT_LINK_FAIL;
1236 	else if (m_curTokenStr == "compile_or_link_fail")
1237 		expectResult = EXPECT_COMPILE_LINK_FAIL;
1238 	else if (m_curTokenStr == "validation_fail")
1239 		expectResult = EXPECT_VALIDATION_FAIL;
1240 	else if (m_curTokenStr == "build_successful")
1241 		expectResult = EXPECT_BUILD_SUCCESSFUL;
1242 	else
1243 		parseError(string("invalid expected result value: " + m_curTokenStr));
1244 
1245 	advanceToken();
1246 }
1247 
parseGLSLVersion(glu::GLSLVersion & version)1248 void ShaderParser::parseGLSLVersion (glu::GLSLVersion& version)
1249 {
1250 	int			versionNum		= 0;
1251 	std::string	postfix			= "";
1252 
1253 	assumeToken(TOKEN_INT_LITERAL);
1254 	versionNum = parseIntLiteral(m_curTokenStr.c_str());
1255 	advanceToken();
1256 
1257 	if (m_curToken == TOKEN_IDENTIFIER)
1258 	{
1259 		postfix = m_curTokenStr;
1260 		advanceToken();
1261 	}
1262 
1263 	DE_STATIC_ASSERT(glu::GLSL_VERSION_LAST == 14);
1264 
1265 	if		(versionNum == 100 && postfix == "es")	version = glu::GLSL_VERSION_100_ES;
1266 	else if (versionNum == 300 && postfix == "es")	version = glu::GLSL_VERSION_300_ES;
1267 	else if (versionNum == 310 && postfix == "es")	version = glu::GLSL_VERSION_310_ES;
1268 	else if (versionNum == 320 && postfix == "es")	version = glu::GLSL_VERSION_320_ES;
1269 	else if (versionNum == 130)						version = glu::GLSL_VERSION_130;
1270 	else if (versionNum == 140)						version = glu::GLSL_VERSION_140;
1271 	else if (versionNum == 150)						version = glu::GLSL_VERSION_150;
1272 	else if (versionNum == 330)						version = glu::GLSL_VERSION_330;
1273 	else if (versionNum == 400)						version = glu::GLSL_VERSION_400;
1274 	else if (versionNum == 410)						version = glu::GLSL_VERSION_410;
1275 	else if (versionNum == 420)						version = glu::GLSL_VERSION_420;
1276 	else if (versionNum == 430)						version = glu::GLSL_VERSION_430;
1277 	else if (versionNum == 440)						version = glu::GLSL_VERSION_440;
1278 	else if (versionNum == 450)						version = glu::GLSL_VERSION_450;
1279 	else
1280 		parseError("Unknown GLSL version");
1281 }
1282 
parsePipelineProgram(ProgramSpecification & program)1283 void ShaderParser::parsePipelineProgram (ProgramSpecification& program)
1284 {
1285 	advanceToken(TOKEN_PIPELINE_PROGRAM);
1286 
1287 	for (;;)
1288 	{
1289 		if (m_curToken == TOKEN_END)
1290 			break;
1291 		else if (m_curToken == TOKEN_ACTIVE_STAGES)
1292 		{
1293 			advanceToken();
1294 			program.activeStages = parseShaderStageList();
1295 		}
1296 		else if (m_curToken == TOKEN_REQUIRE)
1297 		{
1298 			CaseRequirement requirement;
1299 			parseRequirement(requirement);
1300 
1301 			if (requirement.type == CaseRequirement::TYPE_EXTENSION)
1302 				program.requiredExtensions.push_back(requirement.extension);
1303 			else
1304 				parseError("only extension requirements are allowed inside pipeline program");
1305 		}
1306 		else if (m_curToken == TOKEN_VERTEX						||
1307 				 m_curToken == TOKEN_FRAGMENT					||
1308 				 m_curToken == TOKEN_TESSELLATION_CONTROL		||
1309 				 m_curToken == TOKEN_TESSELLATION_EVALUATION	||
1310 				 m_curToken == TOKEN_GEOMETRY)
1311 		{
1312 			const Token	token = m_curToken;
1313 			string		source;
1314 
1315 			advanceToken();
1316 			assumeToken(TOKEN_SHADER_SOURCE);
1317 			source = parseShaderSource(m_curTokenStr.c_str());
1318 			advanceToken();
1319 
1320 			switch (token)
1321 			{
1322 				case TOKEN_VERTEX:					program.sources.sources[SHADERTYPE_VERTEX].push_back(source);					break;
1323 				case TOKEN_FRAGMENT:				program.sources.sources[SHADERTYPE_FRAGMENT].push_back(source);					break;
1324 				case TOKEN_TESSELLATION_CONTROL:	program.sources.sources[SHADERTYPE_TESSELLATION_CONTROL].push_back(source);		break;
1325 				case TOKEN_TESSELLATION_EVALUATION:	program.sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].push_back(source);	break;
1326 				case TOKEN_GEOMETRY:				program.sources.sources[SHADERTYPE_GEOMETRY].push_back(source);					break;
1327 				default:
1328 					parseError(DE_FALSE);
1329 			}
1330 		}
1331 		else
1332 			parseError(string("invalid pipeline program value: " + m_curTokenStr));
1333 	}
1334 	advanceToken(TOKEN_END);
1335 
1336 	if (program.activeStages == 0)
1337 		parseError("program pipeline object must have active stages");
1338 }
1339 
parseShaderCase(vector<tcu::TestNode * > & shaderNodeList)1340 void ShaderParser::parseShaderCase (vector<tcu::TestNode*>& shaderNodeList)
1341 {
1342 	// Parse 'case'.
1343 	PARSE_DBG(("  parseShaderCase()\n"));
1344 	advanceToken(TOKEN_CASE);
1345 
1346 	// Parse case name.
1347 	string caseName = m_curTokenStr;
1348 	advanceToken(); // \note [pyry] All token types are allowed here.
1349 
1350 	// \todo [pyry] Optimize by parsing most stuff directly to ShaderCaseSpecification
1351 
1352 	// Setup case.
1353 	GLSLVersion						version			= DEFAULT_GLSL_VERSION;
1354 	ExpectResult					expectResult	= EXPECT_PASS;
1355 	string							description;
1356 	string							bothSource;
1357 	vector<string>					vertexSources;
1358 	vector<string>					fragmentSources;
1359 	vector<string>					tessellationCtrlSources;
1360 	vector<string>					tessellationEvalSources;
1361 	vector<string>					geometrySources;
1362 	ValueBlock						valueBlock;
1363 	bool							valueBlockSeen	= false;
1364 	vector<CaseRequirement>			requirements;
1365 	vector<ProgramSpecification>	pipelinePrograms;
1366 
1367 	for (;;)
1368 	{
1369 		if (m_curToken == TOKEN_END)
1370 			break;
1371 		else if (m_curToken == TOKEN_DESC)
1372 		{
1373 			advanceToken();
1374 			assumeToken(TOKEN_STRING);
1375 			description = parseStringLiteral(m_curTokenStr.c_str());
1376 			advanceToken();
1377 		}
1378 		else if (m_curToken == TOKEN_EXPECT)
1379 		{
1380 			advanceToken();
1381 			parseExpectResult(expectResult);
1382 		}
1383 		else if (m_curToken == TOKEN_VALUES)
1384 		{
1385 			if (valueBlockSeen)
1386 				parseError("multiple value blocks");
1387 			parseValueBlock(valueBlock);
1388 			valueBlockSeen = true;
1389 		}
1390 		else if (m_curToken == TOKEN_BOTH						||
1391 				 m_curToken == TOKEN_VERTEX						||
1392 				 m_curToken == TOKEN_FRAGMENT					||
1393 				 m_curToken == TOKEN_TESSELLATION_CONTROL		||
1394 				 m_curToken == TOKEN_TESSELLATION_EVALUATION	||
1395 				 m_curToken == TOKEN_GEOMETRY)
1396 		{
1397 			const Token	token = m_curToken;
1398 			string		source;
1399 
1400 			advanceToken();
1401 			assumeToken(TOKEN_SHADER_SOURCE);
1402 			source = parseShaderSource(m_curTokenStr.c_str());
1403 			advanceToken();
1404 
1405 			switch (token)
1406 			{
1407 				case TOKEN_VERTEX:					vertexSources.push_back(source);			break;
1408 				case TOKEN_FRAGMENT:				fragmentSources.push_back(source);			break;
1409 				case TOKEN_TESSELLATION_CONTROL:	tessellationCtrlSources.push_back(source);	break;
1410 				case TOKEN_TESSELLATION_EVALUATION:	tessellationEvalSources.push_back(source);	break;
1411 				case TOKEN_GEOMETRY:				geometrySources.push_back(source);			break;
1412 				case TOKEN_BOTH:
1413 				{
1414 					if (!bothSource.empty())
1415 						parseError("multiple 'both' blocks");
1416 					bothSource = source;
1417 					break;
1418 				}
1419 
1420 				default:
1421 					parseError(DE_FALSE);
1422 			}
1423 		}
1424 		else if (m_curToken == TOKEN_VERSION)
1425 		{
1426 			advanceToken();
1427 			parseGLSLVersion(version);
1428 		}
1429 		else if (m_curToken == TOKEN_REQUIRE)
1430 		{
1431 			CaseRequirement requirement;
1432 			parseRequirement(requirement);
1433 			requirements.push_back(requirement);
1434 		}
1435 		else if (m_curToken == TOKEN_PIPELINE_PROGRAM)
1436 		{
1437 			ProgramSpecification pipelineProgram;
1438 			parsePipelineProgram(pipelineProgram);
1439 			pipelineProgram.sources.separable = true;
1440 			pipelinePrograms.push_back(pipelineProgram);
1441 		}
1442 		else
1443 			parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
1444 	}
1445 
1446 	advanceToken(TOKEN_END); // case end
1447 
1448 	// \todo [pyry] Clean up
1449 	vector<RequiredCapability>	requiredCaps;
1450 	vector<RequiredExtension>	requiredExts;
1451 	bool						fullGLSLES100Required	= false;
1452 
1453 	for (size_t reqNdx = 0; reqNdx < requirements.size(); ++reqNdx)
1454 	{
1455 		const CaseRequirement&	requirement	= requirements[reqNdx];
1456 
1457 		if (requirement.type == CaseRequirement::TYPE_EXTENSION)
1458 			requiredExts.push_back(requirement.extension);
1459 		else if (requirement.type == CaseRequirement::TYPE_IMPLEMENTATION_LIMIT)
1460 			requiredCaps.push_back(requirement.requiredCap);
1461 		else if (requirement.type == CaseRequirement::TYPE_FULL_GLSL_ES_100_SUPPORT)
1462 			fullGLSLES100Required = true;
1463 		else
1464 			DE_ASSERT(false);
1465 	}
1466 
1467 	if (!bothSource.empty())
1468 	{
1469 		if (!vertexSources.empty()				||
1470 			!fragmentSources.empty()			||
1471 			!tessellationCtrlSources.empty()	||
1472 			!tessellationEvalSources.empty()	||
1473 			!geometrySources.empty()			||
1474 			!pipelinePrograms.empty())
1475 		{
1476 			parseError("'both' cannot be mixed with other shader stages");
1477 		}
1478 
1479 		// vertex
1480 		{
1481 			ShaderCaseSpecification	spec;
1482 			spec.caseType				= CASETYPE_VERTEX_ONLY;
1483 			spec.expectResult			= expectResult;
1484 			spec.targetVersion			= version;
1485 			spec.fullGLSLES100Required	= fullGLSLES100Required;
1486 			spec.requiredCaps			= requiredCaps;
1487 			spec.values					= valueBlock;
1488 
1489 			spec.programs.resize(1);
1490 			spec.programs[0].sources << VertexSource(bothSource);
1491 			spec.programs[0].requiredExtensions	= requiredExts;
1492 
1493 			shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_vertex", description, ShaderCaseSpecification(spec)));
1494 		}
1495 
1496 		// fragment
1497 		{
1498 			ShaderCaseSpecification	spec;
1499 			spec.caseType				= CASETYPE_FRAGMENT_ONLY;
1500 			spec.expectResult			= expectResult;
1501 			spec.targetVersion			= version;
1502 			spec.fullGLSLES100Required	= fullGLSLES100Required;
1503 			spec.requiredCaps			= requiredCaps;
1504 			spec.values					= valueBlock;
1505 
1506 			spec.programs.resize(1);
1507 			spec.programs[0].sources << FragmentSource(bothSource);
1508 			spec.programs[0].requiredExtensions	= requiredExts;
1509 
1510 			shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_fragment", description, ShaderCaseSpecification(spec)));
1511 		}
1512 	}
1513 	else if (pipelinePrograms.empty())
1514 	{
1515 		ShaderCaseSpecification	spec;
1516 		spec.caseType				= CASETYPE_COMPLETE;
1517 		spec.expectResult			= expectResult;
1518 		spec.targetVersion			= version;
1519 		spec.fullGLSLES100Required	= fullGLSLES100Required;
1520 		spec.requiredCaps			= requiredCaps;
1521 		spec.values					= valueBlock;
1522 
1523 		spec.programs.resize(1);
1524 		spec.programs[0].sources.sources[SHADERTYPE_VERTEX].swap(vertexSources);
1525 		spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].swap(fragmentSources);
1526 		spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_CONTROL].swap(tessellationCtrlSources);
1527 		spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].swap(tessellationEvalSources);
1528 		spec.programs[0].sources.sources[SHADERTYPE_GEOMETRY].swap(geometrySources);
1529 		spec.programs[0].requiredExtensions.swap(requiredExts);
1530 
1531 		shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec)));
1532 	}
1533 	else
1534 	{
1535 		if (!vertexSources.empty()				||
1536 			!fragmentSources.empty()			||
1537 			!tessellationCtrlSources.empty()	||
1538 			!tessellationEvalSources.empty()	||
1539 			!geometrySources.empty())
1540 		{
1541 			parseError("pipeline programs cannot be mixed with complete programs");
1542 		}
1543 
1544 		if (!requiredExts.empty())
1545 			parseError("global extension requirements cannot be mixed with pipeline programs");
1546 
1547 		// Pipeline case, multiple programs
1548 		{
1549 			ShaderCaseSpecification	spec;
1550 			spec.caseType				= CASETYPE_COMPLETE;
1551 			spec.expectResult			= expectResult;
1552 			spec.targetVersion			= version;
1553 			spec.fullGLSLES100Required	= fullGLSLES100Required;
1554 			spec.requiredCaps			= requiredCaps;
1555 			spec.values					= valueBlock;
1556 
1557 			spec.programs.swap(pipelinePrograms);
1558 
1559 			shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec)));
1560 		}
1561 	}
1562 }
1563 
parseShaderGroup(vector<tcu::TestNode * > & shaderNodeList)1564 void ShaderParser::parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList)
1565 {
1566 	// Parse 'case'.
1567 	PARSE_DBG(("  parseShaderGroup()\n"));
1568 	advanceToken(TOKEN_GROUP);
1569 
1570 	// Parse case name.
1571 	string name = m_curTokenStr;
1572 	advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
1573 
1574 	// Parse description.
1575 	assumeToken(TOKEN_STRING);
1576 	string description = parseStringLiteral(m_curTokenStr.c_str());
1577 	advanceToken(TOKEN_STRING);
1578 
1579 	std::vector<tcu::TestNode*> children;
1580 
1581 	// Parse group children.
1582 	for (;;)
1583 	{
1584 		if (m_curToken == TOKEN_END)
1585 			break;
1586 		else if (m_curToken == TOKEN_GROUP)
1587 			parseShaderGroup(children);
1588 		else if (m_curToken == TOKEN_CASE)
1589 			parseShaderCase(children);
1590 		else if (m_curToken == TOKEN_IMPORT)
1591 			parseImport(children);
1592 		else
1593 			parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
1594 	}
1595 
1596 	advanceToken(TOKEN_END); // group end
1597 
1598 	// Create group node.
1599 	tcu::TestCaseGroup* groupNode = m_caseFactory->createGroup(name, description, children);
1600 	shaderNodeList.push_back(groupNode);
1601 }
1602 
parseImport(vector<tcu::TestNode * > & shaderNodeList)1603 void ShaderParser::parseImport (vector<tcu::TestNode*>& shaderNodeList)
1604 {
1605 	std::string	importFileName;
1606 
1607 	advanceToken(TOKEN_IMPORT);
1608 
1609 	assumeToken(TOKEN_STRING);
1610 	importFileName = parseStringLiteral(m_curTokenStr.c_str());
1611 	advanceToken(TOKEN_STRING);
1612 
1613 	{
1614 		ShaderParser					subParser		(m_archive, de::FilePath::join(de::FilePath(m_filename).getDirName(), importFileName).getPath(), m_caseFactory);
1615 		const vector<tcu::TestNode*>	importedCases = subParser.parse();
1616 
1617 		// \todo [2015-08-03 pyry] Not exception safe
1618 		shaderNodeList.insert(shaderNodeList.end(), importedCases.begin(), importedCases.end());
1619 	}
1620 }
1621 
parse(void)1622 vector<tcu::TestNode*> ShaderParser::parse (void)
1623 {
1624 	const int	dataLen		= m_resource->getSize();
1625 
1626 	m_input.resize(dataLen+1);
1627 	m_resource->setPosition(0);
1628 	m_resource->read((deUint8*)&m_input[0], dataLen);
1629 	m_input[dataLen] = '\0';
1630 
1631 	// Initialize parser.
1632 	m_curPtr		= &m_input[0];
1633 	m_curToken		= TOKEN_INVALID;
1634 	m_curTokenStr	= "";
1635 	advanceToken();
1636 
1637 	vector<tcu::TestNode*> nodeList;
1638 
1639 	// Parse all cases.
1640 	PARSE_DBG(("parse()\n"));
1641 	for (;;)
1642 	{
1643 		if (m_curToken == TOKEN_CASE)
1644 			parseShaderCase(nodeList);
1645 		else if (m_curToken == TOKEN_GROUP)
1646 			parseShaderGroup(nodeList);
1647 		else if (m_curToken == TOKEN_IMPORT)
1648 			parseImport(nodeList);
1649 		else if (m_curToken == TOKEN_EOF)
1650 			break;
1651 		else
1652 			parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
1653 	}
1654 
1655 	assumeToken(TOKEN_EOF);
1656 //	printf("  parsed %d test cases.\n", caseList.size());
1657 	return nodeList;
1658 }
1659 
parseFile(const tcu::Archive & archive,const std::string & filename,ShaderCaseFactory * caseFactory)1660 std::vector<tcu::TestNode*> parseFile (const tcu::Archive& archive, const std::string& filename, ShaderCaseFactory* caseFactory)
1661 {
1662 	sl::ShaderParser	parser	(archive, filename, caseFactory);
1663 
1664 	return parser.parse();
1665 }
1666 
1667 // Execution utilities
1668 
dumpValue(tcu::TestLog & log,const Value & val,const char * storageName,int arrayNdx)1669 static void dumpValue (tcu::TestLog& log, const Value& val, const char* storageName, int arrayNdx)
1670 {
1671 	const char* const	valueName		= val.name.c_str();
1672 	const DataType		dataType		= val.type.getBasicType();
1673 	int					scalarSize		= getDataTypeScalarSize(dataType);
1674 	ostringstream		result;
1675 
1676 	result << "    " << storageName << " ";
1677 
1678 	result << getDataTypeName(dataType) << " " << valueName << ":";
1679 
1680 	if (isDataTypeScalar(dataType))
1681 		result << " ";
1682 	if (isDataTypeVector(dataType))
1683 		result << " [ ";
1684 	else if (isDataTypeMatrix(dataType))
1685 		result << "\n";
1686 
1687 	if (isDataTypeScalarOrVector(dataType))
1688 	{
1689 		for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1690 		{
1691 			int						elemNdx	= arrayNdx;
1692 			const Value::Element&	e		= val.elements[elemNdx*scalarSize + scalarNdx];
1693 			result << ((scalarNdx != 0) ? ", " : "");
1694 
1695 			if (isDataTypeFloatOrVec(dataType))
1696 				result << e.float32;
1697 			else if (isDataTypeIntOrIVec(dataType))
1698 				result << e.int32;
1699 			else if (isDataTypeUintOrUVec(dataType))
1700 				result << (deUint32)e.int32;
1701 			else if (isDataTypeBoolOrBVec(dataType))
1702 				result << (e.bool32 ? "true" : "false");
1703 		}
1704 	}
1705 	else if (isDataTypeMatrix(dataType))
1706 	{
1707 		int numRows = getDataTypeMatrixNumRows(dataType);
1708 		int numCols = getDataTypeMatrixNumColumns(dataType);
1709 		for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1710 		{
1711 			result << "       [ ";
1712 			for (int colNdx = 0; colNdx < numCols; colNdx++)
1713 			{
1714 				int		elemNdx = arrayNdx;
1715 				float	v		= val.elements[elemNdx*scalarSize + rowNdx*numCols + colNdx].float32;
1716 				result << ((colNdx==0) ? "" : ", ") << v;
1717 			}
1718 			result << " ]\n";
1719 		}
1720 	}
1721 
1722 	if (isDataTypeScalar(dataType))
1723 		result << "\n";
1724 	else if (isDataTypeVector(dataType))
1725 		result << " ]\n";
1726 
1727 	log << TestLog::Message << result.str() << TestLog::EndMessage;
1728 }
1729 
dumpValues(tcu::TestLog & log,const vector<Value> & values,const char * storageName,int arrayNdx)1730 static void dumpValues (tcu::TestLog& log, const vector<Value>& values, const char* storageName, int arrayNdx)
1731 {
1732 	for (size_t valNdx = 0; valNdx < values.size(); valNdx++)
1733 		dumpValue(log, values[valNdx], storageName, arrayNdx);
1734 }
1735 
dumpValues(tcu::TestLog & log,const ValueBlock & values,int arrayNdx)1736 void dumpValues (tcu::TestLog& log, const ValueBlock& values, int arrayNdx)
1737 {
1738 	dumpValues(log, values.inputs,		"input",	arrayNdx);
1739 	dumpValues(log, values.outputs,		"expected",	arrayNdx);
1740 	dumpValues(log, values.uniforms,	"uniform",	arrayNdx);
1741 }
1742 
generateExtensionStatements(std::ostringstream & buf,const std::vector<RequiredExtension> & extensions,glu::ShaderType type)1743 static void generateExtensionStatements (std::ostringstream& buf, const std::vector<RequiredExtension>& extensions, glu::ShaderType type)
1744 {
1745 	for (size_t ndx = 0; ndx < extensions.size(); ++ndx)
1746 	{
1747 		DE_ASSERT(extensions[ndx].effectiveStages != 0u &&
1748 				  extensions[ndx].alternatives.size() == 1);
1749 
1750 		if ((extensions[ndx].effectiveStages & (1u << (deUint32)type)) != 0)
1751 			buf << "#extension " << extensions[ndx].alternatives[0] << " : require\n";
1752 	}
1753 }
1754 
1755 // Injects #extension XXX : require lines after the last preprocessor directive in the shader code. Does not support line continuations
injectExtensionRequirements(const std::string & baseCode,const std::vector<RequiredExtension> & extensions,glu::ShaderType shaderType)1756 std::string injectExtensionRequirements (const std::string& baseCode, const std::vector<RequiredExtension>& extensions, glu::ShaderType shaderType)
1757 {
1758 	std::istringstream	baseCodeBuf					(baseCode);
1759 	std::ostringstream	resultBuf;
1760 	std::string			line;
1761 	bool				firstNonPreprocessorLine	= true;
1762 	std::ostringstream	extStr;
1763 
1764 	generateExtensionStatements(extStr, extensions, shaderType);
1765 
1766 	// skip if no requirements
1767 	if (extStr.str().empty())
1768 		return baseCode;
1769 
1770 	while (std::getline(baseCodeBuf, line))
1771 	{
1772 		// begins with '#'?
1773 		const std::string::size_type	firstNonWhitespace		= line.find_first_not_of("\t ");
1774 		const bool						isPreprocessorDirective	= (firstNonWhitespace != std::string::npos && line.at(firstNonWhitespace) == '#');
1775 
1776 		// Inject #extensions
1777 		if (!isPreprocessorDirective && firstNonPreprocessorLine)
1778 		{
1779 			firstNonPreprocessorLine = false;
1780 			resultBuf << extStr.str();
1781 		}
1782 
1783 		resultBuf << line << "\n";
1784 	}
1785 
1786 	return resultBuf.str();
1787 }
1788 
genCompareFunctions(ostringstream & stream,const ValueBlock & valueBlock,bool useFloatTypes)1789 void genCompareFunctions (ostringstream& stream, const ValueBlock& valueBlock, bool useFloatTypes)
1790 {
1791 	bool cmpTypeFound[TYPE_LAST];
1792 	for (int i = 0; i < TYPE_LAST; i++)
1793 		cmpTypeFound[i] = false;
1794 
1795 	for (size_t valueNdx = 0; valueNdx < valueBlock.outputs.size(); valueNdx++)
1796 	{
1797 		const Value& val = valueBlock.outputs[valueNdx];
1798 		cmpTypeFound[(size_t)val.type.getBasicType()] = true;
1799 	}
1800 
1801 	if (useFloatTypes)
1802 	{
1803 		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n";
1804 		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n";
1805 		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n";
1806 		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n";
1807 		if (cmpTypeFound[TYPE_INT])			stream << "bool isOk (float a, int b)  { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n";
1808 		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n";
1809 		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n";
1810 		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n";
1811 		if (cmpTypeFound[TYPE_UINT])		stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n";
1812 		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n";
1813 		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n";
1814 		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n";
1815 	}
1816 	else
1817 	{
1818 		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (bool a, bool b)   { return (a == b); }\n";
1819 		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n";
1820 		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n";
1821 		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n";
1822 		if (cmpTypeFound[TYPE_INT])			stream << "bool isOk (int a, int b)     { return (a == b); }\n";
1823 		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n";
1824 		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n";
1825 		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n";
1826 		if (cmpTypeFound[TYPE_UINT])		stream << "bool isOk (uint a, uint b)   { return (a == b); }\n";
1827 		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n";
1828 		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n";
1829 		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n";
1830 	}
1831 
1832 	if (cmpTypeFound[TYPE_FLOAT])		stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n";
1833 	if (cmpTypeFound[TYPE_FLOAT_VEC2])	stream << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1834 	if (cmpTypeFound[TYPE_FLOAT_VEC3])	stream << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1835 	if (cmpTypeFound[TYPE_FLOAT_VEC4])	stream << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1836 
1837 	if (cmpTypeFound[TYPE_FLOAT_MAT2])		stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1838 	if (cmpTypeFound[TYPE_FLOAT_MAT2X3])	stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1839 	if (cmpTypeFound[TYPE_FLOAT_MAT2X4])	stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1840 	if (cmpTypeFound[TYPE_FLOAT_MAT3X2])	stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1841 	if (cmpTypeFound[TYPE_FLOAT_MAT3])		stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1842 	if (cmpTypeFound[TYPE_FLOAT_MAT3X4])	stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1843 	if (cmpTypeFound[TYPE_FLOAT_MAT4X2])	stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n";
1844 	if (cmpTypeFound[TYPE_FLOAT_MAT4X3])	stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n";
1845 	if (cmpTypeFound[TYPE_FLOAT_MAT4])		stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n";
1846 }
1847 
1848 } // sl
1849 } // glu
1850