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
50using tcu::TestLog;
51using tcu::Vec3;
52using tcu::Vec4;
53using tcu::Mat3;
54using tcu::Mat4;
55using std::string;
56using std::vector;
57using namespace glw; // GL types
58
59namespace deqp
60{
61
62namespace gles3
63{
64
65namespace Performance
66{
67
68static const bool	WARMUP_CPU_AT_BEGINNING_OF_CASE					= false;
69static const bool	WARMUP_CPU_BEFORE_EACH_MEASUREMENT				= true;
70
71static const int	MAX_VIEWPORT_WIDTH								= 64;
72static const int	MAX_VIEWPORT_HEIGHT								= 64;
73
74static const int	DEFAULT_MINIMUM_MEASUREMENT_COUNT				= 15;
75static const float	RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD	= 0.05f;
76
77// Texture size for the light shader and texture lookup shader cases.
78static const int	TEXTURE_WIDTH									= 64;
79static const int	TEXTURE_HEIGHT									= 64;
80
81template <typename T>
82inline 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.
90static 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.
125static 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
137template <typename T>
138static 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
147template <typename T>
148static 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
158template <typename T>
159static float vectorFloatMinimum (const vector<T>& v)
160{
161	DE_ASSERT(!v.empty());
162	return (float)*std::min_element(v.begin(), v.end());
163}
164
165template <typename T>
166static float vectorFloatMaximum (const vector<T>& v)
167{
168	DE_ASSERT(!v.empty());
169	return (float)*std::max_element(v.begin(), v.end());
170}
171
172template <typename T>
173static 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
185template <typename T>
186static float vectorFloatRelativeStandardDeviation (const vector<T>& v)
187{
188	return hackySafeRelativeResult(vectorFloatStandardDeviation(v), vectorFloatAverage(v));
189}
190
191template <typename T>
192static 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
203template <typename T>
204static float vectorFloatRelativeMedianAbsoluteDeviation (const vector<T>& v)
205{
206	return hackySafeRelativeResult(vectorFloatMedianAbsoluteDeviation(v), vectorFloatMedian(v));
207}
208
209template <typename T>
210static float vectorFloatMaximumMinusMinimum (const vector<T>& v)
211{
212	return vectorFloatMaximum(v) - vectorFloatMinimum(v);
213}
214
215template <typename T>
216static float vectorFloatRelativeMaximumMinusMinimum (const vector<T>& v)
217{
218	return hackySafeRelativeResult(vectorFloatMaximumMinusMinimum(v), vectorFloatMaximum(v));
219}
220
221template <typename T>
222static 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
236template <typename T>
237static 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>.
243static 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).
258template <int Size>
259static 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).
272template <int Size>
273static 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
285static 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
299static 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
313enum LightType
314{
315	LIGHT_DIRECTIONAL = 0,
316	LIGHT_POINT,
317
318	LIGHT_LAST,
319};
320
321enum 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.
331enum 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
340enum 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.
350enum ShaderValidity
351{
352	SHADER_VALIDITY_VALID = 0,
353	SHADER_VALIDITY_INVALID_CHAR,
354	SHADER_VALIDITY_SEMANTIC_ERROR,
355
356	SHADER_VALIDITY_LAST
357};
358
359class ShaderCompilerCase : public TestCase
360{
361public:
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
402protected:
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
414private:
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
499class ShaderCompilerLightCase : public ShaderCompilerCase
500{
501public:
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
508protected:
509	ProgramContext			generateShaderData			(int measurementNdx) const;
510
511private:
512	int						m_numLights;
513	bool					m_isVertexCase;
514	LightType				m_lightType;
515	glu::Texture2D*			m_texture;
516};
517
518class ShaderCompilerTextureCase : public ShaderCompilerCase
519{
520public:
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
527protected:
528	ProgramContext					generateShaderData			(int measurementNdx) const;
529
530private:
531	int								m_numLookups;
532	vector<glu::Texture2D*>			m_textures;
533	ConditionalUsage				m_conditionalUsage;
534	ConditionalType					m_conditionalType;
535};
536
537class ShaderCompilerLoopCase : public ShaderCompilerCase
538{
539public:
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
543protected:
544	ProgramContext		generateShaderData		(int measurementNdx) const;
545
546private:
547	int					m_numLoopIterations;
548	int					m_nestingDepth;
549	bool				m_isVertexCase;
550	LoopType			m_type;
551};
552
553class ShaderCompilerOperCase : public ShaderCompilerCase
554{
555public:
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
559protected:
560	ProgramContext		generateShaderData		(int measurementNdx) const;
561
562private:
563	string				m_oper;
564	int					m_numOperations;
565	bool				m_isVertexCase;
566};
567
568class ShaderCompilerMandelbrotCase : public ShaderCompilerCase
569{
570public:
571						ShaderCompilerMandelbrotCase	(Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numFractalIterations);
572						~ShaderCompilerMandelbrotCase	(void);
573
574protected:
575	ProgramContext		generateShaderData				(int measurementNdx) const;
576
577private:
578	int					m_numFractalIterations;
579};
580
581class InvalidShaderCompilerCase : public TestCase
582{
583public:
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
598protected:
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
610private:
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
665class InvalidShaderCompilerLightCase : public InvalidShaderCompilerCase
666{
667public:
668							InvalidShaderCompilerLightCase	(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, int numLights, LightType lightType);
669							~InvalidShaderCompilerLightCase	(void);
670
671protected:
672	ProgramContext			generateShaderSources			(int measurementNdx) const;
673
674private:
675	bool					m_isVertexCase;
676	int						m_numLights;
677	LightType				m_lightType;
678};
679
680class InvalidShaderCompilerTextureCase : public InvalidShaderCompilerCase
681{
682public:
683							InvalidShaderCompilerTextureCase	(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType);
684							~InvalidShaderCompilerTextureCase	(void);
685
686protected:
687	ProgramContext			generateShaderSources				(int measurementNdx) const;
688
689private:
690	int						m_numLookups;
691	ConditionalUsage		m_conditionalUsage;
692	ConditionalType			m_conditionalType;
693};
694
695class InvalidShaderCompilerLoopCase : public InvalidShaderCompilerCase
696{
697public:
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
701protected:
702	ProgramContext		generateShaderSources			(int measurementNdx) const;
703
704private:
705	bool				m_isVertexCase;
706	int					m_numLoopIterations;
707	int					m_nestingDepth;
708	LoopType			m_type;
709};
710
711class InvalidShaderCompilerOperCase : public InvalidShaderCompilerCase
712{
713public:
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
717protected:
718	ProgramContext		generateShaderSources			(int measurementNdx) const;
719
720private:
721	bool				m_isVertexCase;
722	string				m_oper;
723	int					m_numOperations;
724};
725
726class InvalidShaderCompilerMandelbrotCase : public InvalidShaderCompilerCase
727{
728public:
729						InvalidShaderCompilerMandelbrotCase		(Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numFractalIterations);
730						~InvalidShaderCompilerMandelbrotCase	(void);
731
732protected:
733	ProgramContext		generateShaderSources					(int measurementNdx) const;
734
735private:
736	int					m_numFractalIterations;
737};
738
739static 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.
745static 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.
757static 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.
904static 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.
1039static 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.
1065static 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.
1145static 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.
1217static 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.
1274static 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
1300static 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.
1313static 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.
1333static 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.
1362static 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.
1389static 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.
1409static 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.
1427static 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.
1463static 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.
1534static 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.
1558static 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
1575static 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
1604static 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
1640static 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
1659static 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
1670ShaderCompilerCase::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
1683ShaderCompilerCase::~ShaderCompilerCase (void)
1684{
1685}
1686
1687deUint32 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
1695void 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
1706ShaderCompilerCase::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
1721void 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
1730bool 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
1739bool 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
1753void 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
1794void 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
1812void 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
1834void 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
1842ShaderCompilerCase::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
1854bool 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
1872ShaderCompilerCase::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
2166ShaderCompilerLightCase::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
2175ShaderCompilerLightCase::~ShaderCompilerLightCase (void)
2176{
2177	ShaderCompilerLightCase::deinit();
2178}
2179
2180void ShaderCompilerLightCase::deinit (void)
2181{
2182	delete m_texture;
2183	m_texture = DE_NULL;
2184}
2185
2186void 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
2212ShaderCompilerCase::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
2226ShaderCompilerTextureCase::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
2234ShaderCompilerTextureCase::~ShaderCompilerTextureCase (void)
2235{
2236	ShaderCompilerTextureCase::deinit();
2237}
2238
2239void 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
2246void 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
2278ShaderCompilerCase::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
2292ShaderCompilerLoopCase::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
2301ShaderCompilerLoopCase::~ShaderCompilerLoopCase (void)
2302{
2303}
2304
2305ShaderCompilerCase::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
2320ShaderCompilerOperCase::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
2328ShaderCompilerOperCase::~ShaderCompilerOperCase (void)
2329{
2330}
2331
2332ShaderCompilerCase::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
2356ShaderCompilerMandelbrotCase::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
2362ShaderCompilerMandelbrotCase::~ShaderCompilerMandelbrotCase (void)
2363{
2364}
2365
2366ShaderCompilerCase::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
2381InvalidShaderCompilerCase::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
2391InvalidShaderCompilerCase::~InvalidShaderCompilerCase (void)
2392{
2393}
2394
2395deUint32 InvalidShaderCompilerCase::getSpecializationID (int measurementNdx) const
2396{
2397	return m_startHash ^ (deUint32)deInt32Hash((deInt32)measurementNdx);
2398}
2399
2400InvalidShaderCompilerCase::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
2411void 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
2420bool 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
2429void 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
2437InvalidShaderCompilerCase::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
2448void 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
2456bool 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
2474InvalidShaderCompilerCase::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
2675InvalidShaderCompilerLightCase::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
2683InvalidShaderCompilerLightCase::~InvalidShaderCompilerLightCase (void)
2684{
2685}
2686
2687InvalidShaderCompilerCase::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
2703InvalidShaderCompilerTextureCase::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
2711InvalidShaderCompilerTextureCase::~InvalidShaderCompilerTextureCase (void)
2712{
2713}
2714
2715InvalidShaderCompilerCase::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
2731InvalidShaderCompilerLoopCase::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
2740InvalidShaderCompilerLoopCase::~InvalidShaderCompilerLoopCase (void)
2741{
2742}
2743
2744InvalidShaderCompilerCase::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
2760InvalidShaderCompilerOperCase::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
2768InvalidShaderCompilerOperCase::~InvalidShaderCompilerOperCase (void)
2769{
2770}
2771
2772InvalidShaderCompilerCase::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
2796InvalidShaderCompilerMandelbrotCase::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
2802InvalidShaderCompilerMandelbrotCase::~InvalidShaderCompilerMandelbrotCase (void)
2803{
2804}
2805
2806InvalidShaderCompilerCase::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
2822void 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