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