Home | History | Annotate | Download | only in performance
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 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 compilation performance tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3pShaderCompilationCases.hpp"
     25 #include "tcuTestLog.hpp"
     26 #include "tcuVector.hpp"
     27 #include "tcuMatrix.hpp"
     28 #include "tcuTextureUtil.hpp"
     29 #include "tcuPlatform.hpp"
     30 #include "tcuCommandLine.hpp"
     31 #include "tcuRenderTarget.hpp"
     32 #include "tcuCPUWarmup.hpp"
     33 #include "tcuStringTemplate.hpp"
     34 #include "gluTexture.hpp"
     35 #include "gluPixelTransfer.hpp"
     36 #include "gluRenderContext.hpp"
     37 #include "deStringUtil.hpp"
     38 #include "deRandom.hpp"
     39 #include "deClock.h"
     40 #include "deMath.h"
     41 
     42 #include "glwEnums.hpp"
     43 #include "glwFunctions.hpp"
     44 
     45 #include <map>
     46 #include <algorithm>
     47 #include <limits>
     48 #include <iomanip>
     49 
     50 using tcu::TestLog;
     51 using tcu::Vec3;
     52 using tcu::Vec4;
     53 using tcu::Mat3;
     54 using tcu::Mat4;
     55 using std::string;
     56 using std::vector;
     57 using namespace glw; // GL types
     58 
     59 namespace deqp
     60 {
     61 
     62 namespace gles3
     63 {
     64 
     65 namespace Performance
     66 {
     67 
     68 static const bool	WARMUP_CPU_AT_BEGINNING_OF_CASE					= false;
     69 static const bool	WARMUP_CPU_BEFORE_EACH_MEASUREMENT				= true;
     70 
     71 static const int	MAX_VIEWPORT_WIDTH								= 64;
     72 static const int	MAX_VIEWPORT_HEIGHT								= 64;
     73 
     74 static const int	DEFAULT_MINIMUM_MEASUREMENT_COUNT				= 15;
     75 static const float	RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD	= 0.05f;
     76 
     77 // Texture size for the light shader and texture lookup shader cases.
     78 static const int	TEXTURE_WIDTH									= 64;
     79 static const int	TEXTURE_HEIGHT									= 64;
     80 
     81 template <typename T>
     82 inline string toStringWithPadding (T value, int minLength)
     83 {
     84 	std::ostringstream s;
     85 	s << std::setfill('0') << std::setw(minLength) << value;
     86 	return s.str();
     87 }
     88 
     89 // Add some whitespace and comments to str. They should depend on uniqueNumber.
     90 static string strWithWhiteSpaceAndComments (const string& str, deUint32 uniqueNumber)
     91 {
     92 	string res("");
     93 
     94 	// Find the first newline.
     95 	int firstLineEndNdx = 0;
     96 	while (firstLineEndNdx < (int)str.size() && str[firstLineEndNdx] != '\n')
     97 	{
     98 		res += str[firstLineEndNdx];
     99 		firstLineEndNdx++;
    100 	}
    101 	res += '\n';
    102 	DE_ASSERT(firstLineEndNdx < (int)str.size());
    103 
    104 	// Add the whitespaces and comments just after the first line.
    105 
    106 	de::Random		rnd		(uniqueNumber);
    107 	int				numWS	= rnd.getInt(10, 20);
    108 
    109 	for (int i = 0; i < numWS; i++)
    110 		res += " \t\n"[rnd.getInt(0, 2)];
    111 
    112 	res += "/* unique comment " + de::toString(uniqueNumber) + " */\n";
    113 	res += "// unique comment " + de::toString(uniqueNumber) + "\n";
    114 
    115 	for (int i = 0; i < numWS; i++)
    116 		res += " \t\n"[rnd.getInt(0, 2)];
    117 
    118 	// Add the rest of the string.
    119 	res.append(&str.c_str()[firstLineEndNdx + 1]);
    120 
    121 	return res;
    122 }
    123 
    124 //! Helper for computing relative magnitudes while avoiding division by zero.
    125 static float hackySafeRelativeResult (float x, float y)
    126 {
    127 	// \note A possible case is that x is standard deviation, and y is average
    128 	//		 (or similarly for median or some such). So, if y is 0, that
    129 	//		 probably means that x is also 0(ish) (because in practice we're
    130 	//		 dealing with non-negative values, in which case an average of 0
    131 	//		 implies that the samples are all 0 - note that the same isn't
    132 	//		 strictly true for things like median) so a relative result of 0
    133 	//		 wouldn't be that far from the truth.
    134 	return y == 0.0f ? 0.0f : x/y;
    135 }
    136 
    137 template <typename T>
    138 static float vectorFloatAverage (const vector<T>& v)
    139 {
    140 	DE_ASSERT(!v.empty());
    141 	float result = 0.0f;
    142 	for (int i = 0; i < (int)v.size(); i++)
    143 		result += (float)v[i];
    144 	return result / (float)v.size();
    145 }
    146 
    147 template <typename T>
    148 static float vectorFloatMedian (const vector<T>& v)
    149 {
    150 	DE_ASSERT(!v.empty());
    151 	vector<T> temp = v;
    152 	std::sort(temp.begin(), temp.end());
    153 	return temp.size() % 2 == 0
    154 		   ? 0.5f * ((float)temp[temp.size()/2-1] + (float)temp[temp.size()/2])
    155 		   : (float)temp[temp.size()/2];
    156 }
    157 
    158 template <typename T>
    159 static float vectorFloatMinimum (const vector<T>& v)
    160 {
    161 	DE_ASSERT(!v.empty());
    162 	return (float)*std::min_element(v.begin(), v.end());
    163 }
    164 
    165 template <typename T>
    166 static float vectorFloatMaximum (const vector<T>& v)
    167 {
    168 	DE_ASSERT(!v.empty());
    169 	return (float)*std::max_element(v.begin(), v.end());
    170 }
    171 
    172 template <typename T>
    173 static float vectorFloatStandardDeviation (const vector<T>& v)
    174 {
    175 	float average	= vectorFloatAverage(v);
    176 	float result	= 0.0f;
    177 	for (int i = 0; i < (int)v.size(); i++)
    178 	{
    179 		float d = (float)v[i] - average;
    180 		result += d*d;
    181 	}
    182 	return deFloatSqrt(result/(float)v.size());
    183 }
    184 
    185 template <typename T>
    186 static float vectorFloatRelativeStandardDeviation (const vector<T>& v)
    187 {
    188 	return hackySafeRelativeResult(vectorFloatStandardDeviation(v), vectorFloatAverage(v));
    189 }
    190 
    191 template <typename T>
    192 static float vectorFloatMedianAbsoluteDeviation (const vector<T>& v)
    193 {
    194 	float			median				= vectorFloatMedian(v);
    195 	vector<float>	absoluteDeviations	(v.size());
    196 
    197 	for (int i = 0; i < (int)v.size(); i++)
    198 		absoluteDeviations[i] = deFloatAbs((float)v[i] - median);
    199 
    200 	return vectorFloatMedian(absoluteDeviations);
    201 }
    202 
    203 template <typename T>
    204 static float vectorFloatRelativeMedianAbsoluteDeviation (const vector<T>& v)
    205 {
    206 	return hackySafeRelativeResult(vectorFloatMedianAbsoluteDeviation(v), vectorFloatMedian(v));
    207 }
    208 
    209 template <typename T>
    210 static float vectorFloatMaximumMinusMinimum (const vector<T>& v)
    211 {
    212 	return vectorFloatMaximum(v) - vectorFloatMinimum(v);
    213 }
    214 
    215 template <typename T>
    216 static float vectorFloatRelativeMaximumMinusMinimum (const vector<T>& v)
    217 {
    218 	return hackySafeRelativeResult(vectorFloatMaximumMinusMinimum(v), vectorFloatMaximum(v));
    219 }
    220 
    221 template <typename T>
    222 static vector<T> vectorLowestPercentage (const vector<T>& v, float factor)
    223 {
    224 	DE_ASSERT(0.0f < factor && factor <= 1.0f);
    225 
    226 	int			targetSize	= (int)(deFloatCeil(factor*(float)v.size()));
    227 	vector<T>	temp		= v;
    228 	std::sort(temp.begin(), temp.end());
    229 
    230 	while ((int)temp.size() > targetSize)
    231 		temp.pop_back();
    232 
    233 	return temp;
    234 }
    235 
    236 template <typename T>
    237 static float vectorFloatFirstQuartile (const vector<T>& v)
    238 {
    239 	return vectorFloatMedian(vectorLowestPercentage(v, 0.5f));
    240 }
    241 
    242 // Helper function for combining 4 tcu::Vec4's into one tcu::Vector<float, 16>.
    243 static tcu::Vector<float, 16> combineVec4ToVec16 (const Vec4& a0, const Vec4& a1, const Vec4& a2, const Vec4& a3)
    244 {
    245 	tcu::Vector<float, 16> result;
    246 
    247 	for (int vecNdx = 0; vecNdx < 4; vecNdx++)
    248 	{
    249 		const Vec4& srcVec = vecNdx == 0 ? a0 : vecNdx == 1 ? a1 : vecNdx == 2 ? a2 : a3;
    250 		for (int i = 0; i < 4; i++)
    251 			result[vecNdx*4 + i] = srcVec[i];
    252 	}
    253 
    254 	return result;
    255 }
    256 
    257 // Helper function for extending an n-sized (n <= 16) vector to a 16-sized vector (padded with zeros).
    258 template <int Size>
    259 static tcu::Vector<float, 16> vecTo16 (const tcu::Vector<float, Size>& vec)
    260 {
    261 	DE_STATIC_ASSERT(Size <= 16);
    262 
    263 	tcu::Vector<float, 16> res(0.0f);
    264 
    265 	for (int i = 0; i < Size; i++)
    266 		res[i] = vec[i];
    267 
    268 	return res;
    269 }
    270 
    271 // Helper function for extending an n-sized (n <= 16) array to a 16-sized vector (padded with zeros).
    272 template <int Size>
    273 static tcu::Vector<float, 16> arrTo16 (const tcu::Array<float, Size>& arr)
    274 {
    275 	DE_STATIC_ASSERT(Size <= 16);
    276 
    277 	tcu::Vector<float, 16> res(0.0f);
    278 
    279 	for(int i = 0; i < Size; i++)
    280 		res[i] = arr[i];
    281 
    282 	return res;
    283 }
    284 
    285 static string getShaderInfoLog (const glw::Functions& gl, deUint32 shader)
    286 {
    287 	string			result;
    288 	int				infoLogLen = 0;
    289 	vector<char>	infoLogBuf;
    290 
    291 	gl.getShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
    292 	infoLogBuf.resize(infoLogLen + 1);
    293 	gl.getShaderInfoLog(shader, infoLogLen + 1, DE_NULL, &infoLogBuf[0]);
    294 	result = &infoLogBuf[0];
    295 
    296 	return result;
    297 }
    298 
    299 static string getProgramInfoLog (const glw::Functions& gl, deUint32 program)
    300 {
    301 	string			result;
    302 	int				infoLogLen = 0;
    303 	vector<char>	infoLogBuf;
    304 
    305 	gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
    306 	infoLogBuf.resize(infoLogLen + 1);
    307 	gl.getProgramInfoLog(program, infoLogLen + 1, DE_NULL, &infoLogBuf[0]);
    308 	result = &infoLogBuf[0];
    309 
    310 	return result;
    311 }
    312 
    313 enum LightType
    314 {
    315 	LIGHT_DIRECTIONAL = 0,
    316 	LIGHT_POINT,
    317 
    318 	LIGHT_LAST,
    319 };
    320 
    321 enum LoopType
    322 {
    323 	LOOP_TYPE_STATIC = 0,
    324 	LOOP_TYPE_UNIFORM,
    325 	LOOP_TYPE_DYNAMIC,
    326 
    327 	LOOP_LAST
    328 };
    329 
    330 // For texture lookup cases: which texture lookups are inside a conditional statement.
    331 enum ConditionalUsage
    332 {
    333 	CONDITIONAL_USAGE_NONE = 0,		// No conditional statements.
    334 	CONDITIONAL_USAGE_FIRST_HALF,	// First numLookUps/2 lookups are inside a conditional statement.
    335 	CONDITIONAL_USAGE_EVERY_OTHER,	// First, third etc. lookups are inside conditional statements.
    336 
    337 	CONDITIONAL_USAGE_LAST
    338 };
    339 
    340 enum ConditionalType
    341 {
    342 	CONDITIONAL_TYPE_STATIC = 0,
    343 	CONDITIONAL_TYPE_UNIFORM,
    344 	CONDITIONAL_TYPE_DYNAMIC,
    345 
    346 	CONDITIONAL_TYPE_LAST
    347 };
    348 
    349 // For the invalid shader compilation tests; what kind of invalidity a shader shall contain.
    350 enum ShaderValidity
    351 {
    352 	SHADER_VALIDITY_VALID = 0,
    353 	SHADER_VALIDITY_INVALID_CHAR,
    354 	SHADER_VALIDITY_SEMANTIC_ERROR,
    355 
    356 	SHADER_VALIDITY_LAST
    357 };
    358 
    359 class ShaderCompilerCase : public TestCase
    360 {
    361 public:
    362 	struct AttribSpec
    363 	{
    364 		string					name;
    365 		tcu::Vector<float, 16>	value;
    366 
    367 		AttribSpec (const string& n, const tcu::Vector<float, 16>& v) : name(n), value(v) {}
    368 	};
    369 
    370 	struct UniformSpec
    371 	{
    372 		enum Type
    373 		{
    374 			TYPE_FLOAT = 0,
    375 			TYPE_VEC2,
    376 			TYPE_VEC3,
    377 			TYPE_VEC4,
    378 
    379 			TYPE_MAT3,
    380 			TYPE_MAT4,
    381 
    382 			TYPE_TEXTURE_UNIT,
    383 
    384 			TYPE_LAST
    385 		};
    386 
    387 		string					name;
    388 		Type					type;
    389 		tcu::Vector<float, 16>	value;
    390 
    391 		UniformSpec (const string& n, Type t, float v)							: name(n), type(t), value(v) {}
    392 		UniformSpec (const string& n, Type t, const tcu::Vector<float, 16>& v)	: name(n), type(t), value(v) {}
    393 	};
    394 
    395 								ShaderCompilerCase		(Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments);
    396 								~ShaderCompilerCase		(void);
    397 
    398 	void						init					(void);
    399 
    400 	IterateResult				iterate					(void);
    401 
    402 protected:
    403 	struct ProgramContext
    404 	{
    405 		string					vertShaderSource;
    406 		string					fragShaderSource;
    407 		vector<AttribSpec>		vertexAttributes;
    408 		vector<UniformSpec>		uniforms;
    409 	};
    410 
    411 	deUint32					getSpecializationID		(int measurementNdx) const;		// Return an ID that depends on the case ID, current measurement index and time; used to specialize attribute names etc. (avoid shader caching).
    412 	virtual ProgramContext		generateShaderData		(int measurementNdx) const = 0;	// Generate shader sources and inputs. Attribute etc. names depend on above name specialization.
    413 
    414 private:
    415 	struct Measurement
    416 	{
    417 		// \note All times in microseconds. 32-bit integers would probably suffice (would need over an hour of test case runtime to overflow), but better safe than sorry.
    418 		deInt64 sourceSetTime;
    419 		deInt64 vertexCompileTime;
    420 		deInt64 fragmentCompileTime;
    421 		deInt64 programLinkTime;
    422 		deInt64 firstInputSetTime;
    423 		deInt64 firstDrawTime;
    424 
    425 		deInt64 secondInputSetTime;
    426 		deInt64 secondDrawTime;
    427 
    428 		deInt64 firstPhase				(void) const { return sourceSetTime + vertexCompileTime + fragmentCompileTime + programLinkTime + firstInputSetTime + firstDrawTime; }
    429 		deInt64 secondPhase				(void) const { return secondInputSetTime + secondDrawTime; }
    430 
    431 		deInt64 totalTimeWithoutDraw	(void) const { return firstPhase() - de::min(secondPhase(), firstInputSetTime + firstDrawTime); }
    432 
    433 		Measurement (deInt64 sourceSetTime_,
    434 					 deInt64 vertexCompileTime_,
    435 					 deInt64 fragmentCompileTime_,
    436 					 deInt64 programLinkTime_,
    437 					 deInt64 firstInputSetTime_,
    438 					 deInt64 firstDrawTime_,
    439 					 deInt64 secondInputSetTime_,
    440 					 deInt64 secondDrawTime_)
    441 			: sourceSetTime			(sourceSetTime_)
    442 			, vertexCompileTime		(vertexCompileTime_)
    443 			, fragmentCompileTime	(fragmentCompileTime_)
    444 			, programLinkTime		(programLinkTime_)
    445 			, firstInputSetTime		(firstInputSetTime_)
    446 			, firstDrawTime			(firstDrawTime_)
    447 			, secondInputSetTime	(secondInputSetTime_)
    448 			, secondDrawTime		(secondDrawTime_)
    449 		{
    450 		}
    451 	};
    452 
    453 	struct ShadersAndProgram
    454 	{
    455 		deUint32 vertShader;
    456 		deUint32 fragShader;
    457 		deUint32 program;
    458 	};
    459 
    460 	struct Logs
    461 	{
    462 		string vert;
    463 		string frag;
    464 		string link;
    465 	};
    466 
    467 	struct BuildInfo
    468 	{
    469 		bool vertCompileSuccess;
    470 		bool fragCompileSuccess;
    471 		bool linkSuccess;
    472 
    473 		Logs logs;
    474 	};
    475 
    476 	ShadersAndProgram			createShadersAndProgram		(void) const;
    477 	void						setShaderSources			(deUint32 vertShader, deUint32 fragShader, const ProgramContext&) const;
    478 	bool						compileShader				(deUint32 shader) const;
    479 	bool						linkAndUseProgram			(deUint32 program) const;
    480 	void						setShaderInputs				(deUint32 program, const ProgramContext&) const;							// Set attribute pointers and uniforms.
    481 	void						draw						(void) const;																// Clear, draw and finish.
    482 	void						cleanup						(const ShadersAndProgram&, const ProgramContext&, bool linkSuccess) const;	// Do GL deinitializations.
    483 
    484 	Logs						getLogs						(const ShadersAndProgram&) const;
    485 	void						logProgramData				(const BuildInfo&, const ProgramContext&) const;
    486 	bool						goodEnoughMeasurements		(const vector<Measurement>& measurements) const;
    487 
    488 	int							m_viewportWidth;
    489 	int							m_viewportHeight;
    490 
    491 	bool						m_avoidCache;				// If true, avoid caching between measurements as well (and not only between test cases).
    492 	bool						m_addWhitespaceAndComments;	// If true, add random whitespace and comments to the source (good caching should ignore those).
    493 	deUint32					m_startHash;				// A hash from case id and time, at the time of construction.
    494 
    495 	int							m_minimumMeasurementCount;
    496 	int							m_maximumMeasurementCount;
    497 };
    498 
    499 class ShaderCompilerLightCase : public ShaderCompilerCase
    500 {
    501 public:
    502 							ShaderCompilerLightCase		(Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, int numLights, LightType lightType);
    503 							~ShaderCompilerLightCase	(void);
    504 
    505 	void					init						(void);
    506 	void					deinit						(void);
    507 
    508 protected:
    509 	ProgramContext			generateShaderData			(int measurementNdx) const;
    510 
    511 private:
    512 	int						m_numLights;
    513 	bool					m_isVertexCase;
    514 	LightType				m_lightType;
    515 	glu::Texture2D*			m_texture;
    516 };
    517 
    518 class ShaderCompilerTextureCase : public ShaderCompilerCase
    519 {
    520 public:
    521 									ShaderCompilerTextureCase	(Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType);
    522 									~ShaderCompilerTextureCase	(void);
    523 
    524 	void							init						(void);
    525 	void							deinit						(void);
    526 
    527 protected:
    528 	ProgramContext					generateShaderData			(int measurementNdx) const;
    529 
    530 private:
    531 	int								m_numLookups;
    532 	vector<glu::Texture2D*>			m_textures;
    533 	ConditionalUsage				m_conditionalUsage;
    534 	ConditionalType					m_conditionalType;
    535 };
    536 
    537 class ShaderCompilerLoopCase : public ShaderCompilerCase
    538 {
    539 public:
    540 						ShaderCompilerLoopCase	(Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, LoopType type, int numLoopIterations, int nestingDepth);
    541 						~ShaderCompilerLoopCase	(void);
    542 
    543 protected:
    544 	ProgramContext		generateShaderData		(int measurementNdx) const;
    545 
    546 private:
    547 	int					m_numLoopIterations;
    548 	int					m_nestingDepth;
    549 	bool				m_isVertexCase;
    550 	LoopType			m_type;
    551 };
    552 
    553 class ShaderCompilerOperCase : public ShaderCompilerCase
    554 {
    555 public:
    556 						ShaderCompilerOperCase	(Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, const char* oper, int numOperations);
    557 						~ShaderCompilerOperCase	(void);
    558 
    559 protected:
    560 	ProgramContext		generateShaderData		(int measurementNdx) const;
    561 
    562 private:
    563 	string				m_oper;
    564 	int					m_numOperations;
    565 	bool				m_isVertexCase;
    566 };
    567 
    568 class ShaderCompilerMandelbrotCase : public ShaderCompilerCase
    569 {
    570 public:
    571 						ShaderCompilerMandelbrotCase	(Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numFractalIterations);
    572 						~ShaderCompilerMandelbrotCase	(void);
    573 
    574 protected:
    575 	ProgramContext		generateShaderData				(int measurementNdx) const;
    576 
    577 private:
    578 	int					m_numFractalIterations;
    579 };
    580 
    581 class InvalidShaderCompilerCase : public TestCase
    582 {
    583 public:
    584 	// \note Similar to the ShaderValidity enum, but doesn't have a VALID type.
    585 	enum InvalidityType
    586 	{
    587 		INVALIDITY_INVALID_CHAR = 0,
    588 		INVALIDITY_SEMANTIC_ERROR,
    589 
    590 		INVALIDITY_LAST
    591 	};
    592 
    593 						InvalidShaderCompilerCase	(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType);
    594 						~InvalidShaderCompilerCase	(void);
    595 
    596 	IterateResult		iterate						(void);
    597 
    598 protected:
    599 	struct ProgramContext
    600 	{
    601 		string vertShaderSource;
    602 		string fragShaderSource;
    603 	};
    604 
    605 	deUint32				getSpecializationID		(int measurementNdx) const;			// Return an ID that depends on the case ID, current measurement index and time; used to specialize attribute names etc. (avoid shader caching).
    606 	virtual ProgramContext	generateShaderSources	(int measurementNdx) const = 0;		// Generate shader sources. Attribute etc. names depend on above name specialization.
    607 
    608 	InvalidityType			m_invalidityType;
    609 
    610 private:
    611 	struct Measurement
    612 	{
    613 		// \note All times in microseconds. 32-bit integers would probably suffice (would need over an hour of test case runtime to overflow), but better safe than sorry.
    614 		deInt64 sourceSetTime;
    615 		deInt64 vertexCompileTime;
    616 		deInt64 fragmentCompileTime;
    617 
    618 		deInt64 totalTime (void) const { return sourceSetTime + vertexCompileTime + fragmentCompileTime; }
    619 
    620 		Measurement (deInt64 sourceSetTime_,
    621 					 deInt64 vertexCompileTime_,
    622 					 deInt64 fragmentCompileTime_)
    623 			: sourceSetTime			(sourceSetTime_)
    624 			, vertexCompileTime		(vertexCompileTime_)
    625 			, fragmentCompileTime	(fragmentCompileTime_)
    626 		{
    627 		}
    628 	};
    629 
    630 	struct Shaders
    631 	{
    632 		deUint32 vertShader;
    633 		deUint32 fragShader;
    634 	};
    635 
    636 	struct Logs
    637 	{
    638 		string vert;
    639 		string frag;
    640 	};
    641 
    642 	struct BuildInfo
    643 	{
    644 		bool vertCompileSuccess;
    645 		bool fragCompileSuccess;
    646 
    647 		Logs logs;
    648 	};
    649 
    650 	Shaders						createShaders			(void) const;
    651 	void						setShaderSources		(const Shaders&, const ProgramContext&) const;
    652 	bool						compileShader			(deUint32 shader) const;
    653 	void						cleanup					(const Shaders&) const;
    654 
    655 	Logs						getLogs					(const Shaders&) const;
    656 	void						logProgramData			(const BuildInfo&, const ProgramContext&) const;
    657 	bool						goodEnoughMeasurements	(const vector<Measurement>& measurements) const;
    658 
    659 	deUint32					m_startHash; // A hash from case id and time, at the time of construction.
    660 
    661 	int							m_minimumMeasurementCount;
    662 	int							m_maximumMeasurementCount;
    663 };
    664 
    665 class InvalidShaderCompilerLightCase : public InvalidShaderCompilerCase
    666 {
    667 public:
    668 							InvalidShaderCompilerLightCase	(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, int numLights, LightType lightType);
    669 							~InvalidShaderCompilerLightCase	(void);
    670 
    671 protected:
    672 	ProgramContext			generateShaderSources			(int measurementNdx) const;
    673 
    674 private:
    675 	bool					m_isVertexCase;
    676 	int						m_numLights;
    677 	LightType				m_lightType;
    678 };
    679 
    680 class InvalidShaderCompilerTextureCase : public InvalidShaderCompilerCase
    681 {
    682 public:
    683 							InvalidShaderCompilerTextureCase	(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType);
    684 							~InvalidShaderCompilerTextureCase	(void);
    685 
    686 protected:
    687 	ProgramContext			generateShaderSources				(int measurementNdx) const;
    688 
    689 private:
    690 	int						m_numLookups;
    691 	ConditionalUsage		m_conditionalUsage;
    692 	ConditionalType			m_conditionalType;
    693 };
    694 
    695 class InvalidShaderCompilerLoopCase : public InvalidShaderCompilerCase
    696 {
    697 public:
    698 						InvalidShaderCompilerLoopCase	(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool , LoopType type, int numLoopIterations, int nestingDepth);
    699 						~InvalidShaderCompilerLoopCase	(void);
    700 
    701 protected:
    702 	ProgramContext		generateShaderSources			(int measurementNdx) const;
    703 
    704 private:
    705 	bool				m_isVertexCase;
    706 	int					m_numLoopIterations;
    707 	int					m_nestingDepth;
    708 	LoopType			m_type;
    709 };
    710 
    711 class InvalidShaderCompilerOperCase : public InvalidShaderCompilerCase
    712 {
    713 public:
    714 						InvalidShaderCompilerOperCase	(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, const char* oper, int numOperations);
    715 						~InvalidShaderCompilerOperCase	(void);
    716 
    717 protected:
    718 	ProgramContext		generateShaderSources			(int measurementNdx) const;
    719 
    720 private:
    721 	bool				m_isVertexCase;
    722 	string				m_oper;
    723 	int					m_numOperations;
    724 };
    725 
    726 class InvalidShaderCompilerMandelbrotCase : public InvalidShaderCompilerCase
    727 {
    728 public:
    729 						InvalidShaderCompilerMandelbrotCase		(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numFractalIterations);
    730 						~InvalidShaderCompilerMandelbrotCase	(void);
    731 
    732 protected:
    733 	ProgramContext		generateShaderSources					(int measurementNdx) const;
    734 
    735 private:
    736 	int					m_numFractalIterations;
    737 };
    738 
    739 static string getNameSpecialization (deUint32 id)
    740 {
    741 	return "_" + toStringWithPadding(id, 10);
    742 }
    743 
    744 // Substitute StringTemplate parameters for attribute/uniform/varying name and constant expression specialization as well as possible shader compilation error causes.
    745 static string specializeShaderSource (const string& shaderSourceTemplate, deUint32 cacheAvoidanceID, ShaderValidity validity)
    746 {
    747 	std::map<string, string> params;
    748 	params["NAME_SPEC"]			= getNameSpecialization(cacheAvoidanceID);
    749 	params["FLOAT01"]			= de::floatToString((float)cacheAvoidanceID / (float)(std::numeric_limits<deUint32>::max()), 6);
    750 	params["SEMANTIC_ERROR"]	= validity != SHADER_VALIDITY_SEMANTIC_ERROR	? "" : "\tfloat invalid = sin(1.0, 2.0);\n";
    751 	params["INVALID_CHAR"]		= validity != SHADER_VALIDITY_INVALID_CHAR		? "" : "@\n"; // \note Some implementations crash when the invalid character is the last character in the source, so use newline.
    752 
    753 	return tcu::StringTemplate(shaderSourceTemplate).specialize(params);
    754 }
    755 
    756 // Function for generating the vertex shader of a (directional or point) light case.
    757 static string lightVertexTemplate (int numLights, bool isVertexCase, LightType lightType)
    758 {
    759 	string resultTemplate;
    760 
    761 	resultTemplate +=
    762 		"#version 300 es\n"
    763 		"in highp vec4 a_position${NAME_SPEC};\n"
    764 		"in mediump vec3 a_normal${NAME_SPEC};\n"
    765 		"in mediump vec4 a_texCoord0${NAME_SPEC};\n"
    766 		"uniform mediump vec3 u_material_ambientColor${NAME_SPEC};\n"
    767 		"uniform mediump vec4 u_material_diffuseColor${NAME_SPEC};\n"
    768 		"uniform mediump vec3 u_material_emissiveColor${NAME_SPEC};\n"
    769 		"uniform mediump vec3 u_material_specularColor${NAME_SPEC};\n"
    770 		"uniform mediump float u_material_shininess${NAME_SPEC};\n";
    771 
    772 	for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
    773 	{
    774 		string ndxStr = de::toString(lightNdx);
    775 
    776 		resultTemplate +=
    777 			"uniform mediump vec3 u_light" + ndxStr + "_color${NAME_SPEC};\n"
    778 			"uniform mediump vec3 u_light" + ndxStr + "_direction${NAME_SPEC};\n";
    779 
    780 		if (lightType == LIGHT_POINT)
    781 			resultTemplate +=
    782 				"uniform mediump vec4 u_light" + ndxStr + "_position${NAME_SPEC};\n"
    783 				"uniform mediump float u_light" + ndxStr + "_constantAttenuation${NAME_SPEC};\n"
    784 				"uniform mediump float u_light" + ndxStr + "_linearAttenuation${NAME_SPEC};\n"
    785 				"uniform mediump float u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC};\n";
    786 	}
    787 
    788 	resultTemplate +=
    789 		"uniform highp mat4 u_mvpMatrix${NAME_SPEC};\n"
    790 		"uniform highp mat4 u_modelViewMatrix${NAME_SPEC};\n"
    791 		"uniform mediump mat3 u_normalMatrix${NAME_SPEC};\n"
    792 		"uniform mediump mat4 u_texCoordMatrix0${NAME_SPEC};\n"
    793 		"out mediump vec4 v_color${NAME_SPEC};\n"
    794 		"out mediump vec2 v_texCoord0${NAME_SPEC};\n";
    795 
    796 	if (!isVertexCase)
    797 	{
    798 		resultTemplate += "out mediump vec3 v_eyeNormal${NAME_SPEC};\n";
    799 
    800 		if (lightType == LIGHT_POINT)
    801 			resultTemplate +=
    802 				"out mediump vec3 v_directionToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n"
    803 				"out mediump float v_distanceToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n";
    804 	}
    805 
    806 	resultTemplate +=
    807 		"mediump vec3 direction (mediump vec4 from, mediump vec4 to)\n"
    808 		"{\n"
    809 		"	return vec3(to.xyz * from.w - from.xyz * to.w);\n"
    810 		"}\n"
    811 		"\n"
    812 		"mediump vec3 computeLighting (\n"
    813 		"	mediump vec3 directionToLight,\n"
    814 		"	mediump vec3 halfVector,\n"
    815 		"	mediump vec3 normal,\n"
    816 		"	mediump vec3 lightColor,\n"
    817 		"	mediump vec3 diffuseColor,\n"
    818 		"	mediump vec3 specularColor,\n"
    819 		"	mediump float shininess)\n"
    820 		"{\n"
    821 		"	mediump float normalDotDirection  = max(dot(normal, directionToLight), 0.0);\n"
    822 		"	mediump vec3  color               = normalDotDirection * diffuseColor * lightColor;\n"
    823 		"\n"
    824 		"	if (normalDotDirection != 0.0)\n"
    825 		"		color += pow(max(dot(normal, halfVector), 0.0), shininess) * specularColor * lightColor;\n"
    826 		"\n"
    827 		"	return color;\n"
    828 		"}\n"
    829 		"\n";
    830 
    831 	if (lightType == LIGHT_POINT)
    832 		resultTemplate +=
    833 			"mediump float computeDistanceAttenuation (mediump float distToLight, mediump float constAtt, mediump float linearAtt, mediump float quadraticAtt)\n"
    834 			"{\n"
    835 			"	return 1.0 / (constAtt + linearAtt * distToLight + quadraticAtt * distToLight * distToLight);\n"
    836 			"}\n"
    837 			"\n";
    838 
    839 	resultTemplate +=
    840 		"void main (void)\n"
    841 		"{\n"
    842 		"	highp vec4 position = a_position${NAME_SPEC};\n"
    843 		"	highp vec3 normal = a_normal${NAME_SPEC};\n"
    844 		"	gl_Position = u_mvpMatrix${NAME_SPEC} * position * (0.95 + 0.05*${FLOAT01});\n"
    845 		"	v_texCoord0${NAME_SPEC} = (u_texCoordMatrix0${NAME_SPEC} * a_texCoord0${NAME_SPEC}).xy;\n"
    846 		"	mediump vec4 color = vec4(u_material_emissiveColor${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.a);\n"
    847 		"\n"
    848 		"	highp vec4 eyePosition = u_modelViewMatrix${NAME_SPEC} * position;\n"
    849 		"	mediump vec3 eyeNormal = normalize(u_normalMatrix${NAME_SPEC} * normal);\n";
    850 
    851 	if (!isVertexCase)
    852 		resultTemplate += "\tv_eyeNormal${NAME_SPEC} = eyeNormal;\n";
    853 
    854 	resultTemplate += "\n";
    855 
    856 	for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
    857 	{
    858 		string ndxStr = de::toString(lightNdx);
    859 
    860 		resultTemplate +=
    861 			"	/* Light " + ndxStr + " */\n";
    862 
    863 		if (lightType == LIGHT_POINT)
    864 		{
    865 			resultTemplate +=
    866 				"	mediump float distanceToLight" + ndxStr + " = distance(eyePosition, u_light" + ndxStr + "_position${NAME_SPEC});\n"
    867 				"	mediump vec3 directionToLight" + ndxStr + " = normalize(direction(eyePosition, u_light" + ndxStr + "_position${NAME_SPEC}));\n";
    868 
    869 			if (isVertexCase)
    870 				resultTemplate +=
    871 					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
    872 					"	color.rgb += computeLighting(directionToLight" + ndxStr + ", halfVector" + ndxStr + ", eyeNormal, u_light" + ndxStr + "_color${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.rgb, "
    873 					"u_material_specularColor${NAME_SPEC}, u_material_shininess${NAME_SPEC}) * computeDistanceAttenuation(distanceToLight" + ndxStr + ", u_light" + ndxStr + "_constantAttenuation${NAME_SPEC}, "
    874 					"u_light" + ndxStr + "_linearAttenuation${NAME_SPEC}, u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC});\n";
    875 			else
    876 				resultTemplate +=
    877 					"	v_directionToLight${NAME_SPEC}[" + ndxStr + "] = directionToLight" + ndxStr + ";\n"
    878 					"	v_distanceToLight${NAME_SPEC}[" + ndxStr + "]  = distanceToLight" + ndxStr + ";\n";
    879 		}
    880 		else if (lightType == LIGHT_DIRECTIONAL)
    881 		{
    882 			if (isVertexCase)
    883 				resultTemplate +=
    884 					"	mediump vec3 directionToLight" + ndxStr + " = -u_light" + ndxStr + "_direction${NAME_SPEC};\n"
    885 					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
    886 					"	color.rgb += computeLighting(directionToLight" + ndxStr + ", halfVector" + ndxStr + ", eyeNormal, u_light" + ndxStr + "_color${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.rgb, u_material_specularColor${NAME_SPEC}, u_material_shininess${NAME_SPEC});\n";
    887 		}
    888 		else
    889 			DE_ASSERT(DE_FALSE);
    890 
    891 		resultTemplate += "\n";
    892 	}
    893 
    894 	resultTemplate +=
    895 		"	v_color${NAME_SPEC} = color;\n"
    896 		"${SEMANTIC_ERROR}"
    897 		"}\n"
    898 		"${INVALID_CHAR}";
    899 
    900 	return resultTemplate;
    901 }
    902 
    903 // Function for generating the fragment shader of a (directional or point) light case.
    904 static string lightFragmentTemplate (int numLights, bool isVertexCase, LightType lightType)
    905 {
    906 	string resultTemplate;
    907 
    908 	resultTemplate +=
    909 		"#version 300 es\n"
    910 		"layout(location = 0) out mediump vec4 o_color;\n";
    911 
    912 	if (!isVertexCase)
    913 	{
    914 		resultTemplate +=
    915 			"uniform mediump vec3 u_material_ambientColor${NAME_SPEC};\n"
    916 			"uniform mediump vec4 u_material_diffuseColor${NAME_SPEC};\n"
    917 			"uniform mediump vec3 u_material_emissiveColor${NAME_SPEC};\n"
    918 			"uniform mediump vec3 u_material_specularColor${NAME_SPEC};\n"
    919 			"uniform mediump float u_material_shininess${NAME_SPEC};\n";
    920 
    921 		for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
    922 		{
    923 			string ndxStr = de::toString(lightNdx);
    924 
    925 			resultTemplate +=
    926 				"uniform mediump vec3 u_light" + ndxStr + "_color${NAME_SPEC};\n"
    927 				"uniform mediump vec3 u_light" + ndxStr + "_direction${NAME_SPEC};\n";
    928 
    929 			if (lightType == LIGHT_POINT)
    930 				resultTemplate +=
    931 					"uniform mediump vec4 u_light" + ndxStr + "_position${NAME_SPEC};\n"
    932 					"uniform mediump float u_light" + ndxStr + "_constantAttenuation${NAME_SPEC};\n"
    933 					"uniform mediump float u_light" + ndxStr + "_linearAttenuation${NAME_SPEC};\n"
    934 					"uniform mediump float u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC};\n";
    935 		}
    936 	}
    937 
    938 	resultTemplate +=
    939 		"uniform sampler2D u_sampler0${NAME_SPEC};\n"
    940 		"in mediump vec4 v_color${NAME_SPEC};\n"
    941 		"in mediump vec2 v_texCoord0${NAME_SPEC};\n";
    942 
    943 	if (!isVertexCase)
    944 	{
    945 		resultTemplate +=
    946 			"in mediump vec3 v_eyeNormal${NAME_SPEC};\n";
    947 
    948 		if (lightType == LIGHT_POINT)
    949 			resultTemplate +=
    950 				"in mediump vec3 v_directionToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n"
    951 				"in mediump float v_distanceToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n";
    952 
    953 		resultTemplate +=
    954 			"mediump vec3 direction (mediump vec4 from, mediump vec4 to)\n"
    955 			"{\n"
    956 			"	return vec3(to.xyz * from.w - from.xyz * to.w);\n"
    957 			"}\n"
    958 			"\n";
    959 
    960 		resultTemplate +=
    961 			"mediump vec3 computeLighting (\n"
    962 			"	mediump vec3 directionToLight,\n"
    963 			"	mediump vec3 halfVector,\n"
    964 			"	mediump vec3 normal,\n"
    965 			"	mediump vec3 lightColor,\n"
    966 			"	mediump vec3 diffuseColor,\n"
    967 			"	mediump vec3 specularColor,\n"
    968 			"	mediump float shininess)\n"
    969 			"{\n"
    970 			"	mediump float normalDotDirection  = max(dot(normal, directionToLight), 0.0);\n"
    971 			"	mediump vec3  color               = normalDotDirection * diffuseColor * lightColor;\n"
    972 			"\n"
    973 			"	if (normalDotDirection != 0.0)\n"
    974 			"		color += pow(max(dot(normal, halfVector), 0.0), shininess) * specularColor * lightColor;\n"
    975 			"\n"
    976 			"	return color;\n"
    977 			"}\n"
    978 			"\n";
    979 
    980 		if (lightType == LIGHT_POINT)
    981 			resultTemplate +=
    982 				"mediump float computeDistanceAttenuation (mediump float distToLight, mediump float constAtt, mediump float linearAtt, mediump float quadraticAtt)\n"
    983 				"{\n"
    984 				"	return 1.0 / (constAtt + linearAtt * distToLight + quadraticAtt * distToLight * distToLight);\n"
    985 				"}\n"
    986 				"\n";
    987 	}
    988 
    989 	resultTemplate +=
    990 		"void main (void)\n"
    991 		"{\n"
    992 		"	mediump vec2 texCoord0 = v_texCoord0${NAME_SPEC}.xy;\n"
    993 		"	mediump vec4 color = v_color${NAME_SPEC};\n";
    994 
    995 	if (!isVertexCase)
    996 	{
    997 		resultTemplate +=
    998 			"	mediump vec3 eyeNormal = normalize(v_eyeNormal${NAME_SPEC});\n"
    999 			"\n";
   1000 
   1001 		for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
   1002 		{
   1003 			string ndxStr = de::toString(lightNdx);
   1004 
   1005 			resultTemplate +=
   1006 				"	/* Light " + ndxStr + " */\n";
   1007 
   1008 			if (lightType == LIGHT_POINT)
   1009 				resultTemplate +=
   1010 					"	mediump vec3 directionToLight" + ndxStr + " = normalize(v_directionToLight${NAME_SPEC}[" + ndxStr + "]);\n"
   1011 					"	mediump float distanceToLight" + ndxStr + " = v_distanceToLight${NAME_SPEC}[" + ndxStr + "];\n"
   1012 					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
   1013 					"	color.rgb += computeLighting(directionToLight" + ndxStr + ", halfVector" + ndxStr + ", eyeNormal, u_light" + ndxStr + "_color${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.rgb, "
   1014 					"u_material_specularColor${NAME_SPEC}, u_material_shininess${NAME_SPEC}) * computeDistanceAttenuation(distanceToLight" + ndxStr + ", u_light" + ndxStr + "_constantAttenuation${NAME_SPEC}, "
   1015 					"u_light" + ndxStr + "_linearAttenuation${NAME_SPEC}, u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC});\n"
   1016 					"\n";
   1017 			else if (lightType == LIGHT_DIRECTIONAL)
   1018 				resultTemplate +=
   1019 					"	mediump vec3 directionToLight" + ndxStr + " = -u_light" + ndxStr + "_direction${NAME_SPEC};\n"
   1020 					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
   1021 					"	color.rgb += computeLighting(directionToLight" + ndxStr + ", halfVector" + ndxStr + ", eyeNormal, u_light" + ndxStr + "_color${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.rgb, u_material_specularColor${NAME_SPEC}, u_material_shininess${NAME_SPEC});\n"
   1022 					"\n";
   1023 			else
   1024 				DE_ASSERT(DE_FALSE);
   1025 		}
   1026 	}
   1027 
   1028 	resultTemplate +=
   1029 		"	color *= texture(u_sampler0${NAME_SPEC}, texCoord0);\n"
   1030 		"	o_color = color + ${FLOAT01};\n"
   1031 		"${SEMANTIC_ERROR}"
   1032 		"}\n"
   1033 		"${INVALID_CHAR}";
   1034 
   1035 	return resultTemplate;
   1036 }
   1037 
   1038 // Function for generating the shader attributes of a (directional or point) light case.
   1039 static vector<ShaderCompilerCase::AttribSpec> lightShaderAttributes (const string& nameSpecialization)
   1040 {
   1041 	vector<ShaderCompilerCase::AttribSpec> result;
   1042 
   1043 	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
   1044 													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
   1045 																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
   1046 																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
   1047 																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
   1048 
   1049 	result.push_back(ShaderCompilerCase::AttribSpec("a_normal" + nameSpecialization,
   1050 													combineVec4ToVec16(Vec4(0.0f, 0.0f, -1.0f, 0.0f),
   1051 																	   Vec4(0.0f, 0.0f, -1.0f, 0.0f),
   1052 																	   Vec4(0.0f, 0.0f, -1.0f, 0.0f),
   1053 																	   Vec4(0.0f, 0.0f, -1.0f, 0.0f))));
   1054 
   1055 	result.push_back(ShaderCompilerCase::AttribSpec("a_texCoord0" + nameSpecialization,
   1056 													combineVec4ToVec16(Vec4(0.0f, 0.0f, 0.0f, 0.0f),
   1057 																	   Vec4(1.0f, 0.0f, 0.0f, 0.0f),
   1058 																	   Vec4(0.0f, 1.0f, 0.0f, 0.0f),
   1059 																	   Vec4(1.0f, 1.0f, 0.0f, 0.0f))));
   1060 
   1061 	return result;
   1062 }
   1063 
   1064 // Function for generating the shader uniforms of a (directional or point) light case.
   1065 static vector<ShaderCompilerCase::UniformSpec> lightShaderUniforms (const string& nameSpecialization, int numLights, LightType lightType)
   1066 {
   1067 	vector<ShaderCompilerCase::UniformSpec> result;
   1068 
   1069 	result.push_back(ShaderCompilerCase::UniformSpec("u_material_ambientColor" + nameSpecialization,
   1070 													 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
   1071 													 vecTo16(Vec3(0.5f, 0.7f, 0.9f))));
   1072 
   1073 	result.push_back(ShaderCompilerCase::UniformSpec("u_material_diffuseColor" + nameSpecialization,
   1074 													 ShaderCompilerCase:: UniformSpec::TYPE_VEC4,
   1075 													 vecTo16(Vec4(0.3f, 0.4f, 0.5f, 1.0f))));
   1076 
   1077 	result.push_back(ShaderCompilerCase::UniformSpec("u_material_emissiveColor" + nameSpecialization,
   1078 													 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
   1079 													 vecTo16(Vec3(0.7f, 0.2f, 0.2f))));
   1080 
   1081 	result.push_back(ShaderCompilerCase::UniformSpec("u_material_specularColor" + nameSpecialization,
   1082 													 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
   1083 													 vecTo16(Vec3(0.2f, 0.6f, 1.0f))));
   1084 
   1085 	result.push_back(ShaderCompilerCase::UniformSpec("u_material_shininess" + nameSpecialization,
   1086 													 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
   1087 													 0.8f));
   1088 
   1089 	for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
   1090 	{
   1091 		string ndxStr = de::toString(lightNdx);
   1092 
   1093 		result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_color" + nameSpecialization,
   1094 														 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
   1095 														 vecTo16(Vec3(0.8f, 0.6f, 0.3f))));
   1096 
   1097 		result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_direction" + nameSpecialization,
   1098 														 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
   1099 														 vecTo16(Vec3(0.2f, 0.3f, 0.4f))));
   1100 
   1101 		if (lightType == LIGHT_POINT)
   1102 		{
   1103 			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_position" + nameSpecialization,
   1104 															 ShaderCompilerCase::UniformSpec::TYPE_VEC4,
   1105 															 vecTo16(Vec4(1.0f, 0.6f, 0.3f, 0.2f))));
   1106 
   1107 			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_constantAttenuation" + nameSpecialization,
   1108 															 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
   1109 															 0.6f));
   1110 
   1111 			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_linearAttenuation" + nameSpecialization,
   1112 															 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
   1113 															 0.5f));
   1114 
   1115 			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_quadraticAttenuation" + nameSpecialization,
   1116 															 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
   1117 															 0.4f));
   1118 		}
   1119 	}
   1120 
   1121 	result.push_back(ShaderCompilerCase::UniformSpec("u_mvpMatrix" + nameSpecialization,
   1122 													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
   1123 													 arrTo16(Mat4(1.0f).getColumnMajorData())));
   1124 
   1125 	result.push_back(ShaderCompilerCase::UniformSpec("u_modelViewMatrix" + nameSpecialization,
   1126 													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
   1127 													 arrTo16(Mat4(1.0f).getColumnMajorData())));
   1128 
   1129 	result.push_back(ShaderCompilerCase::UniformSpec("u_normalMatrix" + nameSpecialization,
   1130 													 ShaderCompilerCase::UniformSpec::TYPE_MAT3,
   1131 													 arrTo16(Mat3(1.0f).getColumnMajorData())));
   1132 
   1133 	result.push_back(ShaderCompilerCase::UniformSpec("u_texCoordMatrix0" + nameSpecialization,
   1134 													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
   1135 													 arrTo16(Mat4(1.0f).getColumnMajorData())));
   1136 
   1137 	result.push_back(ShaderCompilerCase::UniformSpec("u_sampler0" + nameSpecialization,
   1138 													 ShaderCompilerCase::UniformSpec::TYPE_TEXTURE_UNIT,
   1139 													 0.0f));
   1140 
   1141 	return result;
   1142 }
   1143 
   1144 // Function for generating a vertex shader with a for loop.
   1145 static string loopVertexTemplate (LoopType type, bool isVertexCase, int numLoopIterations, int nestingDepth)
   1146 {
   1147 	string resultTemplate;
   1148 	string loopBound		= type == LOOP_TYPE_STATIC	? de::toString(numLoopIterations)
   1149 							: type == LOOP_TYPE_UNIFORM	? "int(u_loopBound${NAME_SPEC})"
   1150 							: type == LOOP_TYPE_DYNAMIC	? "int(a_loopBound${NAME_SPEC})"
   1151 							: "";
   1152 
   1153 	DE_ASSERT(!loopBound.empty());
   1154 
   1155 	resultTemplate +=
   1156 		"#version 300 es\n"
   1157 		"in highp vec4 a_position${NAME_SPEC};\n";
   1158 
   1159 	if (type == LOOP_TYPE_DYNAMIC)
   1160 		resultTemplate +=
   1161 			"in mediump float a_loopBound${NAME_SPEC};\n";
   1162 
   1163 	resultTemplate +=
   1164 		"in mediump vec4 a_value${NAME_SPEC};\n"
   1165 		"out mediump vec4 v_value${NAME_SPEC};\n";
   1166 
   1167 	if (isVertexCase)
   1168 	{
   1169 		if (type == LOOP_TYPE_UNIFORM)
   1170 			resultTemplate += "uniform mediump float u_loopBound${NAME_SPEC};\n";
   1171 
   1172 		resultTemplate +=
   1173 			"\n"
   1174 			"void main()\n"
   1175 			"{\n"
   1176 			"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
   1177 			"	mediump vec4 value = a_value${NAME_SPEC};\n";
   1178 
   1179 		for (int i = 0; i < nestingDepth; i++)
   1180 		{
   1181 			string iterName = "i" + de::toString(i);
   1182 			resultTemplate += string(i + 1, '\t') + "for (int " + iterName + " = 0; " + iterName + " < " + loopBound + "; " + iterName + "++)\n";
   1183 		}
   1184 
   1185 		resultTemplate += string(nestingDepth + 1, '\t') + "value *= a_value${NAME_SPEC};\n";
   1186 
   1187 		resultTemplate +=
   1188 			"	v_value${NAME_SPEC} = value;\n";
   1189 	}
   1190 	else
   1191 	{
   1192 		if (type == LOOP_TYPE_DYNAMIC)
   1193 			resultTemplate +=
   1194 				"out mediump float v_loopBound${NAME_SPEC};\n";
   1195 
   1196 		resultTemplate +=
   1197 			"\n"
   1198 			"void main()\n"
   1199 			"{\n"
   1200 			"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
   1201 			"	v_value${NAME_SPEC} = a_value${NAME_SPEC};\n";
   1202 
   1203 		if (type == LOOP_TYPE_DYNAMIC)
   1204 			resultTemplate +=
   1205 				"	v_loopBound${NAME_SPEC} = a_loopBound${NAME_SPEC};\n";
   1206 	}
   1207 
   1208 	resultTemplate +=
   1209 		"${SEMANTIC_ERROR}"
   1210 		"}\n"
   1211 		"${INVALID_CHAR}";
   1212 
   1213 	return resultTemplate;
   1214 }
   1215 
   1216 // Function for generating a fragment shader with a for loop.
   1217 static string loopFragmentTemplate (LoopType type, bool isVertexCase, int numLoopIterations, int nestingDepth)
   1218 {
   1219 	string resultTemplate;
   1220 	string loopBound		= type == LOOP_TYPE_STATIC	? de::toString(numLoopIterations)
   1221 							: type == LOOP_TYPE_UNIFORM	? "int(u_loopBound${NAME_SPEC})"
   1222 							: type == LOOP_TYPE_DYNAMIC	? "int(v_loopBound${NAME_SPEC})"
   1223 							: "";
   1224 
   1225 	DE_ASSERT(!loopBound.empty());
   1226 
   1227 	resultTemplate +=
   1228 		"#version 300 es\n"
   1229 		"layout(location = 0) out mediump vec4 o_color;\n"
   1230 		"in mediump vec4 v_value${NAME_SPEC};\n";
   1231 
   1232 	if (!isVertexCase)
   1233 	{
   1234 		if (type == LOOP_TYPE_DYNAMIC)
   1235 			resultTemplate +=
   1236 				"in mediump float v_loopBound${NAME_SPEC};\n";
   1237 		else if (type == LOOP_TYPE_UNIFORM)
   1238 			resultTemplate +=
   1239 				"uniform mediump float u_loopBound${NAME_SPEC};\n";
   1240 
   1241 		resultTemplate +=
   1242 			"\n"
   1243 			"void main()\n"
   1244 			"{\n"
   1245 			"	mediump vec4 value = v_value${NAME_SPEC};\n";
   1246 
   1247 		for (int i = 0; i < nestingDepth; i++)
   1248 		{
   1249 			string iterName = "i" + de::toString(i);
   1250 			resultTemplate += string(i + 1, '\t') + "for (int " + iterName + " = 0; " + iterName + " < " + loopBound + "; " + iterName + "++)\n";
   1251 		}
   1252 
   1253 		resultTemplate += string(nestingDepth + 1, '\t') + "value *= v_value${NAME_SPEC};\n";
   1254 
   1255 		resultTemplate +=
   1256 			"	o_color = value + ${FLOAT01};\n";
   1257 	}
   1258 	else
   1259 		resultTemplate +=
   1260 			"\n"
   1261 			"void main()\n"
   1262 			"{\n"
   1263 			"	o_color = v_value${NAME_SPEC} + ${FLOAT01};\n";
   1264 
   1265 	resultTemplate +=
   1266 		"${SEMANTIC_ERROR}"
   1267 		"}\n"
   1268 		"${INVALID_CHAR}";
   1269 
   1270 	return resultTemplate;
   1271 }
   1272 
   1273 // Function for generating the shader attributes for a loop case.
   1274 static vector<ShaderCompilerCase::AttribSpec> loopShaderAttributes (const string& nameSpecialization, LoopType type, int numLoopIterations)
   1275 {
   1276 	vector<ShaderCompilerCase::AttribSpec> result;
   1277 
   1278 	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
   1279 													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
   1280 																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
   1281 																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
   1282 																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
   1283 
   1284 	result.push_back(ShaderCompilerCase::AttribSpec("a_value" + nameSpecialization,
   1285 													combineVec4ToVec16(Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
   1286 																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
   1287 																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
   1288 																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f))));
   1289 
   1290 	if (type == LOOP_TYPE_DYNAMIC)
   1291 		result.push_back(ShaderCompilerCase::AttribSpec("a_loopBound" + nameSpecialization,
   1292 														combineVec4ToVec16(Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f),
   1293 																		   Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f),
   1294 																		   Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f),
   1295 																		   Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f))));
   1296 
   1297 	return result;
   1298 }
   1299 
   1300 static vector<ShaderCompilerCase::UniformSpec> loopShaderUniforms (const string& nameSpecialization, LoopType type, int numLoopIterations)
   1301 {
   1302 	vector<ShaderCompilerCase::UniformSpec> result;
   1303 
   1304 	if (type == LOOP_TYPE_UNIFORM)
   1305 		result.push_back(ShaderCompilerCase::UniformSpec("u_loopBound" + nameSpecialization,
   1306 														 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
   1307 														 (float)numLoopIterations));
   1308 
   1309 	return result;
   1310 }
   1311 
   1312 // Function for generating the shader attributes for a case with only one attribute value in addition to the position attribute.
   1313 static vector<ShaderCompilerCase::AttribSpec> singleValueShaderAttributes (const string& nameSpecialization)
   1314 {
   1315 	vector<ShaderCompilerCase::AttribSpec> result;
   1316 
   1317 	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
   1318 													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
   1319 																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
   1320 																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
   1321 																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
   1322 
   1323 	result.push_back(ShaderCompilerCase::AttribSpec("a_value" + nameSpecialization,
   1324 													combineVec4ToVec16(Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
   1325 																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
   1326 																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
   1327 																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f))));
   1328 
   1329 	return result;
   1330 }
   1331 
   1332 // Function for generating a vertex shader with a binary operation chain.
   1333 static string binaryOpVertexTemplate (int numOperations, const char* op)
   1334 {
   1335 	string resultTemplate;
   1336 
   1337 	resultTemplate +=
   1338 		"#version 300 es\n"
   1339 		"in highp vec4 a_position${NAME_SPEC};\n"
   1340 		"in mediump vec4 a_value${NAME_SPEC};\n"
   1341 		"out mediump vec4 v_value${NAME_SPEC};\n"
   1342 		"\n"
   1343 		"void main()\n"
   1344 		"{\n"
   1345 		"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
   1346 		"	mediump vec4 value = ";
   1347 
   1348 	for (int i = 0; i < numOperations; i++)
   1349 		resultTemplate += string(i > 0 ? op : "") + "a_value${NAME_SPEC}";
   1350 
   1351 	resultTemplate +=
   1352 		";\n"
   1353 		"	v_value${NAME_SPEC} = value;\n"
   1354 		"${SEMANTIC_ERROR}"
   1355 		"}\n"
   1356 		"${INVALID_CHAR}";
   1357 
   1358 	return resultTemplate;
   1359 }
   1360 
   1361 // Function for generating a fragment shader with a binary operation chain.
   1362 static string binaryOpFragmentTemplate (int numOperations, const char* op)
   1363 {
   1364 	string resultTemplate;
   1365 
   1366 	resultTemplate +=
   1367 		"#version 300 es\n"
   1368 		"layout(location = 0) out mediump vec4 o_color;\n"
   1369 		"in mediump vec4 v_value${NAME_SPEC};\n"
   1370 		"\n"
   1371 		"void main()\n"
   1372 		"{\n"
   1373 		"	mediump vec4 value = ";
   1374 
   1375 	for (int i = 0; i < numOperations; i++)
   1376 		resultTemplate += string(i > 0 ? op : "") + "v_value${NAME_SPEC}";
   1377 
   1378 	resultTemplate +=
   1379 		";\n"
   1380 		"	o_color = value + ${FLOAT01};\n"
   1381 		"${SEMANTIC_ERROR}"
   1382 		"}\n"
   1383 		"${INVALID_CHAR}";
   1384 
   1385 	return resultTemplate;
   1386 }
   1387 
   1388 // Function for generating a vertex that takes one attribute in addition to position and just passes it to the fragment shader as a varying.
   1389 static string singleVaryingVertexTemplate (void)
   1390 {
   1391 	const char* resultTemplate =
   1392 		"#version 300 es\n"
   1393 		"in highp vec4 a_position${NAME_SPEC};\n"
   1394 		"in mediump vec4 a_value${NAME_SPEC};\n"
   1395 		"out mediump vec4 v_value${NAME_SPEC};\n"
   1396 		"\n"
   1397 		"void main()\n"
   1398 		"{\n"
   1399 		"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
   1400 		"	v_value${NAME_SPEC} = a_value${NAME_SPEC};\n"
   1401 		"${SEMANTIC_ERROR}"
   1402 		"}\n"
   1403 		"${INVALID_CHAR}";
   1404 
   1405 	return resultTemplate;
   1406 }
   1407 
   1408 // Function for generating a fragment shader that takes a single varying and uses it as the color.
   1409 static string singleVaryingFragmentTemplate (void)
   1410 {
   1411 	const char* resultTemplate =
   1412 		"#version 300 es\n"
   1413 		"layout(location = 0) out mediump vec4 o_color;\n"
   1414 		"in mediump vec4 v_value${NAME_SPEC};\n"
   1415 		"\n"
   1416 		"void main()\n"
   1417 		"{\n"
   1418 		"	o_color = v_value${NAME_SPEC} + ${FLOAT01};\n"
   1419 		"${SEMANTIC_ERROR}"
   1420 		"}\n"
   1421 		"${INVALID_CHAR}";
   1422 
   1423 	return resultTemplate;
   1424 }
   1425 
   1426 // Function for generating the vertex shader of a texture lookup case.
   1427 static string textureLookupVertexTemplate (ConditionalUsage conditionalUsage, ConditionalType conditionalType)
   1428 {
   1429 	string	resultTemplate;
   1430 	bool	conditionVaryingNeeded = conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_DYNAMIC;
   1431 
   1432 	resultTemplate +=
   1433 		"#version 300 es\n"
   1434 		"in highp vec4 a_position${NAME_SPEC};\n"
   1435 		"in mediump vec2 a_coords${NAME_SPEC};\n"
   1436 		"out mediump vec2 v_coords${NAME_SPEC};\n";
   1437 
   1438 	if (conditionVaryingNeeded)
   1439 		resultTemplate +=
   1440 			"in mediump float a_condition${NAME_SPEC};\n"
   1441 			"out mediump float v_condition${NAME_SPEC};\n";
   1442 
   1443 	resultTemplate +=
   1444 		"\n"
   1445 		"void main()\n"
   1446 		"{\n"
   1447 		"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
   1448 		"	v_coords${NAME_SPEC} = a_coords${NAME_SPEC};\n";
   1449 
   1450 	if (conditionVaryingNeeded)
   1451 		resultTemplate +=
   1452 			"	v_condition${NAME_SPEC} = a_condition${NAME_SPEC};\n";
   1453 
   1454 	resultTemplate +=
   1455 		"${SEMANTIC_ERROR}"
   1456 		"}\n"
   1457 		"${INVALID_CHAR}";
   1458 
   1459 	return resultTemplate;
   1460 }
   1461 
   1462 // Function for generating the fragment shader of a texture lookup case.
   1463 static string textureLookupFragmentTemplate (int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
   1464 {
   1465 	string resultTemplate;
   1466 
   1467 	resultTemplate +=
   1468 		"#version 300 es\n"
   1469 		"layout(location = 0) out mediump vec4 o_color;\n"
   1470 		"in mediump vec2 v_coords${NAME_SPEC};\n";
   1471 
   1472 	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_DYNAMIC)
   1473 		resultTemplate +=
   1474 			"in mediump float v_condition${NAME_SPEC};\n";
   1475 
   1476 	for (int i = 0; i < numLookups; i++)
   1477 		resultTemplate +=
   1478 			"uniform sampler2D u_sampler" + de::toString(i) + "${NAME_SPEC};\n";
   1479 
   1480 	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_UNIFORM)
   1481 		resultTemplate +=
   1482 			"uniform mediump float u_condition${NAME_SPEC};\n";
   1483 
   1484 	resultTemplate +=
   1485 		"\n"
   1486 		"void main()\n"
   1487 		"{\n"
   1488 		"	mediump vec4 color = vec4(0.0);\n";
   1489 
   1490 	const char* conditionalTerm = conditionalType == CONDITIONAL_TYPE_STATIC	? "1.0 > 0.0"
   1491 								: conditionalType == CONDITIONAL_TYPE_UNIFORM	? "u_condition${NAME_SPEC} > 0.0"
   1492 								: conditionalType == CONDITIONAL_TYPE_DYNAMIC	? "v_condition${NAME_SPEC} > 0.0"
   1493 								: DE_NULL;
   1494 
   1495 	DE_ASSERT(conditionalTerm != DE_NULL);
   1496 
   1497 	if (conditionalUsage == CONDITIONAL_USAGE_FIRST_HALF)
   1498 		resultTemplate += string("") +
   1499 			"	if (" + conditionalTerm + ")\n"
   1500 			"	{\n";
   1501 
   1502 	for (int i = 0; i < numLookups; i++)
   1503 	{
   1504 		if (conditionalUsage == CONDITIONAL_USAGE_FIRST_HALF)
   1505 		{
   1506 			if (i < (numLookups + 1) / 2)
   1507 				resultTemplate += "\t";
   1508 		}
   1509 		else if (conditionalUsage == CONDITIONAL_USAGE_EVERY_OTHER)
   1510 		{
   1511 			if (i % 2 == 0)
   1512 				resultTemplate += string("") +
   1513 					"	if (" + conditionalTerm + ")\n"
   1514 					"\t";
   1515 		}
   1516 
   1517 		resultTemplate +=
   1518 			"	color += texture(u_sampler" + de::toString(i) + "${NAME_SPEC}, v_coords${NAME_SPEC});\n";
   1519 
   1520 		if (conditionalUsage == CONDITIONAL_USAGE_FIRST_HALF && i == (numLookups - 1) / 2)
   1521 			resultTemplate += "\t}\n";
   1522 	}
   1523 
   1524 	resultTemplate +=
   1525 		"	o_color = color/" + de::toString(numLookups) + ".0 + ${FLOAT01};\n" +
   1526 		"${SEMANTIC_ERROR}"
   1527 		"}\n"
   1528 		"${INVALID_CHAR}";
   1529 
   1530 	return resultTemplate;
   1531 }
   1532 
   1533 // Function for generating the shader attributes of a texture lookup case.
   1534 static vector<ShaderCompilerCase::AttribSpec> textureLookupShaderAttributes (const string& nameSpecialization, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
   1535 {
   1536 	vector<ShaderCompilerCase::AttribSpec> result;
   1537 
   1538 	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
   1539 													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
   1540 																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
   1541 																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
   1542 																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
   1543 
   1544 	result.push_back(ShaderCompilerCase::AttribSpec("a_coords" + nameSpecialization,
   1545 													combineVec4ToVec16(Vec4(0.0f, 0.0f, 0.0f, 0.0f),
   1546 																	   Vec4(0.0f, 1.0f, 0.0f, 0.0f),
   1547 																	   Vec4(1.0f, 0.0f, 0.0f, 0.0f),
   1548 																	   Vec4(1.0f, 1.0f, 0.0f, 0.0f))));
   1549 
   1550 	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_DYNAMIC)
   1551 		result.push_back(ShaderCompilerCase::AttribSpec("a_condition" + nameSpecialization,
   1552 														combineVec4ToVec16(Vec4(1.0f), Vec4(1.0f), Vec4(1.0f), Vec4(1.0f))));
   1553 
   1554 	return result;
   1555 }
   1556 
   1557 // Function for generating the shader uniforms of a texture lookup case.
   1558 static vector<ShaderCompilerCase::UniformSpec> textureLookupShaderUniforms (const string& nameSpecialization, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
   1559 {
   1560 	vector<ShaderCompilerCase::UniformSpec> result;
   1561 
   1562 	for (int i = 0; i < numLookups; i++)
   1563 		result.push_back(ShaderCompilerCase::UniformSpec("u_sampler" + de::toString(i) + nameSpecialization,
   1564 														 ShaderCompilerCase::UniformSpec::TYPE_TEXTURE_UNIT,
   1565 														 (float)i));
   1566 
   1567 	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_UNIFORM)
   1568 		result.push_back(ShaderCompilerCase::UniformSpec("u_condition" + nameSpecialization,
   1569 														 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
   1570 														 1.0f));
   1571 
   1572 	return result;
   1573 }
   1574 
   1575 static string mandelbrotVertexTemplate (void)
   1576 {
   1577 	const char* resultTemplate =
   1578 		"#version 300 es\n"
   1579 		"uniform highp mat4 u_mvp${NAME_SPEC};\n"
   1580 		"\n"
   1581 		"in highp vec4 a_vertex${NAME_SPEC};\n"
   1582 		"in highp vec4 a_coord${NAME_SPEC};\n"
   1583 		"\n"
   1584 		"out mediump vec2 v_coord${NAME_SPEC};\n"
   1585 		"\n"
   1586 		"void main(void)\n"
   1587 		"{\n"
   1588 		"	gl_Position = u_mvp${NAME_SPEC} * a_vertex${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
   1589 		"\n"
   1590 		"	float xMin = -2.0;\n"
   1591 		"	float xMax = +0.5;\n"
   1592 		"	float yMin = -1.5;\n"
   1593 		"	float yMax = +1.5;\n"
   1594 		"\n"
   1595 		"	v_coord${NAME_SPEC}.x = a_coord${NAME_SPEC}.x * (xMax - xMin) + xMin;\n"
   1596 		"	v_coord${NAME_SPEC}.y = a_coord${NAME_SPEC}.y * (yMax - yMin) + yMin;\n"
   1597 		"${SEMANTIC_ERROR}"
   1598 		"}\n"
   1599 		"${INVALID_CHAR}";
   1600 
   1601 	return resultTemplate;
   1602 }
   1603 
   1604 static string mandelbrotFragmentTemplate (int numFractalIterations)
   1605 {
   1606 	string resultTemplate =
   1607 		"#version 300 es\n"
   1608 		"layout(location = 0) out mediump vec4 o_color;\n"
   1609 		"in mediump vec2 v_coord${NAME_SPEC};\n"
   1610 		"\n"
   1611 		"precision mediump float;\n"
   1612 		"\n"
   1613 		"#define NUM_ITERS " + de::toString(numFractalIterations) + "\n"
   1614 		"\n"
   1615 		"void main (void)\n"
   1616 		"{\n"
   1617 		"	vec2 coords = v_coord${NAME_SPEC};\n"
   1618 		"	float u_limit = 2.0 * 2.0;\n"
   1619 		"	vec2 tmp = vec2(0, 0);\n"
   1620 		"	int iter;\n"
   1621 		"\n"
   1622 		"	for (iter = 0; iter < NUM_ITERS; iter++)\n"
   1623 		"	{\n"
   1624 		"		tmp = vec2((tmp.x + tmp.y) * (tmp.x - tmp.y), 2.0 * (tmp.x * tmp.y)) + coords;\n"
   1625 		"\n"
   1626 		"		if (dot(tmp, tmp) > u_limit)\n"
   1627 		"			break;\n"
   1628 		"	}\n"
   1629 		"\n"
   1630 		"	vec3 color = vec3(float(iter) * (1.0 / float(NUM_ITERS)));\n"
   1631 		"\n"
   1632 		"	o_color = vec4(color, 1.0) + ${FLOAT01};\n"
   1633 		"${SEMANTIC_ERROR}"
   1634 		"}\n"
   1635 		"${INVALID_CHAR}";
   1636 
   1637 	return resultTemplate;
   1638 }
   1639 
   1640 static vector<ShaderCompilerCase::AttribSpec> mandelbrotShaderAttributes (const string& nameSpecialization)
   1641 {
   1642 	vector<ShaderCompilerCase::AttribSpec> result;
   1643 
   1644 	result.push_back(ShaderCompilerCase::AttribSpec("a_vertex" + nameSpecialization,
   1645 													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
   1646 																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
   1647 																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
   1648 																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
   1649 
   1650 	result.push_back(ShaderCompilerCase::AttribSpec("a_coord" + nameSpecialization,
   1651 													combineVec4ToVec16(Vec4(0.0f, 0.0f, 0.0f, 1.0f),
   1652 																	   Vec4(0.0f, 1.0f, 0.0f, 1.0f),
   1653 																	   Vec4(1.0f, 0.0f, 0.0f, 1.0f),
   1654 																	   Vec4(1.0f, 1.0f, 0.0f, 1.0f))));
   1655 
   1656 	return result;
   1657 }
   1658 
   1659 static vector<ShaderCompilerCase::UniformSpec> mandelbrotShaderUniforms (const string& nameSpecialization)
   1660 {
   1661 	vector<ShaderCompilerCase::UniformSpec> result;
   1662 
   1663 	result.push_back(ShaderCompilerCase::UniformSpec("u_mvp" + nameSpecialization,
   1664 													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
   1665 													 arrTo16(Mat4(1.0f).getColumnMajorData())));
   1666 
   1667 	return result;
   1668 }
   1669 
   1670 ShaderCompilerCase::ShaderCompilerCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments)
   1671 	: TestCase								(context, tcu::NODETYPE_PERFORMANCE, name, description)
   1672 	, m_viewportWidth						(0)
   1673 	, m_viewportHeight						(0)
   1674 	, m_avoidCache							(avoidCache)
   1675 	, m_addWhitespaceAndComments			(addWhitespaceAndComments)
   1676 	, m_startHash							((deUint32)(deUint64Hash(deGetTime()) ^ deUint64Hash(deGetMicroseconds()) ^ deInt32Hash(caseID)))
   1677 {
   1678 	int cmdLineIterCount = context.getTestContext().getCommandLine().getTestIterationCount();
   1679 	m_minimumMeasurementCount = cmdLineIterCount > 0 ? cmdLineIterCount : DEFAULT_MINIMUM_MEASUREMENT_COUNT;
   1680 	m_maximumMeasurementCount = m_minimumMeasurementCount*3;
   1681 }
   1682 
   1683 ShaderCompilerCase::~ShaderCompilerCase (void)
   1684 {
   1685 }
   1686 
   1687 deUint32 ShaderCompilerCase::getSpecializationID (int measurementNdx) const
   1688 {
   1689 	if (m_avoidCache)
   1690 		return m_startHash ^ (deUint32)deInt32Hash((deInt32)measurementNdx);
   1691 	else
   1692 		return m_startHash;
   1693 }
   1694 
   1695 void ShaderCompilerCase::init (void)
   1696 {
   1697 	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
   1698 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderContext().getRenderTarget();
   1699 
   1700 	m_viewportWidth		= deMin32(MAX_VIEWPORT_WIDTH, renderTarget.getWidth());
   1701 	m_viewportHeight	= deMin32(MAX_VIEWPORT_HEIGHT, renderTarget.getHeight());
   1702 
   1703 	gl.viewport(0, 0, m_viewportWidth, m_viewportHeight);
   1704 }
   1705 
   1706 ShaderCompilerCase::ShadersAndProgram ShaderCompilerCase::createShadersAndProgram (void) const
   1707 {
   1708 	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
   1709 	ShadersAndProgram		result;
   1710 
   1711 	result.vertShader	= gl.createShader(GL_VERTEX_SHADER);
   1712 	result.fragShader	= gl.createShader(GL_FRAGMENT_SHADER);
   1713 	result.program		= gl.createProgram();
   1714 
   1715 	gl.attachShader(result.program, result.vertShader);
   1716 	gl.attachShader(result.program, result.fragShader);
   1717 
   1718 	return result;
   1719 }
   1720 
   1721 void ShaderCompilerCase::setShaderSources (deUint32 vertShader, deUint32 fragShader, const ProgramContext& progCtx) const
   1722 {
   1723 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1724 	const char* vertShaderSourceCStr = progCtx.vertShaderSource.c_str();
   1725 	const char* fragShaderSourceCStr = progCtx.fragShaderSource.c_str();
   1726 	gl.shaderSource(vertShader, 1, &vertShaderSourceCStr, DE_NULL);
   1727 	gl.shaderSource(fragShader, 1, &fragShaderSourceCStr, DE_NULL);
   1728 }
   1729 
   1730 bool ShaderCompilerCase::compileShader (deUint32 shader) const
   1731 {
   1732 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1733 	GLint status = 0;
   1734 	gl.compileShader(shader);
   1735 	gl.getShaderiv(shader, GL_COMPILE_STATUS, &status);
   1736 	return status != 0;
   1737 }
   1738 
   1739 bool ShaderCompilerCase::linkAndUseProgram (deUint32 program) const
   1740 {
   1741 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1742 	GLint linkStatus = 0;
   1743 
   1744 	gl.linkProgram(program);
   1745 	gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
   1746 
   1747 	if (linkStatus != 0)
   1748 		gl.useProgram(program);
   1749 
   1750 	return linkStatus != 0;
   1751 }
   1752 
   1753 void ShaderCompilerCase::setShaderInputs (deUint32 program, const ProgramContext& progCtx) const
   1754 {
   1755 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1756 
   1757 	// Setup attributes.
   1758 
   1759 	for (int attribNdx = 0; attribNdx < (int)progCtx.vertexAttributes.size(); attribNdx++)
   1760 	{
   1761 		int location = gl.getAttribLocation(program, progCtx.vertexAttributes[attribNdx].name.c_str());
   1762 		if (location >= 0)
   1763 		{
   1764 			gl.enableVertexAttribArray(location);
   1765 			gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, progCtx.vertexAttributes[attribNdx].value.getPtr());
   1766 		}
   1767 	}
   1768 
   1769 	// Setup uniforms.
   1770 
   1771 	for (int uniformNdx = 0; uniformNdx < (int)progCtx.uniforms.size(); uniformNdx++)
   1772 	{
   1773 		int location = gl.getUniformLocation(program, progCtx.uniforms[uniformNdx].name.c_str());
   1774 		if (location >= 0)
   1775 		{
   1776 			const float* floatPtr = progCtx.uniforms[uniformNdx].value.getPtr();
   1777 
   1778 			switch (progCtx.uniforms[uniformNdx].type)
   1779 			{
   1780 				case UniformSpec::TYPE_FLOAT:			gl.uniform1fv(location, 1, floatPtr);								break;
   1781 				case UniformSpec::TYPE_VEC2:			gl.uniform2fv(location, 1, floatPtr);								break;
   1782 				case UniformSpec::TYPE_VEC3:			gl.uniform3fv(location, 1, floatPtr);								break;
   1783 				case UniformSpec::TYPE_VEC4:			gl.uniform4fv(location, 1, floatPtr);								break;
   1784 				case UniformSpec::TYPE_MAT3:			gl.uniformMatrix3fv(location, 1, GL_FALSE, floatPtr);				break;
   1785 				case UniformSpec::TYPE_MAT4:			gl.uniformMatrix4fv(location, 1, GL_FALSE, floatPtr);				break;
   1786 				case UniformSpec::TYPE_TEXTURE_UNIT:	gl.uniform1i(location, (GLint)deRoundFloatToInt32(*floatPtr));		break;
   1787 				default:
   1788 					DE_ASSERT(DE_FALSE);
   1789 			}
   1790 		}
   1791 	}
   1792 }
   1793 
   1794 void ShaderCompilerCase::draw (void) const
   1795 {
   1796 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1797 
   1798 	static const deUint8 indices[] =
   1799 	{
   1800 		0, 1, 2,
   1801 		2, 1, 3
   1802 	};
   1803 
   1804 	gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
   1805 	gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, indices);
   1806 
   1807 	// \note Read one pixel to force compilation.
   1808 	deUint32 pixel;
   1809 	gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
   1810 }
   1811 
   1812 void ShaderCompilerCase::cleanup (const ShadersAndProgram& shadersAndProgram, const ProgramContext& progCtx, bool linkSuccess) const
   1813 {
   1814 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1815 
   1816 	if (linkSuccess)
   1817 	{
   1818 		for (int attribNdx = 0; attribNdx < (int)progCtx.vertexAttributes.size(); attribNdx++)
   1819 		{
   1820 			int location = gl.getAttribLocation(shadersAndProgram.program, progCtx.vertexAttributes[attribNdx].name.c_str());
   1821 			if (location >= 0)
   1822 				gl.disableVertexAttribArray(location);
   1823 		}
   1824 	}
   1825 
   1826 	gl.useProgram(0);
   1827 	gl.detachShader(shadersAndProgram.program, shadersAndProgram.vertShader);
   1828 	gl.detachShader(shadersAndProgram.program, shadersAndProgram.fragShader);
   1829 	gl.deleteShader(shadersAndProgram.vertShader);
   1830 	gl.deleteShader(shadersAndProgram.fragShader);
   1831 	gl.deleteProgram(shadersAndProgram.program);
   1832 }
   1833 
   1834 void ShaderCompilerCase::logProgramData (const BuildInfo& buildInfo, const ProgramContext& progCtx) const
   1835 {
   1836 	m_testCtx.getLog() << TestLog::ShaderProgram(buildInfo.linkSuccess, buildInfo.logs.link)
   1837 					   << TestLog::Shader(QP_SHADER_TYPE_VERTEX,	progCtx.vertShaderSource, buildInfo.vertCompileSuccess, buildInfo.logs.vert)
   1838 					   << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT,	progCtx.fragShaderSource, buildInfo.fragCompileSuccess, buildInfo.logs.frag)
   1839 					   << TestLog::EndShaderProgram;
   1840 }
   1841 
   1842 ShaderCompilerCase::Logs ShaderCompilerCase::getLogs (const ShadersAndProgram& shadersAndProgram) const
   1843 {
   1844 	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
   1845 	Logs					result;
   1846 
   1847 	result.vert = getShaderInfoLog(gl, shadersAndProgram.vertShader);
   1848 	result.frag = getShaderInfoLog(gl, shadersAndProgram.fragShader);
   1849 	result.link = getProgramInfoLog(gl, shadersAndProgram.program);
   1850 
   1851 	return result;
   1852 }
   1853 
   1854 bool ShaderCompilerCase::goodEnoughMeasurements (const vector<Measurement>& measurements) const
   1855 {
   1856 	if ((int)measurements.size() < m_minimumMeasurementCount)
   1857 		return false;
   1858 	else
   1859 	{
   1860 		if ((int)measurements.size() >= m_maximumMeasurementCount)
   1861 			return true;
   1862 		else
   1863 		{
   1864 			vector<deInt64> totalTimesWithoutDraw;
   1865 			for (int i = 0; i < (int)measurements.size(); i++)
   1866 				totalTimesWithoutDraw.push_back(measurements[i].totalTimeWithoutDraw());
   1867 			return vectorFloatRelativeMedianAbsoluteDeviation(vectorLowestPercentage(totalTimesWithoutDraw, 0.5f)) < RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD;
   1868 		}
   1869 	}
   1870 }
   1871 
   1872 ShaderCompilerCase::IterateResult ShaderCompilerCase::iterate (void)
   1873 {
   1874 	// Before actual measurements, compile and draw with a dummy shader to avoid possible initial slowdowns in the actual test.
   1875 	{
   1876 		deUint32		specID = getSpecializationID(0);
   1877 		ProgramContext	progCtx;
   1878 		progCtx.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, SHADER_VALIDITY_VALID);
   1879 		progCtx.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, SHADER_VALIDITY_VALID);
   1880 		progCtx.vertexAttributes = singleValueShaderAttributes(getNameSpecialization(specID));
   1881 
   1882 		ShadersAndProgram shadersAndProgram = createShadersAndProgram();
   1883 		setShaderSources(shadersAndProgram.vertShader, shadersAndProgram.fragShader, progCtx);
   1884 
   1885 		BuildInfo buildInfo;
   1886 		buildInfo.vertCompileSuccess	= compileShader(shadersAndProgram.vertShader);
   1887 		buildInfo.fragCompileSuccess	= compileShader(shadersAndProgram.fragShader);
   1888 		buildInfo.linkSuccess			= linkAndUseProgram(shadersAndProgram.program);
   1889 		if (!(buildInfo.vertCompileSuccess && buildInfo.fragCompileSuccess && buildInfo.linkSuccess))
   1890 		{
   1891 			buildInfo.logs = getLogs(shadersAndProgram);
   1892 			logProgramData(buildInfo, progCtx);
   1893 			cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
   1894 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation failed");
   1895 			return STOP;
   1896 		}
   1897 		setShaderInputs(shadersAndProgram.program, progCtx);
   1898 		draw();
   1899 		cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
   1900 	}
   1901 
   1902 	vector<Measurement>		measurements;
   1903 	// \note These are logged after measurements are done.
   1904 	ProgramContext			latestProgramContext;
   1905 	BuildInfo				latestBuildInfo;
   1906 
   1907 	if (WARMUP_CPU_AT_BEGINNING_OF_CASE)
   1908 		tcu::warmupCPU();
   1909 
   1910 	// Actual test measurements.
   1911 	while (!goodEnoughMeasurements(measurements))
   1912 	{
   1913 		// Create shaders, compile & link, set shader inputs and draw. Time measurement is done at relevant points.
   1914 		// \note Setting inputs and drawing are done twice in order to find out the time for actual compiling.
   1915 
   1916 		// \note Shader data (sources and inputs) are generated and GL shader and program objects are created before any time measurements.
   1917 		ProgramContext		progCtx				= generateShaderData((int)measurements.size());
   1918 		ShadersAndProgram	shadersAndProgram	= createShadersAndProgram();
   1919 		BuildInfo			buildInfo;
   1920 
   1921 		if (m_addWhitespaceAndComments)
   1922 		{
   1923 			const deUint32 hash = m_startHash ^ (deUint32)deInt32Hash((deInt32)measurements.size());
   1924 			progCtx.vertShaderSource = strWithWhiteSpaceAndComments(progCtx.vertShaderSource, hash);
   1925 			progCtx.fragShaderSource = strWithWhiteSpaceAndComments(progCtx.fragShaderSource, hash);
   1926 		}
   1927 
   1928 		if (WARMUP_CPU_BEFORE_EACH_MEASUREMENT)
   1929 			tcu::warmupCPU();
   1930 
   1931 		// \note Do NOT do anything too hefty between the first and last deGetMicroseconds() here (other than the gl calls); it would disturb the measurement.
   1932 
   1933 		deUint64 startTime = deGetMicroseconds();
   1934 
   1935 		setShaderSources(shadersAndProgram.vertShader, shadersAndProgram.fragShader, progCtx);
   1936 		deUint64 shaderSourceSetEndTime = deGetMicroseconds();
   1937 
   1938 		buildInfo.vertCompileSuccess = compileShader(shadersAndProgram.vertShader);
   1939 		deUint64 vertexShaderCompileEndTime = deGetMicroseconds();
   1940 
   1941 		buildInfo.fragCompileSuccess = compileShader(shadersAndProgram.fragShader);
   1942 		deUint64 fragmentShaderCompileEndTime = deGetMicroseconds();
   1943 
   1944 		buildInfo.linkSuccess = linkAndUseProgram(shadersAndProgram.program);
   1945 		deUint64 programLinkEndTime = deGetMicroseconds();
   1946 
   1947 		// Check compilation and linking status here, after all compilation and linking gl calls are made.
   1948 		if (!(buildInfo.vertCompileSuccess && buildInfo.fragCompileSuccess && buildInfo.linkSuccess))
   1949 		{
   1950 			buildInfo.logs = getLogs(shadersAndProgram);
   1951 			logProgramData(buildInfo, progCtx);
   1952 			cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
   1953 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation failed");
   1954 			return STOP;
   1955 		}
   1956 
   1957 		setShaderInputs(shadersAndProgram.program, progCtx);
   1958 		deUint64 firstShaderInputSetEndTime = deGetMicroseconds();
   1959 
   1960 		// Draw for the first time.
   1961 		draw();
   1962 		deUint64 firstDrawEndTime = deGetMicroseconds();
   1963 
   1964 		// Set inputs and draw again.
   1965 
   1966 		setShaderInputs(shadersAndProgram.program, progCtx);
   1967 		deUint64 secondShaderInputSetEndTime = deGetMicroseconds();
   1968 
   1969 		draw();
   1970 		deUint64 secondDrawEndTime = deGetMicroseconds();
   1971 
   1972 		// De-initializations (detach shaders etc.).
   1973 
   1974 		buildInfo.logs = getLogs(shadersAndProgram);
   1975 		cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
   1976 
   1977 		// Output measurement log later (after last measurement).
   1978 
   1979 		measurements.push_back(Measurement((deInt64)(shaderSourceSetEndTime			- startTime),
   1980 										   (deInt64)(vertexShaderCompileEndTime		- shaderSourceSetEndTime),
   1981 										   (deInt64)(fragmentShaderCompileEndTime	- vertexShaderCompileEndTime),
   1982 										   (deInt64)(programLinkEndTime				- fragmentShaderCompileEndTime),
   1983 										   (deInt64)(firstShaderInputSetEndTime		- programLinkEndTime),
   1984 										   (deInt64)(firstDrawEndTime				- firstShaderInputSetEndTime),
   1985 										   (deInt64)(secondShaderInputSetEndTime	- firstDrawEndTime),
   1986 										   (deInt64)(secondDrawEndTime				- secondShaderInputSetEndTime)));
   1987 
   1988 		latestBuildInfo			= buildInfo;
   1989 		latestProgramContext	= progCtx;
   1990 
   1991 		m_testCtx.touchWatchdog(); // \note Measurements may take a while in a bad case.
   1992 	}
   1993 
   1994 	// End of test case, log information about measurements.
   1995 	{
   1996 		TestLog& log = m_testCtx.getLog();
   1997 
   1998 		vector<deInt64> sourceSetTimes;
   1999 		vector<deInt64> vertexCompileTimes;
   2000 		vector<deInt64> fragmentCompileTimes;
   2001 		vector<deInt64> programLinkTimes;
   2002 		vector<deInt64> firstInputSetTimes;
   2003 		vector<deInt64> firstDrawTimes;
   2004 		vector<deInt64> secondInputTimes;
   2005 		vector<deInt64> secondDrawTimes;
   2006 		vector<deInt64> firstPhaseTimes;
   2007 		vector<deInt64> secondPhaseTimes;
   2008 		vector<deInt64> totalTimesWithoutDraw;
   2009 		vector<deInt64> specializationTimes;
   2010 
   2011 		if (!m_avoidCache)
   2012 			log << TestLog::Message << "Note: Testing cache hits, so the medians and averages exclude the first iteration." << TestLog::EndMessage;
   2013 
   2014 		log << TestLog::Message << "Note: \"Specialization time\" means first draw time minus second draw time." << TestLog::EndMessage
   2015 			<< TestLog::Message << "Note: \"Compilation time\" means the time up to (and including) linking, plus specialization time." << TestLog::EndMessage;
   2016 
   2017 		log << TestLog::Section("IterationMeasurements", "Iteration measurements of compilation and linking times");
   2018 
   2019 		DE_ASSERT((int)measurements.size() > (m_avoidCache ? 0 : 1));
   2020 
   2021 		for (int ndx = 0; ndx < (int)measurements.size(); ndx++)
   2022 		{
   2023 			const Measurement& curMeas = measurements[ndx];
   2024 
   2025 			// Subtract time of second phase (second input setup and draw) from first (from start to end of first draw).
   2026 			// \note Cap if second phase seems unreasonably high (higher than first input set and draw).
   2027 			deInt64 timeWithoutDraw		= curMeas.totalTimeWithoutDraw();
   2028 
   2029 			// Specialization time = first draw - second draw time. Again, cap at 0 if second draw was longer than first draw.
   2030 			deInt64 specializationTime	= de::max<deInt64>(0, curMeas.firstDrawTime - curMeas.secondDrawTime);
   2031 
   2032 			if (ndx > 0 || m_avoidCache) // \note When allowing cache hits, don't account for the first measurement when calculating median or average.
   2033 			{
   2034 				sourceSetTimes.push_back		(curMeas.sourceSetTime);
   2035 				vertexCompileTimes.push_back	(curMeas.vertexCompileTime);
   2036 				fragmentCompileTimes.push_back	(curMeas.fragmentCompileTime);
   2037 				programLinkTimes.push_back		(curMeas.programLinkTime);
   2038 				firstInputSetTimes.push_back	(curMeas.firstInputSetTime);
   2039 				firstDrawTimes.push_back		(curMeas.firstDrawTime);
   2040 				firstPhaseTimes.push_back		(curMeas.firstPhase());
   2041 				secondDrawTimes.push_back		(curMeas.secondDrawTime);
   2042 				secondInputTimes.push_back		(curMeas.secondInputSetTime);
   2043 				secondPhaseTimes.push_back		(curMeas.secondPhase());
   2044 				totalTimesWithoutDraw.push_back	(timeWithoutDraw);
   2045 				specializationTimes.push_back	(specializationTime);
   2046 			}
   2047 
   2048 			// Log this measurement.
   2049 			log << TestLog::Float("Measurement" + de::toString(ndx) + "CompilationTime",
   2050 								  "Measurement " + de::toString(ndx) + " compilation time",
   2051 								  "ms", QP_KEY_TAG_TIME, (float)timeWithoutDraw / 1000.0f)
   2052 				<< TestLog::Float("Measurement" + de::toString(ndx) + "SpecializationTime",
   2053 								  "Measurement " + de::toString(ndx) + " specialization time",
   2054 								  "ms", QP_KEY_TAG_TIME, (float)specializationTime / 1000.0f);
   2055 		}
   2056 
   2057 		// Log some statistics.
   2058 
   2059 		for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
   2060 		{
   2061 			bool				isEntireRange				= entireRangeOrLowestHalf == 0;
   2062 			string				statNamePrefix				= isEntireRange ? "" : "LowestHalf";
   2063 			vector<deInt64>		rangeTotalTimes				= isEntireRange ? totalTimesWithoutDraw	: vectorLowestPercentage(totalTimesWithoutDraw,	0.5f);
   2064 			vector<deInt64>		rangeSpecializationTimes	= isEntireRange ? specializationTimes	: vectorLowestPercentage(specializationTimes,	0.5f);
   2065 
   2066 #define LOG_COMPILE_SPECIALIZE_TIME_STAT(NAME, DESC, FUNC)																													\
   2067 	log << TestLog::Float(statNamePrefix + "CompilationTime" + (NAME), (DESC) + string(" of compilation time"), "ms", QP_KEY_TAG_TIME, (FUNC)(rangeTotalTimes)/1000.0f)		\
   2068 		<< TestLog::Float(statNamePrefix + "SpecializationTime" + (NAME), (DESC) + string(" of specialization time"), "ms", QP_KEY_TAG_TIME, (FUNC)(rangeSpecializationTimes)/1000.0f)
   2069 
   2070 #define LOG_COMPILE_SPECIALIZE_RELATIVE_STAT(NAME, DESC, FUNC)																										\
   2071 	log << TestLog::Float(statNamePrefix + "CompilationTime" + (NAME), (DESC) + string(" of compilation time"), "", QP_KEY_TAG_NONE, (FUNC)(rangeTotalTimes))		\
   2072 		<< TestLog::Float(statNamePrefix + "SpecializationTime" + (NAME), (DESC) + string(" of specialization time"), "", QP_KEY_TAG_NONE, (FUNC)(rangeSpecializationTimes))
   2073 
   2074 			log << TestLog::Message << "\nStatistics computed from "
   2075 									<< (isEntireRange ? "all" : "only the lowest 50%")
   2076 									<< " of the above measurements:"
   2077 									<< TestLog::EndMessage;
   2078 
   2079 			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Median",							"Median",								vectorFloatMedian);
   2080 			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Average",							"Average",								vectorFloatAverage);
   2081 			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Minimum",							"Minimum",								vectorFloatMinimum);
   2082 			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Maximum",							"Maximum",								vectorFloatMaximum);
   2083 			LOG_COMPILE_SPECIALIZE_TIME_STAT		("MedianAbsoluteDeviation",			"Median absolute deviation",			vectorFloatMedianAbsoluteDeviation);
   2084 			LOG_COMPILE_SPECIALIZE_RELATIVE_STAT	("RelativeMedianAbsoluteDeviation",	"Relative median absolute deviation",	vectorFloatRelativeMedianAbsoluteDeviation);
   2085 			LOG_COMPILE_SPECIALIZE_TIME_STAT		("StandardDeviation",				"Standard deviation",					vectorFloatStandardDeviation);
   2086 			LOG_COMPILE_SPECIALIZE_RELATIVE_STAT	("RelativeStandardDeviation",		"Relative standard deviation",			vectorFloatRelativeStandardDeviation);
   2087 			LOG_COMPILE_SPECIALIZE_TIME_STAT		("MaxMinusMin",						"Max-min",								vectorFloatMaximumMinusMinimum);
   2088 			LOG_COMPILE_SPECIALIZE_RELATIVE_STAT	("RelativeMaxMinusMin",				"Relative max-min",						vectorFloatRelativeMaximumMinusMinimum);
   2089 
   2090 #undef LOG_COMPILE_SPECIALIZE_RELATIVE_STAT
   2091 #undef LOG_COMPILE_SPECIALIZE_TIME_STAT
   2092 
   2093 			if (!isEntireRange && vectorFloatRelativeMedianAbsoluteDeviation(rangeTotalTimes) > RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD)
   2094 				log << TestLog::Message << "\nWARNING: couldn't achieve relative median absolute deviation under threshold value "
   2095 										<< RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD
   2096 										<< " for compilation time of the lowest 50% of measurements" << TestLog::EndMessage;
   2097 		}
   2098 
   2099 		log << TestLog::EndSection; // End section IterationMeasurements
   2100 
   2101 		for (int medianOrAverage = 0; medianOrAverage < 2; medianOrAverage++)
   2102 		{
   2103 			typedef float (*VecFunc)(const vector<deInt64>&);
   2104 
   2105 			bool	isMedian						= medianOrAverage == 0;
   2106 			string	singular						= isMedian ? "Median" : "Average";
   2107 			string	plural							= singular + "s";
   2108 			VecFunc func							= isMedian ? (VecFunc) vectorFloatMedian<deInt64> : (VecFunc) vectorFloatAverage<deInt64>;
   2109 
   2110 			log << TestLog::Section(plural + "PerPhase", plural + " per phase");
   2111 
   2112 			for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
   2113 			{
   2114 				bool	isEntireRange	= entireRangeOrLowestHalf == 0;
   2115 				string	statNamePrefix	= isEntireRange ? "" : "LowestHalf";
   2116 				float	rangeSizeRatio	= isEntireRange ? 1.0f : 0.5f;
   2117 
   2118 #define LOG_TIME(NAME, DESC, DATA) log << TestLog::Float(statNamePrefix + (NAME) + singular, singular + " of " + (DESC), "ms", QP_KEY_TAG_TIME, func(vectorLowestPercentage((DATA), rangeSizeRatio))/1000.0f);
   2119 
   2120 				log << TestLog::Message << (isEntireRange ? "For all measurements:" : "\nFor only the lowest 50% of the measurements:") << TestLog::EndMessage;
   2121 				LOG_TIME("ShaderSourceSetTime",			"shader source set time",			sourceSetTimes);
   2122 				LOG_TIME("VertexShaderCompileTime",		"vertex shader compile time",		vertexCompileTimes);
   2123 				LOG_TIME("FragmentShaderCompileTime",	"fragment shader compile time",		fragmentCompileTimes);
   2124 				LOG_TIME("ProgramLinkTime",				"program link time",				programLinkTimes);
   2125 				LOG_TIME("FirstShaderInputSetTime",		"first shader input set time",		firstInputSetTimes);
   2126 				LOG_TIME("FirstDrawTime",				"first draw time",					firstDrawTimes);
   2127 				LOG_TIME("SecondShaderInputSetTime",	"second shader input set time",		secondInputTimes);
   2128 				LOG_TIME("SecondDrawTime",				"second draw time",					secondDrawTimes);
   2129 
   2130 #undef LOG_TIME
   2131 			}
   2132 
   2133 			log << TestLog::EndSection;
   2134 		}
   2135 
   2136 		// Set result.
   2137 
   2138 		{
   2139 			log << TestLog::Message << "Note: test result is the first quartile (i.e. median of the lowest half of measurements) of compilation times" << TestLog::EndMessage;
   2140 			float result = vectorFloatFirstQuartile(totalTimesWithoutDraw) / 1000.0f;
   2141 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(result, 2).c_str());
   2142 		}
   2143 
   2144 		// Log shaders.
   2145 
   2146 		if (m_avoidCache || m_addWhitespaceAndComments)
   2147 		{
   2148 			string msg = "Note: the following shaders are the ones from the last iteration; ";
   2149 
   2150 			if (m_avoidCache)
   2151 				msg += "variables' names and some constant expressions";
   2152 			if (m_addWhitespaceAndComments)
   2153 				msg += string(m_avoidCache ? " as well as " : "") + "whitespace and comments";
   2154 
   2155 			msg += " differ between iterations.";
   2156 
   2157 			log << TestLog::Message << msg.c_str() << TestLog::EndMessage;
   2158 		}
   2159 
   2160 		logProgramData(latestBuildInfo, latestProgramContext);
   2161 
   2162 		return STOP;
   2163 	}
   2164 }
   2165 
   2166 ShaderCompilerLightCase::ShaderCompilerLightCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, int numLights, LightType lightType)
   2167 	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
   2168 	, m_numLights			(numLights)
   2169 	, m_isVertexCase		(isVertexCase)
   2170 	, m_lightType			(lightType)
   2171 	, m_texture				(DE_NULL)
   2172 {
   2173 }
   2174 
   2175 ShaderCompilerLightCase::~ShaderCompilerLightCase (void)
   2176 {
   2177 	ShaderCompilerLightCase::deinit();
   2178 }
   2179 
   2180 void ShaderCompilerLightCase::deinit (void)
   2181 {
   2182 	delete m_texture;
   2183 	m_texture = DE_NULL;
   2184 }
   2185 
   2186 void ShaderCompilerLightCase::init (void)
   2187 {
   2188 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2189 
   2190 	// Setup texture.
   2191 
   2192 	DE_ASSERT(m_texture == DE_NULL);
   2193 
   2194 	m_texture = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, TEXTURE_WIDTH, TEXTURE_HEIGHT);
   2195 
   2196 	tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_texture->getRefTexture().getFormat());
   2197 
   2198 	m_texture->getRefTexture().allocLevel(0);
   2199 	tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(0), fmtInfo.valueMin, fmtInfo.valueMax);
   2200 
   2201 	gl.activeTexture(GL_TEXTURE0);
   2202 	gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture());
   2203 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   2204 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   2205 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   2206 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   2207 	m_texture->upload();
   2208 
   2209 	ShaderCompilerCase::init();
   2210 }
   2211 
   2212 ShaderCompilerCase::ProgramContext ShaderCompilerLightCase::generateShaderData (int measurementNdx) const
   2213 {
   2214 	deUint32		specID		= getSpecializationID(measurementNdx);
   2215 	string			nameSpec	= getNameSpecialization(specID);
   2216 	ProgramContext	result;
   2217 
   2218 	result.vertShaderSource		= specializeShaderSource(lightVertexTemplate(m_numLights, m_isVertexCase, m_lightType), specID, SHADER_VALIDITY_VALID);
   2219 	result.fragShaderSource		= specializeShaderSource(lightFragmentTemplate(m_numLights, m_isVertexCase, m_lightType), specID, SHADER_VALIDITY_VALID);
   2220 	result.vertexAttributes		= lightShaderAttributes(nameSpec);
   2221 	result.uniforms				= lightShaderUniforms(nameSpec, m_numLights, m_lightType);
   2222 
   2223 	return result;
   2224 }
   2225 
   2226 ShaderCompilerTextureCase::ShaderCompilerTextureCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
   2227 	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
   2228 	, m_numLookups			(numLookups)
   2229 	, m_conditionalUsage	(conditionalUsage)
   2230 	, m_conditionalType		(conditionalType)
   2231 {
   2232 }
   2233 
   2234 ShaderCompilerTextureCase::~ShaderCompilerTextureCase (void)
   2235 {
   2236 	ShaderCompilerTextureCase::deinit();
   2237 }
   2238 
   2239 void ShaderCompilerTextureCase::deinit (void)
   2240 {
   2241 	for (vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
   2242 		delete *i;
   2243 	m_textures.clear();
   2244 }
   2245 
   2246 void ShaderCompilerTextureCase::init (void)
   2247 {
   2248 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2249 
   2250 	// Setup texture.
   2251 
   2252 	DE_ASSERT(m_textures.empty());
   2253 
   2254 	m_textures.reserve(m_numLookups);
   2255 
   2256 	for (int i = 0; i < m_numLookups; i++)
   2257 	{
   2258 		glu::Texture2D*			tex		= new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, TEXTURE_WIDTH, TEXTURE_HEIGHT);
   2259 		tcu::TextureFormatInfo	fmtInfo	= tcu::getTextureFormatInfo(tex->getRefTexture().getFormat());
   2260 
   2261 		tex->getRefTexture().allocLevel(0);
   2262 		tcu::fillWithComponentGradients(tex->getRefTexture().getLevel(0), fmtInfo.valueMin, fmtInfo.valueMax);
   2263 
   2264 		gl.activeTexture(GL_TEXTURE0 + i);
   2265 		gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
   2266 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   2267 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   2268 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   2269 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   2270 		tex->upload();
   2271 
   2272 		m_textures.push_back(tex);
   2273 	}
   2274 
   2275 	ShaderCompilerCase::init();
   2276 }
   2277 
   2278 ShaderCompilerCase::ProgramContext ShaderCompilerTextureCase::generateShaderData (int measurementNdx) const
   2279 {
   2280 	deUint32		specID		= getSpecializationID(measurementNdx);
   2281 	string			nameSpec	= getNameSpecialization(specID);
   2282 	ProgramContext	result;
   2283 
   2284 	result.vertShaderSource		= specializeShaderSource(textureLookupVertexTemplate(m_conditionalUsage, m_conditionalType), specID, SHADER_VALIDITY_VALID);
   2285 	result.fragShaderSource		= specializeShaderSource(textureLookupFragmentTemplate(m_numLookups, m_conditionalUsage, m_conditionalType), specID, SHADER_VALIDITY_VALID);
   2286 	result.vertexAttributes		= textureLookupShaderAttributes(nameSpec, m_conditionalUsage, m_conditionalType);
   2287 	result.uniforms				= textureLookupShaderUniforms(nameSpec, m_numLookups, m_conditionalUsage, m_conditionalType);
   2288 
   2289 	return result;
   2290 }
   2291 
   2292 ShaderCompilerLoopCase::ShaderCompilerLoopCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, LoopType type, int numLoopIterations, int nestingDepth)
   2293 	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
   2294 	, m_numLoopIterations	(numLoopIterations)
   2295 	, m_nestingDepth		(nestingDepth)
   2296 	, m_isVertexCase		(isVertexCase)
   2297 	, m_type				(type)
   2298 {
   2299 }
   2300 
   2301 ShaderCompilerLoopCase::~ShaderCompilerLoopCase (void)
   2302 {
   2303 }
   2304 
   2305 ShaderCompilerCase::ProgramContext ShaderCompilerLoopCase::generateShaderData (int measurementNdx) const
   2306 {
   2307 	deUint32		specID		= getSpecializationID(measurementNdx);
   2308 	string			nameSpec	= getNameSpecialization(specID);
   2309 	ProgramContext	result;
   2310 
   2311 	result.vertShaderSource		= specializeShaderSource(loopVertexTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, SHADER_VALIDITY_VALID);
   2312 	result.fragShaderSource		= specializeShaderSource(loopFragmentTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, SHADER_VALIDITY_VALID);
   2313 
   2314 	result.vertexAttributes		= loopShaderAttributes(nameSpec, m_type, m_numLoopIterations);
   2315 	result.uniforms				= loopShaderUniforms(nameSpec, m_type, m_numLoopIterations);
   2316 
   2317 	return result;
   2318 }
   2319 
   2320 ShaderCompilerOperCase::ShaderCompilerOperCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, const char* oper, int numOperations)
   2321 	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
   2322 	, m_oper				(oper)
   2323 	, m_numOperations		(numOperations)
   2324 	, m_isVertexCase		(isVertexCase)
   2325 {
   2326 }
   2327 
   2328 ShaderCompilerOperCase::~ShaderCompilerOperCase (void)
   2329 {
   2330 }
   2331 
   2332 ShaderCompilerCase::ProgramContext ShaderCompilerOperCase::generateShaderData (int measurementNdx) const
   2333 {
   2334 	deUint32		specID		= getSpecializationID(measurementNdx);
   2335 	string			nameSpec	= getNameSpecialization(specID);
   2336 	ProgramContext	result;
   2337 
   2338 	if (m_isVertexCase)
   2339 	{
   2340 		result.vertShaderSource = specializeShaderSource(binaryOpVertexTemplate(m_numOperations, m_oper.c_str()), specID, SHADER_VALIDITY_VALID);
   2341 		result.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, SHADER_VALIDITY_VALID);
   2342 	}
   2343 	else
   2344 	{
   2345 		result.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, SHADER_VALIDITY_VALID);
   2346 		result.fragShaderSource = specializeShaderSource(binaryOpFragmentTemplate(m_numOperations, m_oper.c_str()), specID, SHADER_VALIDITY_VALID);
   2347 	}
   2348 
   2349 	result.vertexAttributes = singleValueShaderAttributes(nameSpec);
   2350 
   2351 	result.uniforms.clear(); // No uniforms used.
   2352 
   2353 	return result;
   2354 }
   2355 
   2356 ShaderCompilerMandelbrotCase::ShaderCompilerMandelbrotCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numFractalIterations)
   2357 	: ShaderCompilerCase		(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
   2358 	, m_numFractalIterations	(numFractalIterations)
   2359 {
   2360 }
   2361 
   2362 ShaderCompilerMandelbrotCase::~ShaderCompilerMandelbrotCase (void)
   2363 {
   2364 }
   2365 
   2366 ShaderCompilerCase::ProgramContext ShaderCompilerMandelbrotCase::generateShaderData (int measurementNdx) const
   2367 {
   2368 	deUint32		specID		= getSpecializationID(measurementNdx);
   2369 	string			nameSpec	= getNameSpecialization(specID);
   2370 	ProgramContext	result;
   2371 
   2372 	result.vertShaderSource = specializeShaderSource(mandelbrotVertexTemplate(), specID, SHADER_VALIDITY_VALID);
   2373 	result.fragShaderSource = specializeShaderSource(mandelbrotFragmentTemplate(m_numFractalIterations), specID, SHADER_VALIDITY_VALID);
   2374 
   2375 	result.vertexAttributes = mandelbrotShaderAttributes(nameSpec);
   2376 	result.uniforms = mandelbrotShaderUniforms(nameSpec);
   2377 
   2378 	return result;
   2379 }
   2380 
   2381 InvalidShaderCompilerCase::InvalidShaderCompilerCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType)
   2382 	: TestCase						(context, tcu::NODETYPE_PERFORMANCE, name, description)
   2383 	, m_invalidityType				(invalidityType)
   2384 	, m_startHash					((deUint32)(deUint64Hash(deGetTime()) ^ deUint64Hash(deGetMicroseconds()) ^ deInt32Hash(caseID)))
   2385 {
   2386 	int cmdLineIterCount = context.getTestContext().getCommandLine().getTestIterationCount();
   2387 	m_minimumMeasurementCount = cmdLineIterCount > 0 ? cmdLineIterCount : DEFAULT_MINIMUM_MEASUREMENT_COUNT;
   2388 	m_maximumMeasurementCount = 3*m_minimumMeasurementCount;
   2389 }
   2390 
   2391 InvalidShaderCompilerCase::~InvalidShaderCompilerCase (void)
   2392 {
   2393 }
   2394 
   2395 deUint32 InvalidShaderCompilerCase::getSpecializationID (int measurementNdx) const
   2396 {
   2397 	return m_startHash ^ (deUint32)deInt32Hash((deInt32)measurementNdx);
   2398 }
   2399 
   2400 InvalidShaderCompilerCase::Shaders InvalidShaderCompilerCase::createShaders (void) const
   2401 {
   2402 	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
   2403 	Shaders					result;
   2404 
   2405 	result.vertShader = gl.createShader(GL_VERTEX_SHADER);
   2406 	result.fragShader = gl.createShader(GL_FRAGMENT_SHADER);
   2407 
   2408 	return result;
   2409 }
   2410 
   2411 void InvalidShaderCompilerCase::setShaderSources (const Shaders& shaders, const ProgramContext& progCtx) const
   2412 {
   2413 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2414 	const char* vertShaderSourceCStr = progCtx.vertShaderSource.c_str();
   2415 	const char* fragShaderSourceCStr = progCtx.fragShaderSource.c_str();
   2416 	gl.shaderSource(shaders.vertShader, 1, &vertShaderSourceCStr, DE_NULL);
   2417 	gl.shaderSource(shaders.fragShader, 1, &fragShaderSourceCStr, DE_NULL);
   2418 }
   2419 
   2420 bool InvalidShaderCompilerCase::compileShader (deUint32 shader) const
   2421 {
   2422 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2423 	GLint status;
   2424 	gl.compileShader(shader);
   2425 	gl.getShaderiv(shader, GL_COMPILE_STATUS, &status);
   2426 	return status != 0;
   2427 }
   2428 
   2429 void InvalidShaderCompilerCase::logProgramData (const BuildInfo& buildInfo, const ProgramContext& progCtx) const
   2430 {
   2431 	m_testCtx.getLog() << TestLog::ShaderProgram(false, "(No linking done)")
   2432 					   << TestLog::Shader(QP_SHADER_TYPE_VERTEX,	progCtx.vertShaderSource, buildInfo.vertCompileSuccess, buildInfo.logs.vert)
   2433 					   << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT,	progCtx.fragShaderSource, buildInfo.fragCompileSuccess, buildInfo.logs.frag)
   2434 					   << TestLog::EndShaderProgram;
   2435 }
   2436 
   2437 InvalidShaderCompilerCase::Logs InvalidShaderCompilerCase::getLogs (const Shaders& shaders) const
   2438 {
   2439 	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
   2440 	Logs					result;
   2441 
   2442 	result.vert = getShaderInfoLog(gl, shaders.vertShader);
   2443 	result.frag = getShaderInfoLog(gl, shaders.fragShader);
   2444 
   2445 	return result;
   2446 }
   2447 
   2448 void InvalidShaderCompilerCase::cleanup (const Shaders& shaders) const
   2449 {
   2450 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2451 
   2452 	gl.deleteShader(shaders.vertShader);
   2453 	gl.deleteShader(shaders.fragShader);
   2454 }
   2455 
   2456 bool InvalidShaderCompilerCase::goodEnoughMeasurements (const vector<Measurement>& measurements) const
   2457 {
   2458 	if ((int)measurements.size() < m_minimumMeasurementCount)
   2459 		return false;
   2460 	else
   2461 	{
   2462 		if ((int)measurements.size() >= m_maximumMeasurementCount)
   2463 			return true;
   2464 		else
   2465 		{
   2466 			vector<deInt64> totalTimes;
   2467 			for (int i = 0; i < (int)measurements.size(); i++)
   2468 				totalTimes.push_back(measurements[i].totalTime());
   2469 			return vectorFloatRelativeMedianAbsoluteDeviation(vectorLowestPercentage(totalTimes, 0.5f)) < RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD;
   2470 		}
   2471 	}
   2472 }
   2473 
   2474 InvalidShaderCompilerCase::IterateResult InvalidShaderCompilerCase::iterate (void)
   2475 {
   2476 	ShaderValidity shaderValidity = m_invalidityType == INVALIDITY_INVALID_CHAR		? SHADER_VALIDITY_INVALID_CHAR
   2477 								  : m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
   2478 								  : SHADER_VALIDITY_LAST;
   2479 
   2480 	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
   2481 
   2482 	// Before actual measurements, compile a dummy shader to avoid possible initial slowdowns in the actual test.
   2483 	{
   2484 		deUint32		specID = getSpecializationID(0);
   2485 		ProgramContext	progCtx;
   2486 		progCtx.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, shaderValidity);
   2487 		progCtx.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, shaderValidity);
   2488 
   2489 		Shaders shaders = createShaders();
   2490 		setShaderSources(shaders, progCtx);
   2491 
   2492 		BuildInfo buildInfo;
   2493 		buildInfo.vertCompileSuccess = compileShader(shaders.vertShader);
   2494 		buildInfo.fragCompileSuccess = compileShader(shaders.fragShader);
   2495 		if (buildInfo.vertCompileSuccess || buildInfo.fragCompileSuccess)
   2496 		{
   2497 			buildInfo.logs = getLogs(shaders);
   2498 			logProgramData(buildInfo, progCtx);
   2499 			cleanup(shaders);
   2500 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation of a shader erroneously succeeded");
   2501 			return STOP;
   2502 		}
   2503 		cleanup(shaders);
   2504 	}
   2505 
   2506 	vector<Measurement>		measurements;
   2507 	// \note These are logged after measurements are done.
   2508 	ProgramContext			latestProgramContext;
   2509 	BuildInfo				latestBuildInfo;
   2510 
   2511 	if (WARMUP_CPU_AT_BEGINNING_OF_CASE)
   2512 		tcu::warmupCPU();
   2513 
   2514 	// Actual test measurements.
   2515 	while (!goodEnoughMeasurements(measurements))
   2516 	{
   2517 		// Create shader and compile. Measure time.
   2518 
   2519 		// \note Shader sources are generated and GL shader objects are created before any time measurements.
   2520 		ProgramContext	progCtx		= generateShaderSources((int)measurements.size());
   2521 		Shaders			shaders		= createShaders();
   2522 		BuildInfo		buildInfo;
   2523 
   2524 		if (WARMUP_CPU_BEFORE_EACH_MEASUREMENT)
   2525 			tcu::warmupCPU();
   2526 
   2527 		// \note Do NOT do anything too hefty between the first and last deGetMicroseconds() here (other than the gl calls); it would disturb the measurement.
   2528 
   2529 		deUint64 startTime = deGetMicroseconds();
   2530 
   2531 		setShaderSources(shaders, progCtx);
   2532 		deUint64 shaderSourceSetEndTime = deGetMicroseconds();
   2533 
   2534 		buildInfo.vertCompileSuccess = compileShader(shaders.vertShader);
   2535 		deUint64 vertexShaderCompileEndTime = deGetMicroseconds();
   2536 
   2537 		buildInfo.fragCompileSuccess = compileShader(shaders.fragShader);
   2538 		deUint64 fragmentShaderCompileEndTime = deGetMicroseconds();
   2539 
   2540 		buildInfo.logs = getLogs(shaders);
   2541 
   2542 		// Both shader compilations should have failed.
   2543 		if (buildInfo.vertCompileSuccess || buildInfo.fragCompileSuccess)
   2544 		{
   2545 			logProgramData(buildInfo, progCtx);
   2546 			cleanup(shaders);
   2547 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation of a shader erroneously succeeded");
   2548 			return STOP;
   2549 		}
   2550 
   2551 		// De-initializations (delete shaders).
   2552 
   2553 		cleanup(shaders);
   2554 
   2555 		// Output measurement log later (after last measurement).
   2556 
   2557 		measurements.push_back(Measurement((deInt64)(shaderSourceSetEndTime			- startTime),
   2558 										   (deInt64)(vertexShaderCompileEndTime		- shaderSourceSetEndTime),
   2559 										   (deInt64)(fragmentShaderCompileEndTime	- vertexShaderCompileEndTime)));
   2560 
   2561 		latestBuildInfo			= buildInfo;
   2562 		latestProgramContext	= progCtx;
   2563 
   2564 		m_testCtx.touchWatchdog(); // \note Measurements may take a while in a bad case.
   2565 	}
   2566 
   2567 	// End of test case, log information about measurements.
   2568 	{
   2569 		TestLog& log = m_testCtx.getLog();
   2570 
   2571 		vector<deInt64> sourceSetTimes;
   2572 		vector<deInt64> vertexCompileTimes;
   2573 		vector<deInt64> fragmentCompileTimes;
   2574 		vector<deInt64> totalTimes;
   2575 
   2576 		log << TestLog::Section("IterationMeasurements", "Iteration measurements of compilation times");
   2577 
   2578 		for (int ndx = 0; ndx < (int)measurements.size(); ndx++)
   2579 		{
   2580 			sourceSetTimes.push_back		(measurements[ndx].sourceSetTime);
   2581 			vertexCompileTimes.push_back	(measurements[ndx].vertexCompileTime);
   2582 			fragmentCompileTimes.push_back	(measurements[ndx].fragmentCompileTime);
   2583 			totalTimes.push_back			(measurements[ndx].totalTime());
   2584 
   2585 			// Log this measurement.
   2586 			log << TestLog::Float("Measurement" + de::toString(ndx) + "Time",
   2587 								  "Measurement " + de::toString(ndx) + " time",
   2588 								  "ms", QP_KEY_TAG_TIME, (float)measurements[ndx].totalTime()/1000.0f);
   2589 		}
   2590 
   2591 		// Log some statistics.
   2592 
   2593 		for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
   2594 		{
   2595 			bool				isEntireRange	= entireRangeOrLowestHalf == 0;
   2596 			string				statNamePrefix	= isEntireRange ? "" : "LowestHalf";
   2597 			vector<deInt64>		rangeTimes		= isEntireRange ? totalTimes : vectorLowestPercentage(totalTimes, 0.5f);
   2598 
   2599 			log << TestLog::Message << "\nStatistics computed from "
   2600 									<< (isEntireRange ? "all" : "only the lowest 50%")
   2601 									<< " of the above measurements:"
   2602 									<< TestLog::EndMessage;
   2603 
   2604 #define LOG_TIME_STAT(NAME, DESC, FUNC)			log << TestLog::Float(statNamePrefix + "TotalTime" + (NAME), (DESC) + string(" of total time"), "ms",	QP_KEY_TAG_TIME, (FUNC)(rangeTimes)/1000.0f)
   2605 #define LOG_RELATIVE_STAT(NAME, DESC, FUNC)		log << TestLog::Float(statNamePrefix + "TotalTime" + (NAME), (DESC) + string(" of total time"), "",		QP_KEY_TAG_NONE, (FUNC)(rangeTimes))
   2606 
   2607 			LOG_TIME_STAT		("Median",							"Median",								vectorFloatMedian);
   2608 			LOG_TIME_STAT		("Average",							"Average",								vectorFloatAverage);
   2609 			LOG_TIME_STAT		("Minimum",							"Minimum",								vectorFloatMinimum);
   2610 			LOG_TIME_STAT		("Maximum",							"Maximum",								vectorFloatMaximum);
   2611 			LOG_TIME_STAT		("MedianAbsoluteDeviation",			"Median absolute deviation",			vectorFloatMedianAbsoluteDeviation);
   2612 			LOG_RELATIVE_STAT	("RelativeMedianAbsoluteDeviation",	"Relative median absolute deviation",	vectorFloatRelativeMedianAbsoluteDeviation);
   2613 			LOG_TIME_STAT		("StandardDeviation",				"Standard deviation",					vectorFloatStandardDeviation);
   2614 			LOG_RELATIVE_STAT	("RelativeStandardDeviation",		"Relative standard deviation",			vectorFloatRelativeStandardDeviation);
   2615 			LOG_TIME_STAT		("MaxMinusMin",						"Max-min",								vectorFloatMaximumMinusMinimum);
   2616 			LOG_RELATIVE_STAT	("RelativeMaxMinusMin",				"Relative max-min",						vectorFloatRelativeMaximumMinusMinimum);
   2617 
   2618 #undef LOG_TIME_STAT
   2619 #undef LOG_RELATIVE_STAT
   2620 
   2621 			if (!isEntireRange && vectorFloatRelativeMedianAbsoluteDeviation(rangeTimes) > RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD)
   2622 				log << TestLog::Message << "\nWARNING: couldn't achieve relative median absolute deviation under threshold value " << RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD << TestLog::EndMessage;
   2623 		}
   2624 
   2625 		log << TestLog::EndSection; // End section IterationMeasurements
   2626 
   2627 		for (int medianOrAverage = 0; medianOrAverage < 2; medianOrAverage++)
   2628 		{
   2629 			typedef float (*VecFunc)(const vector<deInt64>&);
   2630 
   2631 			bool	isMedian						= medianOrAverage == 0;
   2632 			string	singular						= isMedian ? "Median" : "Average";
   2633 			string	plural							= singular + "s";
   2634 			VecFunc func							= isMedian ? (VecFunc) vectorFloatMedian<deInt64> : (VecFunc) vectorFloatAverage<deInt64>;
   2635 
   2636 			log << TestLog::Section(plural + "PerPhase", plural + " per phase");
   2637 
   2638 			for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
   2639 			{
   2640 				bool	isEntireRange	= entireRangeOrLowestHalf == 0;
   2641 				string	statNamePrefix	= isEntireRange ? "" : "LowestHalf";
   2642 				float	rangeSizeRatio	= isEntireRange ? 1.0f : 0.5f;
   2643 
   2644 #define LOG_TIME(NAME, DESC, DATA) log << TestLog::Float(statNamePrefix + (NAME) + singular, singular + " of " + (DESC), "ms", QP_KEY_TAG_TIME, func(vectorLowestPercentage((DATA), rangeSizeRatio))/1000.0f);
   2645 
   2646 				log << TestLog::Message << (isEntireRange ? "For all measurements:" : "\nFor only the lowest 50% of the measurements:") << TestLog::EndMessage;
   2647 				LOG_TIME("ShaderSourceSetTime",			"shader source set time",			sourceSetTimes);
   2648 				LOG_TIME("VertexShaderCompileTime",		"vertex shader compile time",		vertexCompileTimes);
   2649 				LOG_TIME("FragmentShaderCompileTime",	"fragment shader compile time",		fragmentCompileTimes);
   2650 
   2651 #undef LOG_TIME
   2652 			}
   2653 
   2654 			log << TestLog::EndSection;
   2655 		}
   2656 
   2657 		// Set result.
   2658 
   2659 		{
   2660 			log << TestLog::Message << "Note: test result is the first quartile (i.e. median of the lowest half of measurements) of total times" << TestLog::EndMessage;
   2661 			float result = vectorFloatFirstQuartile(totalTimes) / 1000.0f;
   2662 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(result, 2).c_str());
   2663 		}
   2664 
   2665 		// Log shaders.
   2666 
   2667 		log << TestLog::Message << "Note: the following shaders are the ones from the last iteration; variables' names and some constant expressions differ between iterations." << TestLog::EndMessage;
   2668 
   2669 		logProgramData(latestBuildInfo, latestProgramContext);
   2670 
   2671 		return STOP;
   2672 	}
   2673 }
   2674 
   2675 InvalidShaderCompilerLightCase::InvalidShaderCompilerLightCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, int numLights, LightType lightType)
   2676 	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
   2677 	, m_isVertexCase			(isVertexCase)
   2678 	, m_numLights				(numLights)
   2679 	, m_lightType				(lightType)
   2680 {
   2681 }
   2682 
   2683 InvalidShaderCompilerLightCase::~InvalidShaderCompilerLightCase (void)
   2684 {
   2685 }
   2686 
   2687 InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerLightCase::generateShaderSources (int measurementNdx) const
   2688 {
   2689 	deUint32		specID			= getSpecializationID(measurementNdx);
   2690 	ProgramContext	result;
   2691 	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
   2692 									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
   2693 									: SHADER_VALIDITY_LAST;
   2694 
   2695 	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
   2696 
   2697 	result.vertShaderSource = specializeShaderSource(lightVertexTemplate(m_numLights, m_isVertexCase, m_lightType), specID, shaderValidity);
   2698 	result.fragShaderSource = specializeShaderSource(lightFragmentTemplate(m_numLights, m_isVertexCase, m_lightType), specID, shaderValidity);
   2699 
   2700 	return result;
   2701 }
   2702 
   2703 InvalidShaderCompilerTextureCase::InvalidShaderCompilerTextureCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
   2704 	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
   2705 	, m_numLookups				(numLookups)
   2706 	, m_conditionalUsage		(conditionalUsage)
   2707 	, m_conditionalType			(conditionalType)
   2708 {
   2709 }
   2710 
   2711 InvalidShaderCompilerTextureCase::~InvalidShaderCompilerTextureCase (void)
   2712 {
   2713 }
   2714 
   2715 InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerTextureCase::generateShaderSources (int measurementNdx) const
   2716 {
   2717 	deUint32		specID			= getSpecializationID(measurementNdx);
   2718 	ProgramContext	result;
   2719 	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
   2720 									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
   2721 									: SHADER_VALIDITY_LAST;
   2722 
   2723 	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
   2724 
   2725 	result.vertShaderSource = specializeShaderSource(textureLookupVertexTemplate(m_conditionalUsage, m_conditionalType), specID, shaderValidity);
   2726 	result.fragShaderSource = specializeShaderSource(textureLookupFragmentTemplate(m_numLookups, m_conditionalUsage, m_conditionalType), specID, shaderValidity);
   2727 
   2728 	return result;
   2729 }
   2730 
   2731 InvalidShaderCompilerLoopCase::InvalidShaderCompilerLoopCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, LoopType type, int numLoopIterations, int nestingDepth)
   2732 	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
   2733 	, m_isVertexCase			(isVertexCase)
   2734 	, m_numLoopIterations		(numLoopIterations)
   2735 	, m_nestingDepth			(nestingDepth)
   2736 	, m_type					(type)
   2737 {
   2738 }
   2739 
   2740 InvalidShaderCompilerLoopCase::~InvalidShaderCompilerLoopCase (void)
   2741 {
   2742 }
   2743 
   2744 InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerLoopCase::generateShaderSources (int measurementNdx) const
   2745 {
   2746 	deUint32		specID			= getSpecializationID(measurementNdx);
   2747 	ProgramContext	result;
   2748 	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
   2749 									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
   2750 									: SHADER_VALIDITY_LAST;
   2751 
   2752 	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
   2753 
   2754 	result.vertShaderSource = specializeShaderSource(loopVertexTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, shaderValidity);
   2755 	result.fragShaderSource = specializeShaderSource(loopFragmentTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, shaderValidity);
   2756 
   2757 	return result;
   2758 }
   2759 
   2760 InvalidShaderCompilerOperCase::InvalidShaderCompilerOperCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, const char* oper, int numOperations)
   2761 	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
   2762 	, m_isVertexCase			(isVertexCase)
   2763 	, m_oper					(oper)
   2764 	, m_numOperations			(numOperations)
   2765 {
   2766 }
   2767 
   2768 InvalidShaderCompilerOperCase::~InvalidShaderCompilerOperCase (void)
   2769 {
   2770 }
   2771 
   2772 InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerOperCase::generateShaderSources (int measurementNdx) const
   2773 {
   2774 	deUint32		specID			= getSpecializationID(measurementNdx);
   2775 	ProgramContext	result;
   2776 	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
   2777 									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
   2778 									: SHADER_VALIDITY_LAST;
   2779 
   2780 	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
   2781 
   2782 	if (m_isVertexCase)
   2783 	{
   2784 		result.vertShaderSource = specializeShaderSource(binaryOpVertexTemplate(m_numOperations, m_oper.c_str()), specID, shaderValidity);
   2785 		result.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, shaderValidity);
   2786 	}
   2787 	else
   2788 	{
   2789 		result.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, shaderValidity);
   2790 		result.fragShaderSource = specializeShaderSource(binaryOpFragmentTemplate(m_numOperations, m_oper.c_str()), specID, shaderValidity);
   2791 	}
   2792 
   2793 	return result;
   2794 }
   2795 
   2796 InvalidShaderCompilerMandelbrotCase::InvalidShaderCompilerMandelbrotCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numFractalIterations)
   2797 	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
   2798 	, m_numFractalIterations	(numFractalIterations)
   2799 {
   2800 }
   2801 
   2802 InvalidShaderCompilerMandelbrotCase::~InvalidShaderCompilerMandelbrotCase (void)
   2803 {
   2804 }
   2805 
   2806 InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerMandelbrotCase::generateShaderSources (int measurementNdx) const
   2807 {
   2808 	deUint32		specID			= getSpecializationID(measurementNdx);
   2809 	ProgramContext	result;
   2810 	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
   2811 									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
   2812 									: SHADER_VALIDITY_LAST;
   2813 
   2814 	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
   2815 
   2816 	result.vertShaderSource = specializeShaderSource(mandelbrotVertexTemplate(), specID, shaderValidity);
   2817 	result.fragShaderSource = specializeShaderSource(mandelbrotFragmentTemplate(m_numFractalIterations), specID, shaderValidity);
   2818 
   2819 	return result;
   2820 }
   2821 
   2822 void addShaderCompilationPerformanceCases (TestCaseGroup& parentGroup)
   2823 {
   2824 	Context&	context		= parentGroup.getContext();
   2825 	int			caseID		= 0; // Increment this after adding each case. Used for avoiding cache hits between cases.
   2826 
   2827 	TestCaseGroup* validGroup			= new TestCaseGroup(context, "valid_shader",	"Valid Shader Compiler Cases");
   2828 	TestCaseGroup* invalidGroup			= new TestCaseGroup(context, "invalid_shader",	"Invalid Shader Compiler Cases");
   2829 	TestCaseGroup* cacheGroup			= new TestCaseGroup(context, "cache",			"Allow shader caching");
   2830 	parentGroup.addChild(validGroup);
   2831 	parentGroup.addChild(invalidGroup);
   2832 	parentGroup.addChild(cacheGroup);
   2833 
   2834 	TestCaseGroup* invalidCharGroup		= new TestCaseGroup(context, "invalid_char",	"Invalid Character Shader Compiler Cases");
   2835 	TestCaseGroup* semanticErrorGroup	= new TestCaseGroup(context, "semantic_error",	"Semantic Error Shader Compiler Cases");
   2836 	invalidGroup->addChild(invalidCharGroup);
   2837 	invalidGroup->addChild(semanticErrorGroup);
   2838 
   2839 	// Lighting shader compilation cases.
   2840 
   2841 	{
   2842 		static const int lightCounts[] = { 1, 2, 4, 8 };
   2843 
   2844 		TestCaseGroup* validLightingGroup			= new TestCaseGroup(context, "lighting", "Shader Compiler Lighting Cases");
   2845 		TestCaseGroup* invalidCharLightingGroup		= new TestCaseGroup(context, "lighting", "Invalid Character Shader Compiler Lighting Cases");
   2846 		TestCaseGroup* semanticErrorLightingGroup	= new TestCaseGroup(context, "lighting", "Semantic Error Shader Compiler Lighting Cases");
   2847 		TestCaseGroup* cacheLightingGroup			= new TestCaseGroup(context, "lighting", "Shader Compiler Lighting Cache Cases");
   2848 		validGroup->addChild(validLightingGroup);
   2849 		invalidCharGroup->addChild(invalidCharLightingGroup);
   2850 		semanticErrorGroup->addChild(semanticErrorLightingGroup);
   2851 		cacheGroup->addChild(cacheLightingGroup);
   2852 
   2853 		for (int lightType = 0; lightType < (int)LIGHT_LAST; lightType++)
   2854 		{
   2855 			const char* lightTypeName = lightType == (int)LIGHT_DIRECTIONAL	? "directional"
   2856 									  : lightType == (int)LIGHT_POINT		? "point"
   2857 									  : DE_NULL;
   2858 
   2859 			DE_ASSERT(lightTypeName != DE_NULL);
   2860 
   2861 			for (int isFrag = 0; isFrag <= 1; isFrag++)
   2862 			{
   2863 				bool		isVertex	= isFrag == 0;
   2864 				const char*	vertFragStr	= isVertex ? "vertex" : "fragment";
   2865 
   2866 				for (int lightCountNdx = 0; lightCountNdx < DE_LENGTH_OF_ARRAY(lightCounts); lightCountNdx++)
   2867 				{
   2868 					int numLights = lightCounts[lightCountNdx];
   2869 
   2870 					string caseName = string("") + lightTypeName + "_" + de::toString(numLights) + "_lights_" + vertFragStr;
   2871 
   2872 					// Valid shader case, no-cache and cache versions.
   2873 
   2874 					validLightingGroup->addChild(new ShaderCompilerLightCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, isVertex, numLights, (LightType)lightType));
   2875 					cacheLightingGroup->addChild(new ShaderCompilerLightCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, isVertex, numLights, (LightType)lightType));
   2876 
   2877 					// Invalid shader cases.
   2878 
   2879 					for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
   2880 					{
   2881 						TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharLightingGroup
   2882 														: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorLightingGroup
   2883 														: DE_NULL;
   2884 
   2885 						DE_ASSERT(curInvalidGroup != DE_NULL);
   2886 
   2887 						curInvalidGroup->addChild(new InvalidShaderCompilerLightCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, isVertex, numLights, (LightType)lightType));
   2888 					}
   2889 				}
   2890 			}
   2891 		}
   2892 	}
   2893 
   2894 	// Texture lookup shader compilation cases.
   2895 
   2896 	{
   2897 		static const int texLookupCounts[] = { 1, 2, 4, 8 };
   2898 
   2899 		TestCaseGroup* validTexGroup			= new TestCaseGroup(context, "texture", "Shader Compiler Texture Lookup Cases");
   2900 		TestCaseGroup* invalidCharTexGroup		= new TestCaseGroup(context, "texture", "Invalid Character Shader Compiler Texture Lookup Cases");
   2901 		TestCaseGroup* semanticErrorTexGroup	= new TestCaseGroup(context, "texture", "Semantic Error Shader Compiler Texture Lookup Cases");
   2902 		TestCaseGroup* cacheTexGroup			= new TestCaseGroup(context, "texture", "Shader Compiler Texture Lookup Cache Cases");
   2903 		validGroup->addChild(validTexGroup);
   2904 		invalidCharGroup->addChild(invalidCharTexGroup);
   2905 		semanticErrorGroup->addChild(semanticErrorTexGroup);
   2906 		cacheGroup->addChild(cacheTexGroup);
   2907 
   2908 		for (int conditionalUsage = 0; conditionalUsage < (int)CONDITIONAL_USAGE_LAST; conditionalUsage++)
   2909 		{
   2910 			const char* conditionalUsageName = conditionalUsage == (int)CONDITIONAL_USAGE_NONE			? "no_conditionals"
   2911 											 : conditionalUsage == (int)CONDITIONAL_USAGE_FIRST_HALF	? "first_half"
   2912 											 : conditionalUsage == (int)CONDITIONAL_USAGE_EVERY_OTHER	? "every_other"
   2913 											 : DE_NULL;
   2914 
   2915 			DE_ASSERT(conditionalUsageName != DE_NULL);
   2916 
   2917 			int lastConditionalType = conditionalUsage == (int)CONDITIONAL_USAGE_NONE ? 1 : (int)CONDITIONAL_TYPE_LAST;
   2918 
   2919 			for (int conditionalType = 0; conditionalType < lastConditionalType; conditionalType++)
   2920 			{
   2921 				const char* conditionalTypeName = conditionalType == (int)CONDITIONAL_TYPE_STATIC	? "static_conditionals"
   2922 												: conditionalType == (int)CONDITIONAL_TYPE_UNIFORM	? "uniform_conditionals"
   2923 												: conditionalType == (int)CONDITIONAL_TYPE_DYNAMIC	? "dynamic_conditionals"
   2924 												: DE_NULL;
   2925 
   2926 				DE_ASSERT(conditionalTypeName != DE_NULL);
   2927 
   2928 				for (int lookupCountNdx = 0; lookupCountNdx < DE_LENGTH_OF_ARRAY(texLookupCounts); lookupCountNdx++)
   2929 				{
   2930 					int numLookups = texLookupCounts[lookupCountNdx];
   2931 
   2932 					string caseName = de::toString(numLookups) + "_lookups_" + conditionalUsageName + (conditionalUsage == (int)CONDITIONAL_USAGE_NONE ? "" : string("_") + conditionalTypeName);
   2933 
   2934 					// Valid shader case, no-cache and cache versions.
   2935 
   2936 					validTexGroup->addChild(new ShaderCompilerTextureCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, numLookups, (ConditionalUsage)conditionalUsage, (ConditionalType)conditionalType));
   2937 					cacheTexGroup->addChild(new ShaderCompilerTextureCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, numLookups, (ConditionalUsage)conditionalUsage, (ConditionalType)conditionalType));
   2938 
   2939 					// Invalid shader cases.
   2940 
   2941 					for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
   2942 					{
   2943 						TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharTexGroup
   2944 														: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorTexGroup
   2945 														: DE_NULL;
   2946 
   2947 						DE_ASSERT(curInvalidGroup != DE_NULL);
   2948 
   2949 						curInvalidGroup->addChild(new InvalidShaderCompilerTextureCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, numLookups, (ConditionalUsage)conditionalUsage, (ConditionalType)conditionalType));
   2950 					}
   2951 				}
   2952 			}
   2953 		}
   2954 	}
   2955 
   2956 	// Loop shader compilation cases.
   2957 
   2958 	{
   2959 		static const int loopIterCounts[]		= { 10, 100, 1000 };
   2960 		static const int maxLoopNestingDepth	= 3;
   2961 		static const int maxTotalLoopIterations	= 2000; // If <loop iteration count> ** <loop nesting depth> (where ** is exponentiation) exceeds this, don't generate the case.
   2962 
   2963 		TestCaseGroup* validLoopGroup			= new TestCaseGroup(context, "loop", "Shader Compiler Loop Cases");
   2964 		TestCaseGroup* invalidCharLoopGroup		= new TestCaseGroup(context, "loop", "Invalid Character Shader Compiler Loop Cases");
   2965 		TestCaseGroup* semanticErrorLoopGroup	= new TestCaseGroup(context, "loop", "Semantic Error Shader Compiler Loop Cases");
   2966 		TestCaseGroup* cacheLoopGroup			= new TestCaseGroup(context, "loop", "Shader Compiler Loop Cache Cases");
   2967 		validGroup->addChild(validLoopGroup);
   2968 		invalidCharGroup->addChild(invalidCharLoopGroup);
   2969 		semanticErrorGroup->addChild(semanticErrorLoopGroup);
   2970 		cacheGroup->addChild(cacheLoopGroup);
   2971 
   2972 		for (int loopType = 0; loopType < (int)LOOP_LAST; loopType++)
   2973 		{
   2974 			const char* loopTypeName = loopType == (int)LOOP_TYPE_STATIC	? "static"
   2975 									 : loopType == (int)LOOP_TYPE_UNIFORM	? "uniform"
   2976 									 : loopType == (int)LOOP_TYPE_DYNAMIC	? "dynamic"
   2977 									 : DE_NULL;
   2978 
   2979 			DE_ASSERT(loopTypeName != DE_NULL);
   2980 
   2981 			TestCaseGroup* validLoopTypeGroup			= new TestCaseGroup(context, loopTypeName, "");
   2982 			TestCaseGroup* invalidCharLoopTypeGroup		= new TestCaseGroup(context, loopTypeName, "");
   2983 			TestCaseGroup* semanticErrorLoopTypeGroup	= new TestCaseGroup(context, loopTypeName, "");
   2984 			TestCaseGroup* cacheLoopTypeGroup			= new TestCaseGroup(context, loopTypeName, "");
   2985 			validLoopGroup->addChild(validLoopTypeGroup);
   2986 			invalidCharLoopGroup->addChild(invalidCharLoopTypeGroup);
   2987 			semanticErrorLoopGroup->addChild(semanticErrorLoopTypeGroup);
   2988 			cacheLoopGroup->addChild(cacheLoopTypeGroup);
   2989 
   2990 			for (int isFrag = 0; isFrag <= 1; isFrag++)
   2991 			{
   2992 				bool		isVertex	= isFrag == 0;
   2993 				const char*	vertFragStr	= isVertex ? "vertex" : "fragment";
   2994 
   2995 				// \note Non-static loop cases with different iteration counts have identical shaders, so only make one of each.
   2996 				int loopIterCountMaxNdx = loopType != (int)LOOP_TYPE_STATIC ? 1 : DE_LENGTH_OF_ARRAY(loopIterCounts);
   2997 
   2998 				for (int nestingDepth = 1; nestingDepth <= maxLoopNestingDepth; nestingDepth++)
   2999 				{
   3000 					for (int loopIterCountNdx = 0; loopIterCountNdx < loopIterCountMaxNdx; loopIterCountNdx++)
   3001 					{
   3002 						int numIterations = loopIterCounts[loopIterCountNdx];
   3003 
   3004 						if (deFloatPow((float)numIterations, (float)nestingDepth) > (float)maxTotalLoopIterations)
   3005 							continue; // Don't generate too heavy tasks.
   3006 
   3007 						string validCaseName = de::toString(numIterations) + "_iterations_" + de::toString(nestingDepth) + "_levels_" + vertFragStr;
   3008 
   3009 						// Valid shader case, no-cache and cache versions.
   3010 
   3011 						validLoopTypeGroup->addChild(new ShaderCompilerLoopCase(context, validCaseName.c_str(), "", caseID++, true  /* avoid cache */, false, isVertex, (LoopType)loopType, numIterations, nestingDepth));
   3012 						cacheLoopTypeGroup->addChild(new ShaderCompilerLoopCase(context, validCaseName.c_str(), "", caseID++, false /* allow cache */, false, isVertex, (LoopType)loopType, numIterations, nestingDepth));
   3013 
   3014 						// Invalid shader cases.
   3015 
   3016 						for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
   3017 						{
   3018 							TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharLoopTypeGroup
   3019 															: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorLoopTypeGroup
   3020 															: DE_NULL;
   3021 
   3022 							DE_ASSERT(curInvalidGroup != DE_NULL);
   3023 
   3024 							string invalidCaseName = de::toString(nestingDepth) + "_levels_" + vertFragStr;
   3025 
   3026 							if (loopType == (int)LOOP_TYPE_STATIC)
   3027 								invalidCaseName = de::toString(numIterations) + "_iterations_" + invalidCaseName; // \note For invalid, non-static loop cases the iteration count means nothing (since no uniforms or attributes are set).
   3028 
   3029 							curInvalidGroup->addChild(new InvalidShaderCompilerLoopCase(context, invalidCaseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, isVertex, (LoopType)loopType, numIterations, nestingDepth));
   3030 						}
   3031 					}
   3032 				}
   3033 			}
   3034 		}
   3035 	}
   3036 
   3037 	// Multiplication shader compilation cases.
   3038 
   3039 	{
   3040 		static const int multiplicationCounts[] = { 10, 100, 1000 };
   3041 
   3042 		TestCaseGroup* validMulGroup			= new TestCaseGroup(context, "multiplication", "Shader Compiler Multiplication Cases");
   3043 		TestCaseGroup* invalidCharMulGroup		= new TestCaseGroup(context, "multiplication", "Invalid Character Shader Compiler Multiplication Cases");
   3044 		TestCaseGroup* semanticErrorMulGroup	= new TestCaseGroup(context, "multiplication", "Semantic Error Shader Compiler Multiplication Cases");
   3045 		TestCaseGroup* cacheMulGroup			= new TestCaseGroup(context, "multiplication", "Shader Compiler Multiplication Cache Cases");
   3046 		validGroup->addChild(validMulGroup);
   3047 		invalidCharGroup->addChild(invalidCharMulGroup);
   3048 		semanticErrorGroup->addChild(semanticErrorMulGroup);
   3049 		cacheGroup->addChild(cacheMulGroup);
   3050 
   3051 		for (int isFrag = 0; isFrag <= 1; isFrag++)
   3052 		{
   3053 			bool		isVertex	= isFrag == 0;
   3054 			const char*	vertFragStr	= isVertex ? "vertex" : "fragment";
   3055 
   3056 			for (int operCountNdx = 0; operCountNdx < DE_LENGTH_OF_ARRAY(multiplicationCounts); operCountNdx++)
   3057 			{
   3058 				int numOpers = multiplicationCounts[operCountNdx];
   3059 
   3060 				string caseName = de::toString(numOpers) + "_operations_" + vertFragStr;
   3061 
   3062 				// Valid shader case, no-cache and cache versions.
   3063 
   3064 				validMulGroup->addChild(new ShaderCompilerOperCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, isVertex, "*", numOpers));
   3065 				cacheMulGroup->addChild(new ShaderCompilerOperCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, isVertex, "*", numOpers));
   3066 
   3067 				// Invalid shader cases.
   3068 
   3069 				for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
   3070 				{
   3071 					TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharMulGroup
   3072 													: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorMulGroup
   3073 													: DE_NULL;
   3074 
   3075 					DE_ASSERT(curInvalidGroup != DE_NULL);
   3076 
   3077 					curInvalidGroup->addChild(new InvalidShaderCompilerOperCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, isVertex, "*", numOpers));
   3078 				}
   3079 			}
   3080 		}
   3081 	}
   3082 
   3083 	// Mandelbrot shader compilation cases.
   3084 
   3085 	{
   3086 		static const int mandelbrotIterationCounts[] = { 32, 64, 128 };
   3087 
   3088 		TestCaseGroup* validMandelbrotGroup			= new TestCaseGroup(context, "mandelbrot", "Shader Compiler Mandelbrot Fractal Cases");
   3089 		TestCaseGroup* invalidCharMandelbrotGroup	= new TestCaseGroup(context, "mandelbrot", "Invalid Character Shader Compiler Mandelbrot Fractal Cases");
   3090 		TestCaseGroup* semanticErrorMandelbrotGroup	= new TestCaseGroup(context, "mandelbrot", "Semantic Error Shader Compiler Mandelbrot Fractal Cases");
   3091 		TestCaseGroup* cacheMandelbrotGroup			= new TestCaseGroup(context, "mandelbrot", "Shader Compiler Mandelbrot Fractal Cache Cases");
   3092 		validGroup->addChild(validMandelbrotGroup);
   3093 		invalidCharGroup->addChild(invalidCharMandelbrotGroup);
   3094 		semanticErrorGroup->addChild(semanticErrorMandelbrotGroup);
   3095 		cacheGroup->addChild(cacheMandelbrotGroup);
   3096 
   3097 		for (int iterCountNdx = 0; iterCountNdx < DE_LENGTH_OF_ARRAY(mandelbrotIterationCounts); iterCountNdx++)
   3098 		{
   3099 			int		numFractalIterations	= mandelbrotIterationCounts[iterCountNdx];
   3100 			string	caseName				= de::toString(numFractalIterations) + "_iterations";
   3101 
   3102 			// Valid shader case, no-cache and cache versions.
   3103 
   3104 			validMandelbrotGroup->addChild(new ShaderCompilerMandelbrotCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, numFractalIterations));
   3105 			cacheMandelbrotGroup->addChild(new ShaderCompilerMandelbrotCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, numFractalIterations));
   3106 
   3107 			// Invalid shader cases.
   3108 
   3109 			for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
   3110 			{
   3111 				TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharMandelbrotGroup
   3112 												: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorMandelbrotGroup
   3113 												: DE_NULL;
   3114 
   3115 				DE_ASSERT(curInvalidGroup != DE_NULL);
   3116 
   3117 				curInvalidGroup->addChild(new InvalidShaderCompilerMandelbrotCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, numFractalIterations));
   3118 			}
   3119 		}
   3120 	}
   3121 
   3122 	// Cases testing cache behaviour when whitespace and comments are added.
   3123 
   3124 	{
   3125 		TestCaseGroup* whitespaceCommentCacheGroup = new TestCaseGroup(context, "cache_whitespace_comment", "Cases testing the effect of whitespace and comments on caching");
   3126 		parentGroup.addChild(whitespaceCommentCacheGroup);
   3127 
   3128 		// \note Add just a small subset of the cases that were added above for the main performance tests.
   3129 
   3130 		// Cases with both vertex and fragment variants.
   3131 		for (int isFrag = 0; isFrag <= 1; isFrag++)
   3132 		{
   3133 			bool	isVertex		= isFrag == 0;
   3134 			string	vtxFragSuffix	= isVertex ? "_vertex" : "_fragment";
   3135 			string	dirLightName	= "directional_2_lights" + vtxFragSuffix;
   3136 			string	loopName		= "static_loop_100_iterations" + vtxFragSuffix;
   3137 			string	multCase		= "multiplication_100_operations" + vtxFragSuffix;
   3138 
   3139 			whitespaceCommentCacheGroup->addChild(new ShaderCompilerLightCase(context, dirLightName.c_str(), "", caseID++, false, true, isVertex, 2, LIGHT_DIRECTIONAL));
   3140 			whitespaceCommentCacheGroup->addChild(new ShaderCompilerLoopCase(context, loopName.c_str(), "", caseID++, false, true, isVertex, LOOP_TYPE_STATIC, 100, 1));
   3141 			whitespaceCommentCacheGroup->addChild(new ShaderCompilerOperCase(context, multCase.c_str(), "", caseID++, false, true, isVertex, "*", 100));
   3142 		}
   3143 
   3144 		// Cases that don't have vertex and fragment variants.
   3145 		whitespaceCommentCacheGroup->addChild(new ShaderCompilerTextureCase(context, "texture_4_lookups", "", caseID++, false, true, 4, CONDITIONAL_USAGE_NONE, CONDITIONAL_TYPE_STATIC));
   3146 		whitespaceCommentCacheGroup->addChild(new ShaderCompilerMandelbrotCase(context, "mandelbrot_32_operations", "", caseID++, false, true, 32));
   3147 	}
   3148 }
   3149 
   3150 } // Performance
   3151 } // gles3
   3152 } // deqp
   3153