Home | History | Annotate | Download | only in opengl
      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 
     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 
     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 
    240 DE_INLINE deBool isWhitespace (char c)
    241 {
    242 	return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
    243 }
    244 
    245 DE_INLINE deBool isEOL (char c)
    246 {
    247 	return (c == '\r') || (c == '\n');
    248 }
    249 
    250 DE_INLINE deBool isNumeric (char c)
    251 {
    252 	return deInRange32(c, '0', '9');
    253 }
    254 
    255 DE_INLINE deBool isAlpha (char c)
    256 {
    257 	return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
    258 }
    259 
    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 
    284 	CaseRequirement (void) : type(TYPE_LAST) {}
    285 
    286 	static CaseRequirement createFullGLSLES100SpecificationRequirement (void)
    287 	{
    288 		CaseRequirement req;
    289 		req.type		= TYPE_FULL_GLSL_ES_100_SUPPORT;
    290 		return req;
    291 	}
    292 
    293 	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 
    301 	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 
    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 
    445 ShaderParser::~ShaderParser (void)
    446 {
    447 }
    448 
    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 
    455 float ShaderParser::parseFloatLiteral (const char* str)
    456 {
    457 	return (float)atof(str);
    458 }
    459 
    460 int ShaderParser::parseIntLiteral (const char* str)
    461 {
    462 	return atoi(str);
    463 }
    464 
    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 
    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 
    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 
    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 
    787 void ShaderParser::advanceToken (Token assumed)
    788 {
    789 	assumeToken(assumed);
    790 	advanceToken();
    791 }
    792 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 == 15);
   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 if (versionNum == 460)						version = glu::GLSL_VERSION_460;
   1280 	else
   1281 		parseError("Unknown GLSL version");
   1282 }
   1283 
   1284 void ShaderParser::parsePipelineProgram (ProgramSpecification& program)
   1285 {
   1286 	advanceToken(TOKEN_PIPELINE_PROGRAM);
   1287 
   1288 	for (;;)
   1289 	{
   1290 		if (m_curToken == TOKEN_END)
   1291 			break;
   1292 		else if (m_curToken == TOKEN_ACTIVE_STAGES)
   1293 		{
   1294 			advanceToken();
   1295 			program.activeStages = parseShaderStageList();
   1296 		}
   1297 		else if (m_curToken == TOKEN_REQUIRE)
   1298 		{
   1299 			CaseRequirement requirement;
   1300 			parseRequirement(requirement);
   1301 
   1302 			if (requirement.type == CaseRequirement::TYPE_EXTENSION)
   1303 				program.requiredExtensions.push_back(requirement.extension);
   1304 			else
   1305 				parseError("only extension requirements are allowed inside pipeline program");
   1306 		}
   1307 		else if (m_curToken == TOKEN_VERTEX						||
   1308 				 m_curToken == TOKEN_FRAGMENT					||
   1309 				 m_curToken == TOKEN_TESSELLATION_CONTROL		||
   1310 				 m_curToken == TOKEN_TESSELLATION_EVALUATION	||
   1311 				 m_curToken == TOKEN_GEOMETRY)
   1312 		{
   1313 			const Token	token = m_curToken;
   1314 			string		source;
   1315 
   1316 			advanceToken();
   1317 			assumeToken(TOKEN_SHADER_SOURCE);
   1318 			source = parseShaderSource(m_curTokenStr.c_str());
   1319 			advanceToken();
   1320 
   1321 			switch (token)
   1322 			{
   1323 				case TOKEN_VERTEX:					program.sources.sources[SHADERTYPE_VERTEX].push_back(source);					break;
   1324 				case TOKEN_FRAGMENT:				program.sources.sources[SHADERTYPE_FRAGMENT].push_back(source);					break;
   1325 				case TOKEN_TESSELLATION_CONTROL:	program.sources.sources[SHADERTYPE_TESSELLATION_CONTROL].push_back(source);		break;
   1326 				case TOKEN_TESSELLATION_EVALUATION:	program.sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].push_back(source);	break;
   1327 				case TOKEN_GEOMETRY:				program.sources.sources[SHADERTYPE_GEOMETRY].push_back(source);					break;
   1328 				default:
   1329 					parseError(DE_FALSE);
   1330 			}
   1331 		}
   1332 		else
   1333 			parseError(string("invalid pipeline program value: " + m_curTokenStr));
   1334 	}
   1335 	advanceToken(TOKEN_END);
   1336 
   1337 	if (program.activeStages == 0)
   1338 		parseError("program pipeline object must have active stages");
   1339 }
   1340 
   1341 void ShaderParser::parseShaderCase (vector<tcu::TestNode*>& shaderNodeList)
   1342 {
   1343 	// Parse 'case'.
   1344 	PARSE_DBG(("  parseShaderCase()\n"));
   1345 	advanceToken(TOKEN_CASE);
   1346 
   1347 	// Parse case name.
   1348 	string caseName = m_curTokenStr;
   1349 	advanceToken(); // \note [pyry] All token types are allowed here.
   1350 
   1351 	// \todo [pyry] Optimize by parsing most stuff directly to ShaderCaseSpecification
   1352 
   1353 	// Setup case.
   1354 	GLSLVersion						version			= DEFAULT_GLSL_VERSION;
   1355 	ExpectResult					expectResult	= EXPECT_PASS;
   1356 	string							description;
   1357 	string							bothSource;
   1358 	vector<string>					vertexSources;
   1359 	vector<string>					fragmentSources;
   1360 	vector<string>					tessellationCtrlSources;
   1361 	vector<string>					tessellationEvalSources;
   1362 	vector<string>					geometrySources;
   1363 	ValueBlock						valueBlock;
   1364 	bool							valueBlockSeen	= false;
   1365 	vector<CaseRequirement>			requirements;
   1366 	vector<ProgramSpecification>	pipelinePrograms;
   1367 
   1368 	for (;;)
   1369 	{
   1370 		if (m_curToken == TOKEN_END)
   1371 			break;
   1372 		else if (m_curToken == TOKEN_DESC)
   1373 		{
   1374 			advanceToken();
   1375 			assumeToken(TOKEN_STRING);
   1376 			description = parseStringLiteral(m_curTokenStr.c_str());
   1377 			advanceToken();
   1378 		}
   1379 		else if (m_curToken == TOKEN_EXPECT)
   1380 		{
   1381 			advanceToken();
   1382 			parseExpectResult(expectResult);
   1383 		}
   1384 		else if (m_curToken == TOKEN_VALUES)
   1385 		{
   1386 			if (valueBlockSeen)
   1387 				parseError("multiple value blocks");
   1388 			parseValueBlock(valueBlock);
   1389 			valueBlockSeen = true;
   1390 		}
   1391 		else if (m_curToken == TOKEN_BOTH						||
   1392 				 m_curToken == TOKEN_VERTEX						||
   1393 				 m_curToken == TOKEN_FRAGMENT					||
   1394 				 m_curToken == TOKEN_TESSELLATION_CONTROL		||
   1395 				 m_curToken == TOKEN_TESSELLATION_EVALUATION	||
   1396 				 m_curToken == TOKEN_GEOMETRY)
   1397 		{
   1398 			const Token	token = m_curToken;
   1399 			string		source;
   1400 
   1401 			advanceToken();
   1402 			assumeToken(TOKEN_SHADER_SOURCE);
   1403 			source = parseShaderSource(m_curTokenStr.c_str());
   1404 			advanceToken();
   1405 
   1406 			switch (token)
   1407 			{
   1408 				case TOKEN_VERTEX:					vertexSources.push_back(source);			break;
   1409 				case TOKEN_FRAGMENT:				fragmentSources.push_back(source);			break;
   1410 				case TOKEN_TESSELLATION_CONTROL:	tessellationCtrlSources.push_back(source);	break;
   1411 				case TOKEN_TESSELLATION_EVALUATION:	tessellationEvalSources.push_back(source);	break;
   1412 				case TOKEN_GEOMETRY:				geometrySources.push_back(source);			break;
   1413 				case TOKEN_BOTH:
   1414 				{
   1415 					if (!bothSource.empty())
   1416 						parseError("multiple 'both' blocks");
   1417 					bothSource = source;
   1418 					break;
   1419 				}
   1420 
   1421 				default:
   1422 					parseError(DE_FALSE);
   1423 			}
   1424 		}
   1425 		else if (m_curToken == TOKEN_VERSION)
   1426 		{
   1427 			advanceToken();
   1428 			parseGLSLVersion(version);
   1429 		}
   1430 		else if (m_curToken == TOKEN_REQUIRE)
   1431 		{
   1432 			CaseRequirement requirement;
   1433 			parseRequirement(requirement);
   1434 			requirements.push_back(requirement);
   1435 		}
   1436 		else if (m_curToken == TOKEN_PIPELINE_PROGRAM)
   1437 		{
   1438 			ProgramSpecification pipelineProgram;
   1439 			parsePipelineProgram(pipelineProgram);
   1440 			pipelineProgram.sources.separable = true;
   1441 			pipelinePrograms.push_back(pipelineProgram);
   1442 		}
   1443 		else
   1444 			parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
   1445 	}
   1446 
   1447 	advanceToken(TOKEN_END); // case end
   1448 
   1449 	// \todo [pyry] Clean up
   1450 	vector<RequiredCapability>	requiredCaps;
   1451 	vector<RequiredExtension>	requiredExts;
   1452 	bool						fullGLSLES100Required	= false;
   1453 
   1454 	for (size_t reqNdx = 0; reqNdx < requirements.size(); ++reqNdx)
   1455 	{
   1456 		const CaseRequirement&	requirement	= requirements[reqNdx];
   1457 
   1458 		if (requirement.type == CaseRequirement::TYPE_EXTENSION)
   1459 			requiredExts.push_back(requirement.extension);
   1460 		else if (requirement.type == CaseRequirement::TYPE_IMPLEMENTATION_LIMIT)
   1461 			requiredCaps.push_back(requirement.requiredCap);
   1462 		else if (requirement.type == CaseRequirement::TYPE_FULL_GLSL_ES_100_SUPPORT)
   1463 			fullGLSLES100Required = true;
   1464 		else
   1465 			DE_ASSERT(false);
   1466 	}
   1467 
   1468 	if (!bothSource.empty())
   1469 	{
   1470 		if (!vertexSources.empty()				||
   1471 			!fragmentSources.empty()			||
   1472 			!tessellationCtrlSources.empty()	||
   1473 			!tessellationEvalSources.empty()	||
   1474 			!geometrySources.empty()			||
   1475 			!pipelinePrograms.empty())
   1476 		{
   1477 			parseError("'both' cannot be mixed with other shader stages");
   1478 		}
   1479 
   1480 		// vertex
   1481 		{
   1482 			ShaderCaseSpecification	spec;
   1483 			spec.caseType				= CASETYPE_VERTEX_ONLY;
   1484 			spec.expectResult			= expectResult;
   1485 			spec.targetVersion			= version;
   1486 			spec.fullGLSLES100Required	= fullGLSLES100Required;
   1487 			spec.requiredCaps			= requiredCaps;
   1488 			spec.values					= valueBlock;
   1489 
   1490 			spec.programs.resize(1);
   1491 			spec.programs[0].sources << VertexSource(bothSource);
   1492 			spec.programs[0].requiredExtensions	= requiredExts;
   1493 
   1494 			shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_vertex", description, ShaderCaseSpecification(spec)));
   1495 		}
   1496 
   1497 		// fragment
   1498 		{
   1499 			ShaderCaseSpecification	spec;
   1500 			spec.caseType				= CASETYPE_FRAGMENT_ONLY;
   1501 			spec.expectResult			= expectResult;
   1502 			spec.targetVersion			= version;
   1503 			spec.fullGLSLES100Required	= fullGLSLES100Required;
   1504 			spec.requiredCaps			= requiredCaps;
   1505 			spec.values					= valueBlock;
   1506 
   1507 			spec.programs.resize(1);
   1508 			spec.programs[0].sources << FragmentSource(bothSource);
   1509 			spec.programs[0].requiredExtensions	= requiredExts;
   1510 
   1511 			shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_fragment", description, ShaderCaseSpecification(spec)));
   1512 		}
   1513 	}
   1514 	else if (pipelinePrograms.empty())
   1515 	{
   1516 		ShaderCaseSpecification	spec;
   1517 		spec.caseType				= CASETYPE_COMPLETE;
   1518 		spec.expectResult			= expectResult;
   1519 		spec.targetVersion			= version;
   1520 		spec.fullGLSLES100Required	= fullGLSLES100Required;
   1521 		spec.requiredCaps			= requiredCaps;
   1522 		spec.values					= valueBlock;
   1523 
   1524 		spec.programs.resize(1);
   1525 		spec.programs[0].sources.sources[SHADERTYPE_VERTEX].swap(vertexSources);
   1526 		spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].swap(fragmentSources);
   1527 		spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_CONTROL].swap(tessellationCtrlSources);
   1528 		spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].swap(tessellationEvalSources);
   1529 		spec.programs[0].sources.sources[SHADERTYPE_GEOMETRY].swap(geometrySources);
   1530 		spec.programs[0].requiredExtensions.swap(requiredExts);
   1531 
   1532 		shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec)));
   1533 	}
   1534 	else
   1535 	{
   1536 		if (!vertexSources.empty()				||
   1537 			!fragmentSources.empty()			||
   1538 			!tessellationCtrlSources.empty()	||
   1539 			!tessellationEvalSources.empty()	||
   1540 			!geometrySources.empty())
   1541 		{
   1542 			parseError("pipeline programs cannot be mixed with complete programs");
   1543 		}
   1544 
   1545 		if (!requiredExts.empty())
   1546 			parseError("global extension requirements cannot be mixed with pipeline programs");
   1547 
   1548 		// Pipeline case, multiple programs
   1549 		{
   1550 			ShaderCaseSpecification	spec;
   1551 			spec.caseType				= CASETYPE_COMPLETE;
   1552 			spec.expectResult			= expectResult;
   1553 			spec.targetVersion			= version;
   1554 			spec.fullGLSLES100Required	= fullGLSLES100Required;
   1555 			spec.requiredCaps			= requiredCaps;
   1556 			spec.values					= valueBlock;
   1557 
   1558 			spec.programs.swap(pipelinePrograms);
   1559 
   1560 			shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec)));
   1561 		}
   1562 	}
   1563 }
   1564 
   1565 void ShaderParser::parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList)
   1566 {
   1567 	// Parse 'case'.
   1568 	PARSE_DBG(("  parseShaderGroup()\n"));
   1569 	advanceToken(TOKEN_GROUP);
   1570 
   1571 	// Parse case name.
   1572 	string name = m_curTokenStr;
   1573 	advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
   1574 
   1575 	// Parse description.
   1576 	assumeToken(TOKEN_STRING);
   1577 	string description = parseStringLiteral(m_curTokenStr.c_str());
   1578 	advanceToken(TOKEN_STRING);
   1579 
   1580 	std::vector<tcu::TestNode*> children;
   1581 
   1582 	// Parse group children.
   1583 	for (;;)
   1584 	{
   1585 		if (m_curToken == TOKEN_END)
   1586 			break;
   1587 		else if (m_curToken == TOKEN_GROUP)
   1588 			parseShaderGroup(children);
   1589 		else if (m_curToken == TOKEN_CASE)
   1590 			parseShaderCase(children);
   1591 		else if (m_curToken == TOKEN_IMPORT)
   1592 			parseImport(children);
   1593 		else
   1594 			parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
   1595 	}
   1596 
   1597 	advanceToken(TOKEN_END); // group end
   1598 
   1599 	// Create group node.
   1600 	tcu::TestCaseGroup* groupNode = m_caseFactory->createGroup(name, description, children);
   1601 	shaderNodeList.push_back(groupNode);
   1602 }
   1603 
   1604 void ShaderParser::parseImport (vector<tcu::TestNode*>& shaderNodeList)
   1605 {
   1606 	std::string	importFileName;
   1607 
   1608 	advanceToken(TOKEN_IMPORT);
   1609 
   1610 	assumeToken(TOKEN_STRING);
   1611 	importFileName = parseStringLiteral(m_curTokenStr.c_str());
   1612 	advanceToken(TOKEN_STRING);
   1613 
   1614 	{
   1615 		ShaderParser					subParser		(m_archive, de::FilePath::join(de::FilePath(m_filename).getDirName(), importFileName).getPath(), m_caseFactory);
   1616 		const vector<tcu::TestNode*>	importedCases = subParser.parse();
   1617 
   1618 		// \todo [2015-08-03 pyry] Not exception safe
   1619 		shaderNodeList.insert(shaderNodeList.end(), importedCases.begin(), importedCases.end());
   1620 	}
   1621 }
   1622 
   1623 vector<tcu::TestNode*> ShaderParser::parse (void)
   1624 {
   1625 	const int	dataLen		= m_resource->getSize();
   1626 
   1627 	m_input.resize(dataLen+1);
   1628 	m_resource->setPosition(0);
   1629 	m_resource->read((deUint8*)&m_input[0], dataLen);
   1630 	m_input[dataLen] = '\0';
   1631 
   1632 	// Initialize parser.
   1633 	m_curPtr		= &m_input[0];
   1634 	m_curToken		= TOKEN_INVALID;
   1635 	m_curTokenStr	= "";
   1636 	advanceToken();
   1637 
   1638 	vector<tcu::TestNode*> nodeList;
   1639 
   1640 	// Parse all cases.
   1641 	PARSE_DBG(("parse()\n"));
   1642 	for (;;)
   1643 	{
   1644 		if (m_curToken == TOKEN_CASE)
   1645 			parseShaderCase(nodeList);
   1646 		else if (m_curToken == TOKEN_GROUP)
   1647 			parseShaderGroup(nodeList);
   1648 		else if (m_curToken == TOKEN_IMPORT)
   1649 			parseImport(nodeList);
   1650 		else if (m_curToken == TOKEN_EOF)
   1651 			break;
   1652 		else
   1653 			parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
   1654 	}
   1655 
   1656 	assumeToken(TOKEN_EOF);
   1657 //	printf("  parsed %d test cases.\n", caseList.size());
   1658 	return nodeList;
   1659 }
   1660 
   1661 std::vector<tcu::TestNode*> parseFile (const tcu::Archive& archive, const std::string& filename, ShaderCaseFactory* caseFactory)
   1662 {
   1663 	sl::ShaderParser	parser	(archive, filename, caseFactory);
   1664 
   1665 	return parser.parse();
   1666 }
   1667 
   1668 // Execution utilities
   1669 
   1670 static void dumpValue (tcu::TestLog& log, const Value& val, const char* storageName, int arrayNdx)
   1671 {
   1672 	const char* const	valueName		= val.name.c_str();
   1673 	const DataType		dataType		= val.type.getBasicType();
   1674 	int					scalarSize		= getDataTypeScalarSize(dataType);
   1675 	ostringstream		result;
   1676 
   1677 	result << "    " << storageName << " ";
   1678 
   1679 	result << getDataTypeName(dataType) << " " << valueName << ":";
   1680 
   1681 	if (isDataTypeScalar(dataType))
   1682 		result << " ";
   1683 	if (isDataTypeVector(dataType))
   1684 		result << " [ ";
   1685 	else if (isDataTypeMatrix(dataType))
   1686 		result << "\n";
   1687 
   1688 	if (isDataTypeScalarOrVector(dataType))
   1689 	{
   1690 		for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
   1691 		{
   1692 			int						elemNdx	= arrayNdx;
   1693 			const Value::Element&	e		= val.elements[elemNdx*scalarSize + scalarNdx];
   1694 			result << ((scalarNdx != 0) ? ", " : "");
   1695 
   1696 			if (isDataTypeFloatOrVec(dataType))
   1697 				result << e.float32;
   1698 			else if (isDataTypeIntOrIVec(dataType))
   1699 				result << e.int32;
   1700 			else if (isDataTypeUintOrUVec(dataType))
   1701 				result << (deUint32)e.int32;
   1702 			else if (isDataTypeBoolOrBVec(dataType))
   1703 				result << (e.bool32 ? "true" : "false");
   1704 		}
   1705 	}
   1706 	else if (isDataTypeMatrix(dataType))
   1707 	{
   1708 		int numRows = getDataTypeMatrixNumRows(dataType);
   1709 		int numCols = getDataTypeMatrixNumColumns(dataType);
   1710 		for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
   1711 		{
   1712 			result << "       [ ";
   1713 			for (int colNdx = 0; colNdx < numCols; colNdx++)
   1714 			{
   1715 				int		elemNdx = arrayNdx;
   1716 				float	v		= val.elements[elemNdx*scalarSize + rowNdx*numCols + colNdx].float32;
   1717 				result << ((colNdx==0) ? "" : ", ") << v;
   1718 			}
   1719 			result << " ]\n";
   1720 		}
   1721 	}
   1722 
   1723 	if (isDataTypeScalar(dataType))
   1724 		result << "\n";
   1725 	else if (isDataTypeVector(dataType))
   1726 		result << " ]\n";
   1727 
   1728 	log << TestLog::Message << result.str() << TestLog::EndMessage;
   1729 }
   1730 
   1731 static void dumpValues (tcu::TestLog& log, const vector<Value>& values, const char* storageName, int arrayNdx)
   1732 {
   1733 	for (size_t valNdx = 0; valNdx < values.size(); valNdx++)
   1734 		dumpValue(log, values[valNdx], storageName, arrayNdx);
   1735 }
   1736 
   1737 void dumpValues (tcu::TestLog& log, const ValueBlock& values, int arrayNdx)
   1738 {
   1739 	dumpValues(log, values.inputs,		"input",	arrayNdx);
   1740 	dumpValues(log, values.outputs,		"expected",	arrayNdx);
   1741 	dumpValues(log, values.uniforms,	"uniform",	arrayNdx);
   1742 }
   1743 
   1744 static void generateExtensionStatements (std::ostringstream& buf, const std::vector<RequiredExtension>& extensions, glu::ShaderType type)
   1745 {
   1746 	for (size_t ndx = 0; ndx < extensions.size(); ++ndx)
   1747 	{
   1748 		DE_ASSERT(extensions[ndx].effectiveStages != 0u &&
   1749 				  extensions[ndx].alternatives.size() == 1);
   1750 
   1751 		if ((extensions[ndx].effectiveStages & (1u << (deUint32)type)) != 0)
   1752 			buf << "#extension " << extensions[ndx].alternatives[0] << " : require\n";
   1753 	}
   1754 }
   1755 
   1756 // Injects #extension XXX : require lines after the last preprocessor directive in the shader code. Does not support line continuations
   1757 std::string injectExtensionRequirements (const std::string& baseCode, const std::vector<RequiredExtension>& extensions, glu::ShaderType shaderType)
   1758 {
   1759 	std::istringstream	baseCodeBuf					(baseCode);
   1760 	std::ostringstream	resultBuf;
   1761 	std::string			line;
   1762 	bool				firstNonPreprocessorLine	= true;
   1763 	std::ostringstream	extStr;
   1764 
   1765 	generateExtensionStatements(extStr, extensions, shaderType);
   1766 
   1767 	// skip if no requirements
   1768 	if (extStr.str().empty())
   1769 		return baseCode;
   1770 
   1771 	while (std::getline(baseCodeBuf, line))
   1772 	{
   1773 		// begins with '#'?
   1774 		const std::string::size_type	firstNonWhitespace		= line.find_first_not_of("\t ");
   1775 		const bool						isPreprocessorDirective	= (firstNonWhitespace != std::string::npos && line.at(firstNonWhitespace) == '#');
   1776 
   1777 		// Inject #extensions
   1778 		if (!isPreprocessorDirective && firstNonPreprocessorLine)
   1779 		{
   1780 			firstNonPreprocessorLine = false;
   1781 			resultBuf << extStr.str();
   1782 		}
   1783 
   1784 		resultBuf << line << "\n";
   1785 	}
   1786 
   1787 	return resultBuf.str();
   1788 }
   1789 
   1790 void genCompareFunctions (ostringstream& stream, const ValueBlock& valueBlock, bool useFloatTypes)
   1791 {
   1792 	bool cmpTypeFound[TYPE_LAST];
   1793 	for (int i = 0; i < TYPE_LAST; i++)
   1794 		cmpTypeFound[i] = false;
   1795 
   1796 	for (size_t valueNdx = 0; valueNdx < valueBlock.outputs.size(); valueNdx++)
   1797 	{
   1798 		const Value& val = valueBlock.outputs[valueNdx];
   1799 		cmpTypeFound[(size_t)val.type.getBasicType()] = true;
   1800 	}
   1801 
   1802 	if (useFloatTypes)
   1803 	{
   1804 		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n";
   1805 		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n";
   1806 		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n";
   1807 		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n";
   1808 		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";
   1809 		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n";
   1810 		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n";
   1811 		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n";
   1812 		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";
   1813 		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n";
   1814 		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n";
   1815 		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n";
   1816 	}
   1817 	else
   1818 	{
   1819 		if (cmpTypeFound[TYPE_BOOL])		stream << "bool isOk (bool a, bool b)   { return (a == b); }\n";
   1820 		if (cmpTypeFound[TYPE_BOOL_VEC2])	stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n";
   1821 		if (cmpTypeFound[TYPE_BOOL_VEC3])	stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n";
   1822 		if (cmpTypeFound[TYPE_BOOL_VEC4])	stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n";
   1823 		if (cmpTypeFound[TYPE_INT])			stream << "bool isOk (int a, int b)     { return (a == b); }\n";
   1824 		if (cmpTypeFound[TYPE_INT_VEC2])	stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n";
   1825 		if (cmpTypeFound[TYPE_INT_VEC3])	stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n";
   1826 		if (cmpTypeFound[TYPE_INT_VEC4])	stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n";
   1827 		if (cmpTypeFound[TYPE_UINT])		stream << "bool isOk (uint a, uint b)   { return (a == b); }\n";
   1828 		if (cmpTypeFound[TYPE_UINT_VEC2])	stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n";
   1829 		if (cmpTypeFound[TYPE_UINT_VEC3])	stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n";
   1830 		if (cmpTypeFound[TYPE_UINT_VEC4])	stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n";
   1831 	}
   1832 
   1833 	if (cmpTypeFound[TYPE_FLOAT])		stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n";
   1834 	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";
   1835 	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";
   1836 	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";
   1837 
   1838 	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";
   1839 	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";
   1840 	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";
   1841 	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";
   1842 	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";
   1843 	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";
   1844 	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";
   1845 	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";
   1846 	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";
   1847 }
   1848 
   1849 } // sl
   1850 } // glu
   1851