1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.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 "es2pShaderCompilationCases.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 gles2
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	? "" : "\tmediump float 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		"attribute highp vec4 a_position${NAME_SPEC};\n"
763		"attribute mediump vec3 a_normal${NAME_SPEC};\n"
764		"attribute mediump vec4 a_texCoord0${NAME_SPEC};\n"
765		"uniform mediump vec3 u_material_ambientColor${NAME_SPEC};\n"
766		"uniform mediump vec4 u_material_diffuseColor${NAME_SPEC};\n"
767		"uniform mediump vec3 u_material_emissiveColor${NAME_SPEC};\n"
768		"uniform mediump vec3 u_material_specularColor${NAME_SPEC};\n"
769		"uniform mediump float u_material_shininess${NAME_SPEC};\n";
770
771	for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
772	{
773		string ndxStr = de::toString(lightNdx);
774
775		resultTemplate +=
776			"uniform mediump vec3 u_light" + ndxStr + "_color${NAME_SPEC};\n"
777			"uniform mediump vec3 u_light" + ndxStr + "_direction${NAME_SPEC};\n";
778
779		if (lightType == LIGHT_POINT)
780			resultTemplate +=
781				"uniform mediump vec4 u_light" + ndxStr + "_position${NAME_SPEC};\n"
782				"uniform mediump float u_light" + ndxStr + "_constantAttenuation${NAME_SPEC};\n"
783				"uniform mediump float u_light" + ndxStr + "_linearAttenuation${NAME_SPEC};\n"
784				"uniform mediump float u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC};\n";
785	}
786
787	resultTemplate +=
788		"uniform highp mat4 u_mvpMatrix${NAME_SPEC};\n"
789		"uniform highp mat4 u_modelViewMatrix${NAME_SPEC};\n"
790		"uniform mediump mat3 u_normalMatrix${NAME_SPEC};\n"
791		"uniform mediump mat4 u_texCoordMatrix0${NAME_SPEC};\n"
792		"varying mediump vec4 v_color${NAME_SPEC};\n"
793		"varying mediump vec2 v_texCoord0${NAME_SPEC};\n";
794
795	if (!isVertexCase)
796	{
797		resultTemplate += "varying mediump vec3 v_eyeNormal${NAME_SPEC};\n";
798
799		if (lightType == LIGHT_POINT)
800			resultTemplate +=
801				"varying mediump vec3 v_directionToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n"
802				"varying mediump float v_distanceToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n";
803	}
804
805	resultTemplate +=
806		"mediump vec3 direction (mediump vec4 from, mediump vec4 to)\n"
807		"{\n"
808		"	return vec3(to.xyz * from.w - from.xyz * to.w);\n"
809		"}\n"
810		"\n"
811		"mediump vec3 computeLighting (\n"
812		"	mediump vec3 directionToLight,\n"
813		"	mediump vec3 halfVector,\n"
814		"	mediump vec3 normal,\n"
815		"	mediump vec3 lightColor,\n"
816		"	mediump vec3 diffuseColor,\n"
817		"	mediump vec3 specularColor,\n"
818		"	mediump float shininess)\n"
819		"{\n"
820		"	mediump float normalDotDirection  = max(dot(normal, directionToLight), 0.0);\n"
821		"	mediump vec3  color               = normalDotDirection * diffuseColor * lightColor;\n"
822		"\n"
823		"	if (normalDotDirection != 0.0)\n"
824		"		color += pow(max(dot(normal, halfVector), 0.0), shininess) * specularColor * lightColor;\n"
825		"\n"
826		"	return color;\n"
827		"}\n"
828		"\n";
829
830	if (lightType == LIGHT_POINT)
831		resultTemplate +=
832			"mediump float computeDistanceAttenuation (mediump float distToLight, mediump float constAtt, mediump float linearAtt, mediump float quadraticAtt)\n"
833			"{\n"
834			"	return 1.0 / (constAtt + linearAtt * distToLight + quadraticAtt * distToLight * distToLight);\n"
835			"}\n"
836			"\n";
837
838	resultTemplate +=
839		"void main (void)\n"
840		"{\n"
841		"	highp vec4 position = a_position${NAME_SPEC};\n"
842		"	highp vec3 normal = a_normal${NAME_SPEC};\n"
843		"	gl_Position = u_mvpMatrix${NAME_SPEC} * position * (0.95 + 0.05*${FLOAT01});\n"
844		"	v_texCoord0${NAME_SPEC} = (u_texCoordMatrix0${NAME_SPEC} * a_texCoord0${NAME_SPEC}).xy;\n"
845		"	mediump vec4 color = vec4(u_material_emissiveColor${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.a);\n"
846		"\n"
847		"	highp vec4 eyePosition = u_modelViewMatrix${NAME_SPEC} * position;\n"
848		"	mediump vec3 eyeNormal = normalize(u_normalMatrix${NAME_SPEC} * normal);\n";
849
850	if (!isVertexCase)
851		resultTemplate += "\tv_eyeNormal${NAME_SPEC} = eyeNormal;\n";
852
853	resultTemplate += "\n";
854
855	for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
856	{
857		string ndxStr = de::toString(lightNdx);
858
859		resultTemplate +=
860			"	/* Light " + ndxStr + " */\n";
861
862		if (lightType == LIGHT_POINT)
863		{
864			resultTemplate +=
865				"	mediump float distanceToLight" + ndxStr + " = distance(eyePosition, u_light" + ndxStr + "_position${NAME_SPEC});\n"
866				"	mediump vec3 directionToLight" + ndxStr + " = normalize(direction(eyePosition, u_light" + ndxStr + "_position${NAME_SPEC}));\n";
867
868			if (isVertexCase)
869				resultTemplate +=
870					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
871					"	color.rgb += computeLighting(directionToLight" + ndxStr + ", halfVector" + ndxStr + ", eyeNormal, u_light" + ndxStr + "_color${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.rgb, "
872					"u_material_specularColor${NAME_SPEC}, u_material_shininess${NAME_SPEC}) * computeDistanceAttenuation(distanceToLight" + ndxStr + ", u_light" + ndxStr + "_constantAttenuation${NAME_SPEC}, "
873					"u_light" + ndxStr + "_linearAttenuation${NAME_SPEC}, u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC});\n";
874			else
875				resultTemplate +=
876					"	v_directionToLight${NAME_SPEC}[" + ndxStr + "] = directionToLight" + ndxStr + ";\n"
877					"	v_distanceToLight${NAME_SPEC}[" + ndxStr + "]  = distanceToLight" + ndxStr + ";\n";
878		}
879		else if (lightType == LIGHT_DIRECTIONAL)
880		{
881			if (isVertexCase)
882				resultTemplate +=
883					"	mediump vec3 directionToLight" + ndxStr + " = -u_light" + ndxStr + "_direction${NAME_SPEC};\n"
884					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
885					"	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";
886		}
887		else
888			DE_ASSERT(DE_FALSE);
889
890		resultTemplate += "\n";
891	}
892
893	resultTemplate +=
894		"	v_color${NAME_SPEC} = color;\n"
895		"${SEMANTIC_ERROR}"
896		"}\n"
897		"${INVALID_CHAR}";
898
899	return resultTemplate;
900}
901
902// Function for generating the fragment shader of a (directional or point) light case.
903static string lightFragmentTemplate (int numLights, bool isVertexCase, LightType lightType)
904{
905	string resultTemplate;
906
907	if (!isVertexCase)
908	{
909		resultTemplate +=
910			"uniform mediump vec3 u_material_ambientColor${NAME_SPEC};\n"
911			"uniform mediump vec4 u_material_diffuseColor${NAME_SPEC};\n"
912			"uniform mediump vec3 u_material_emissiveColor${NAME_SPEC};\n"
913			"uniform mediump vec3 u_material_specularColor${NAME_SPEC};\n"
914			"uniform mediump float u_material_shininess${NAME_SPEC};\n";
915
916		for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
917		{
918			string ndxStr = de::toString(lightNdx);
919
920			resultTemplate +=
921				"uniform mediump vec3 u_light" + ndxStr + "_color${NAME_SPEC};\n"
922				"uniform mediump vec3 u_light" + ndxStr + "_direction${NAME_SPEC};\n";
923
924			if (lightType == LIGHT_POINT)
925				resultTemplate +=
926					"uniform mediump vec4 u_light" + ndxStr + "_position${NAME_SPEC};\n"
927					"uniform mediump float u_light" + ndxStr + "_constantAttenuation${NAME_SPEC};\n"
928					"uniform mediump float u_light" + ndxStr + "_linearAttenuation${NAME_SPEC};\n"
929					"uniform mediump float u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC};\n";
930		}
931	}
932
933	resultTemplate +=
934		"uniform sampler2D u_sampler0${NAME_SPEC};\n"
935		"varying mediump vec4 v_color${NAME_SPEC};\n"
936		"varying mediump vec2 v_texCoord0${NAME_SPEC};\n";
937
938	if (!isVertexCase)
939	{
940		resultTemplate +=
941			"varying mediump vec3 v_eyeNormal${NAME_SPEC};\n";
942
943		if (lightType == LIGHT_POINT)
944			resultTemplate +=
945				"varying mediump vec3 v_directionToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n"
946				"varying mediump float v_distanceToLight${NAME_SPEC}[" + de::toString(numLights) + "];\n";
947
948		resultTemplate +=
949			"mediump vec3 direction (mediump vec4 from, mediump vec4 to)\n"
950			"{\n"
951			"	return vec3(to.xyz * from.w - from.xyz * to.w);\n"
952			"}\n"
953			"\n";
954
955		resultTemplate +=
956			"mediump vec3 computeLighting (\n"
957			"	mediump vec3 directionToLight,\n"
958			"	mediump vec3 halfVector,\n"
959			"	mediump vec3 normal,\n"
960			"	mediump vec3 lightColor,\n"
961			"	mediump vec3 diffuseColor,\n"
962			"	mediump vec3 specularColor,\n"
963			"	mediump float shininess)\n"
964			"{\n"
965			"	mediump float normalDotDirection  = max(dot(normal, directionToLight), 0.0);\n"
966			"	mediump vec3  color               = normalDotDirection * diffuseColor * lightColor;\n"
967			"\n"
968			"	if (normalDotDirection != 0.0)\n"
969			"		color += pow(max(dot(normal, halfVector), 0.0), shininess) * specularColor * lightColor;\n"
970			"\n"
971			"	return color;\n"
972			"}\n"
973			"\n";
974
975		if (lightType == LIGHT_POINT)
976			resultTemplate +=
977				"mediump float computeDistanceAttenuation (mediump float distToLight, mediump float constAtt, mediump float linearAtt, mediump float quadraticAtt)\n"
978				"{\n"
979				"	return 1.0 / (constAtt + linearAtt * distToLight + quadraticAtt * distToLight * distToLight);\n"
980				"}\n"
981				"\n";
982	}
983
984	resultTemplate +=
985		"void main (void)\n"
986		"{\n"
987		"	mediump vec2 texCoord0 = v_texCoord0${NAME_SPEC}.xy;\n"
988		"	mediump vec4 color = v_color${NAME_SPEC};\n";
989
990	if (!isVertexCase)
991	{
992		resultTemplate +=
993			"	mediump vec3 eyeNormal = normalize(v_eyeNormal${NAME_SPEC});\n"
994			"\n";
995
996		for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
997		{
998			string ndxStr = de::toString(lightNdx);
999
1000			resultTemplate +=
1001				"	/* Light " + ndxStr + " */\n";
1002
1003			if (lightType == LIGHT_POINT)
1004				resultTemplate +=
1005					"	mediump vec3 directionToLight" + ndxStr + " = normalize(v_directionToLight${NAME_SPEC}[" + ndxStr + "]);\n"
1006					"	mediump float distanceToLight" + ndxStr + " = v_distanceToLight${NAME_SPEC}[" + ndxStr + "];\n"
1007					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
1008					"	color.rgb += computeLighting(directionToLight" + ndxStr + ", halfVector" + ndxStr + ", eyeNormal, u_light" + ndxStr + "_color${NAME_SPEC}, u_material_diffuseColor${NAME_SPEC}.rgb, "
1009					"u_material_specularColor${NAME_SPEC}, u_material_shininess${NAME_SPEC}) * computeDistanceAttenuation(distanceToLight" + ndxStr + ", u_light" + ndxStr + "_constantAttenuation${NAME_SPEC}, "
1010					"u_light" + ndxStr + "_linearAttenuation${NAME_SPEC}, u_light" + ndxStr + "_quadraticAttenuation${NAME_SPEC});\n"
1011					"\n";
1012			else if (lightType == LIGHT_DIRECTIONAL)
1013				resultTemplate +=
1014					"	mediump vec3 directionToLight" + ndxStr + " = -u_light" + ndxStr + "_direction${NAME_SPEC};\n"
1015					"	mediump vec3 halfVector" + ndxStr + " = normalize(directionToLight" + ndxStr + " + vec3(0.0, 0.0, 1.0));\n"
1016					"	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"
1017					"\n";
1018			else
1019				DE_ASSERT(DE_FALSE);
1020		}
1021	}
1022
1023	resultTemplate +=
1024		"	color *= texture2D(u_sampler0${NAME_SPEC}, texCoord0);\n"
1025		"	gl_FragColor = color + ${FLOAT01};\n"
1026		"${SEMANTIC_ERROR}"
1027		"}\n"
1028		"${INVALID_CHAR}";
1029
1030	return resultTemplate;
1031}
1032
1033// Function for generating the shader attributes of a (directional or point) light case.
1034static vector<ShaderCompilerCase::AttribSpec> lightShaderAttributes (const string& nameSpecialization)
1035{
1036	vector<ShaderCompilerCase::AttribSpec> result;
1037
1038	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
1039													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
1040																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
1041																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
1042																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
1043
1044	result.push_back(ShaderCompilerCase::AttribSpec("a_normal" + nameSpecialization,
1045													combineVec4ToVec16(Vec4(0.0f, 0.0f, -1.0f, 0.0f),
1046																	   Vec4(0.0f, 0.0f, -1.0f, 0.0f),
1047																	   Vec4(0.0f, 0.0f, -1.0f, 0.0f),
1048																	   Vec4(0.0f, 0.0f, -1.0f, 0.0f))));
1049
1050	result.push_back(ShaderCompilerCase::AttribSpec("a_texCoord0" + nameSpecialization,
1051													combineVec4ToVec16(Vec4(0.0f, 0.0f, 0.0f, 0.0f),
1052																	   Vec4(1.0f, 0.0f, 0.0f, 0.0f),
1053																	   Vec4(0.0f, 1.0f, 0.0f, 0.0f),
1054																	   Vec4(1.0f, 1.0f, 0.0f, 0.0f))));
1055
1056	return result;
1057}
1058
1059// Function for generating the shader uniforms of a (directional or point) light case.
1060static vector<ShaderCompilerCase::UniformSpec> lightShaderUniforms (const string& nameSpecialization, int numLights, LightType lightType)
1061{
1062	vector<ShaderCompilerCase::UniformSpec> result;
1063
1064	result.push_back(ShaderCompilerCase::UniformSpec("u_material_ambientColor" + nameSpecialization,
1065													 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
1066													 vecTo16(Vec3(0.5f, 0.7f, 0.9f))));
1067
1068	result.push_back(ShaderCompilerCase::UniformSpec("u_material_diffuseColor" + nameSpecialization,
1069													 ShaderCompilerCase:: UniformSpec::TYPE_VEC4,
1070													 vecTo16(Vec4(0.3f, 0.4f, 0.5f, 1.0f))));
1071
1072	result.push_back(ShaderCompilerCase::UniformSpec("u_material_emissiveColor" + nameSpecialization,
1073													 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
1074													 vecTo16(Vec3(0.7f, 0.2f, 0.2f))));
1075
1076	result.push_back(ShaderCompilerCase::UniformSpec("u_material_specularColor" + nameSpecialization,
1077													 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
1078													 vecTo16(Vec3(0.2f, 0.6f, 1.0f))));
1079
1080	result.push_back(ShaderCompilerCase::UniformSpec("u_material_shininess" + nameSpecialization,
1081													 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
1082													 0.8f));
1083
1084	for (int lightNdx = 0; lightNdx < numLights; lightNdx++)
1085	{
1086		string ndxStr = de::toString(lightNdx);
1087
1088		result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_color" + nameSpecialization,
1089														 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
1090														 vecTo16(Vec3(0.8f, 0.6f, 0.3f))));
1091
1092		result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_direction" + nameSpecialization,
1093														 ShaderCompilerCase::UniformSpec::TYPE_VEC3,
1094														 vecTo16(Vec3(0.2f, 0.3f, 0.4f))));
1095
1096		if (lightType == LIGHT_POINT)
1097		{
1098			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_position" + nameSpecialization,
1099															 ShaderCompilerCase::UniformSpec::TYPE_VEC4,
1100															 vecTo16(Vec4(1.0f, 0.6f, 0.3f, 0.2f))));
1101
1102			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_constantAttenuation" + nameSpecialization,
1103															 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
1104															 0.6f));
1105
1106			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_linearAttenuation" + nameSpecialization,
1107															 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
1108															 0.5f));
1109
1110			result.push_back(ShaderCompilerCase::UniformSpec("u_light" + ndxStr + "_quadraticAttenuation" + nameSpecialization,
1111															 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
1112															 0.4f));
1113		}
1114	}
1115
1116	result.push_back(ShaderCompilerCase::UniformSpec("u_mvpMatrix" + nameSpecialization,
1117													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
1118													 arrTo16(Mat4(1.0f).getColumnMajorData())));
1119
1120	result.push_back(ShaderCompilerCase::UniformSpec("u_modelViewMatrix" + nameSpecialization,
1121													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
1122													 arrTo16(Mat4(1.0f).getColumnMajorData())));
1123
1124	result.push_back(ShaderCompilerCase::UniformSpec("u_normalMatrix" + nameSpecialization,
1125													 ShaderCompilerCase::UniformSpec::TYPE_MAT3,
1126													 arrTo16(Mat3(1.0f).getColumnMajorData())));
1127
1128	result.push_back(ShaderCompilerCase::UniformSpec("u_texCoordMatrix0" + nameSpecialization,
1129													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
1130													 arrTo16(Mat4(1.0f).getColumnMajorData())));
1131
1132	result.push_back(ShaderCompilerCase::UniformSpec("u_sampler0" + nameSpecialization,
1133													 ShaderCompilerCase::UniformSpec::TYPE_TEXTURE_UNIT,
1134													 0.0f));
1135
1136	return result;
1137}
1138
1139// Function for generating a vertex shader with a for loop.
1140static string loopVertexTemplate (LoopType type, bool isVertexCase, int numLoopIterations, int nestingDepth)
1141{
1142	string resultTemplate;
1143	string loopBound		= type == LOOP_TYPE_STATIC	? de::toString(numLoopIterations)
1144							: type == LOOP_TYPE_UNIFORM	? "int(u_loopBound${NAME_SPEC})"
1145							: type == LOOP_TYPE_DYNAMIC	? "int(a_loopBound${NAME_SPEC})"
1146							: "";
1147
1148	DE_ASSERT(!loopBound.empty());
1149
1150	resultTemplate +=
1151		"attribute highp vec4 a_position${NAME_SPEC};\n";
1152
1153	if (type == LOOP_TYPE_DYNAMIC)
1154		resultTemplate +=
1155			"attribute mediump float a_loopBound${NAME_SPEC};\n";
1156
1157	resultTemplate +=
1158		"attribute mediump vec4 a_value${NAME_SPEC};\n"
1159		"varying mediump vec4 v_value${NAME_SPEC};\n";
1160
1161	if (isVertexCase)
1162	{
1163		if (type == LOOP_TYPE_UNIFORM)
1164			resultTemplate += "uniform mediump float u_loopBound${NAME_SPEC};\n";
1165
1166		resultTemplate +=
1167			"\n"
1168			"void main()\n"
1169			"{\n"
1170			"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
1171			"	mediump vec4 value = a_value${NAME_SPEC};\n";
1172
1173		for (int i = 0; i < nestingDepth; i++)
1174		{
1175			string iterName = "i" + de::toString(i);
1176			resultTemplate += string(i + 1, '\t') + "for (int " + iterName + " = 0; " + iterName + " < " + loopBound + "; " + iterName + "++)\n";
1177		}
1178
1179		resultTemplate += string(nestingDepth + 1, '\t') + "value *= a_value${NAME_SPEC};\n";
1180
1181		resultTemplate +=
1182			"	v_value${NAME_SPEC} = value;\n";
1183	}
1184	else
1185	{
1186		if (type == LOOP_TYPE_DYNAMIC)
1187			resultTemplate +=
1188				"varying mediump float v_loopBound${NAME_SPEC};\n";
1189
1190		resultTemplate +=
1191			"\n"
1192			"void main()\n"
1193			"{\n"
1194			"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
1195			"	v_value${NAME_SPEC} = a_value${NAME_SPEC};\n";
1196
1197		if (type == LOOP_TYPE_DYNAMIC)
1198			resultTemplate +=
1199				"	v_loopBound${NAME_SPEC} = a_loopBound${NAME_SPEC};\n";
1200	}
1201
1202	resultTemplate +=
1203		"${SEMANTIC_ERROR}"
1204		"}\n"
1205		"${INVALID_CHAR}";
1206
1207	return resultTemplate;
1208}
1209
1210// Function for generating a fragment shader with a for loop.
1211static string loopFragmentTemplate (LoopType type, bool isVertexCase, int numLoopIterations, int nestingDepth)
1212{
1213	string resultTemplate;
1214	string loopBound		= type == LOOP_TYPE_STATIC	? de::toString(numLoopIterations)
1215							: type == LOOP_TYPE_UNIFORM	? "int(u_loopBound${NAME_SPEC})"
1216							: type == LOOP_TYPE_DYNAMIC	? "int(v_loopBound${NAME_SPEC})"
1217							: "";
1218
1219	DE_ASSERT(!loopBound.empty());
1220
1221	resultTemplate +=
1222		"varying mediump vec4 v_value${NAME_SPEC};\n";
1223
1224	if (!isVertexCase)
1225	{
1226		if (type == LOOP_TYPE_DYNAMIC)
1227			resultTemplate +=
1228				"varying mediump float v_loopBound${NAME_SPEC};\n";
1229		else if (type == LOOP_TYPE_UNIFORM)
1230			resultTemplate +=
1231				"uniform mediump float u_loopBound${NAME_SPEC};\n";
1232
1233		resultTemplate +=
1234			"\n"
1235			"void main()\n"
1236			"{\n"
1237			"	mediump vec4 value = v_value${NAME_SPEC};\n";
1238
1239		for (int i = 0; i < nestingDepth; i++)
1240		{
1241			string iterName = "i" + de::toString(i);
1242			resultTemplate += string(i + 1, '\t') + "for (int " + iterName + " = 0; " + iterName + " < " + loopBound + "; " + iterName + "++)\n";
1243		}
1244
1245		resultTemplate += string(nestingDepth + 1, '\t') + "value *= v_value${NAME_SPEC};\n";
1246
1247		resultTemplate +=
1248			"	gl_FragColor = value + ${FLOAT01};\n";
1249	}
1250	else
1251		resultTemplate +=
1252			"\n"
1253			"void main()\n"
1254			"{\n"
1255			"	gl_FragColor = v_value${NAME_SPEC} + ${FLOAT01};\n";
1256
1257	resultTemplate +=
1258		"${SEMANTIC_ERROR}"
1259		"}\n"
1260		"${INVALID_CHAR}";
1261
1262	return resultTemplate;
1263}
1264
1265// Function for generating the shader attributes for a loop case.
1266static vector<ShaderCompilerCase::AttribSpec> loopShaderAttributes (const string& nameSpecialization, LoopType type, int numLoopIterations)
1267{
1268	vector<ShaderCompilerCase::AttribSpec> result;
1269
1270	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
1271													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
1272																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
1273																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
1274																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
1275
1276	result.push_back(ShaderCompilerCase::AttribSpec("a_value" + nameSpecialization,
1277													combineVec4ToVec16(Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
1278																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
1279																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
1280																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f))));
1281
1282	if (type == LOOP_TYPE_DYNAMIC)
1283		result.push_back(ShaderCompilerCase::AttribSpec("a_loopBound" + nameSpecialization,
1284														combineVec4ToVec16(Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f),
1285																		   Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f),
1286																		   Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f),
1287																		   Vec4((float)numLoopIterations, 0.0f, 0.0f, 0.0f))));
1288
1289	return result;
1290}
1291
1292static vector<ShaderCompilerCase::UniformSpec> loopShaderUniforms (const string& nameSpecialization, LoopType type, int numLoopIterations)
1293{
1294	vector<ShaderCompilerCase::UniformSpec> result;
1295
1296	if (type == LOOP_TYPE_UNIFORM)
1297		result.push_back(ShaderCompilerCase::UniformSpec("u_loopBound" + nameSpecialization,
1298														 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
1299														 (float)numLoopIterations));
1300
1301	return result;
1302}
1303
1304// Function for generating the shader attributes for a case with only one attribute value in addition to the position attribute.
1305static vector<ShaderCompilerCase::AttribSpec> singleValueShaderAttributes (const string& nameSpecialization)
1306{
1307	vector<ShaderCompilerCase::AttribSpec> result;
1308
1309	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
1310													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
1311																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
1312																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
1313																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
1314
1315	result.push_back(ShaderCompilerCase::AttribSpec("a_value" + nameSpecialization,
1316													combineVec4ToVec16(Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
1317																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
1318																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f),
1319																	   Vec4( 1.0f,  1.0f,  1.0f,  1.0f))));
1320
1321	return result;
1322}
1323
1324// Function for generating a vertex shader with a binary operation chain.
1325static string binaryOpVertexTemplate (int numOperations, const char* op)
1326{
1327	string resultTemplate;
1328
1329	resultTemplate +=
1330		"attribute highp vec4 a_position${NAME_SPEC};\n"
1331		"attribute mediump vec4 a_value${NAME_SPEC};\n"
1332		"varying mediump vec4 v_value${NAME_SPEC};\n"
1333		"\n"
1334		"void main()\n"
1335		"{\n"
1336		"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
1337		"	mediump vec4 value = ";
1338
1339	for (int i = 0; i < numOperations; i++)
1340		resultTemplate += string(i > 0 ? op : "") + "a_value${NAME_SPEC}";
1341
1342	resultTemplate +=
1343		";\n"
1344		"	v_value${NAME_SPEC} = value;\n"
1345		"${SEMANTIC_ERROR}"
1346		"}\n"
1347		"${INVALID_CHAR}";
1348
1349	return resultTemplate;
1350}
1351
1352// Function for generating a fragment shader with a binary operation chain.
1353static string binaryOpFragmentTemplate (int numOperations, const char* op)
1354{
1355	string resultTemplate;
1356
1357	resultTemplate +=
1358		"varying mediump vec4 v_value${NAME_SPEC};\n"
1359		"\n"
1360		"void main()\n"
1361		"{\n"
1362		"	mediump vec4 value = ";
1363
1364	for (int i = 0; i < numOperations; i++)
1365		resultTemplate += string(i > 0 ? op : "") + "v_value${NAME_SPEC}";
1366
1367	resultTemplate +=
1368		";\n"
1369		"	gl_FragColor = value + ${FLOAT01};\n"
1370		"${SEMANTIC_ERROR}"
1371		"}\n"
1372		"${INVALID_CHAR}";
1373
1374	return resultTemplate;
1375}
1376
1377// Function for generating a vertex that takes one attribute in addition to position and just passes it to the fragment shader as a varying.
1378static string singleVaryingVertexTemplate (void)
1379{
1380	const char* resultTemplate =
1381		"attribute highp vec4 a_position${NAME_SPEC};\n"
1382		"attribute mediump vec4 a_value${NAME_SPEC};\n"
1383		"varying mediump vec4 v_value${NAME_SPEC};\n"
1384		"\n"
1385		"void main()\n"
1386		"{\n"
1387		"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
1388		"	v_value${NAME_SPEC} = a_value${NAME_SPEC};\n"
1389		"${SEMANTIC_ERROR}"
1390		"}\n"
1391		"${INVALID_CHAR}";
1392
1393	return resultTemplate;
1394}
1395
1396// Function for generating a fragment shader that takes a single varying and uses it as the color.
1397static string singleVaryingFragmentTemplate (void)
1398{
1399	const char* resultTemplate =
1400		"varying mediump vec4 v_value${NAME_SPEC};\n"
1401		"\n"
1402		"void main()\n"
1403		"{\n"
1404		"	gl_FragColor = v_value${NAME_SPEC} + ${FLOAT01};\n"
1405		"${SEMANTIC_ERROR}"
1406		"}\n"
1407		"${INVALID_CHAR}";
1408
1409	return resultTemplate;
1410}
1411
1412// Function for generating the vertex shader of a texture lookup case.
1413static string textureLookupVertexTemplate (ConditionalUsage conditionalUsage, ConditionalType conditionalType)
1414{
1415	string	resultTemplate;
1416	bool	conditionVaryingNeeded = conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_DYNAMIC;
1417
1418	resultTemplate +=
1419		"attribute highp vec4 a_position${NAME_SPEC};\n"
1420		"attribute mediump vec2 a_coords${NAME_SPEC};\n"
1421		"varying mediump vec2 v_coords${NAME_SPEC};\n";
1422
1423	if (conditionVaryingNeeded)
1424		resultTemplate +=
1425			"attribute mediump float a_condition${NAME_SPEC};\n"
1426			"varying mediump float v_condition${NAME_SPEC};\n";
1427
1428	resultTemplate +=
1429		"\n"
1430		"void main()\n"
1431		"{\n"
1432		"	gl_Position = a_position${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
1433		"	v_coords${NAME_SPEC} = a_coords${NAME_SPEC};\n";
1434
1435	if (conditionVaryingNeeded)
1436		resultTemplate +=
1437			"	v_condition${NAME_SPEC} = a_condition${NAME_SPEC};\n";
1438
1439	resultTemplate +=
1440		"${SEMANTIC_ERROR}"
1441		"}\n"
1442		"${INVALID_CHAR}";
1443
1444	return resultTemplate;
1445}
1446
1447// Function for generating the fragment shader of a texture lookup case.
1448static string textureLookupFragmentTemplate (int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
1449{
1450	string resultTemplate;
1451
1452	resultTemplate +=
1453		"varying mediump vec2 v_coords${NAME_SPEC};\n";
1454
1455	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_DYNAMIC)
1456		resultTemplate +=
1457			"varying mediump float v_condition${NAME_SPEC};\n";
1458
1459	for (int i = 0; i < numLookups; i++)
1460		resultTemplate +=
1461			"uniform sampler2D u_sampler" + de::toString(i) + "${NAME_SPEC};\n";
1462
1463	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_UNIFORM)
1464		resultTemplate +=
1465			"uniform mediump float u_condition${NAME_SPEC};\n";
1466
1467	resultTemplate +=
1468		"\n"
1469		"void main()\n"
1470		"{\n"
1471		"	mediump vec4 color = vec4(0.0);\n";
1472
1473	const char* conditionalTerm = conditionalType == CONDITIONAL_TYPE_STATIC	? "1.0 > 0.0"
1474								: conditionalType == CONDITIONAL_TYPE_UNIFORM	? "u_condition${NAME_SPEC} > 0.0"
1475								: conditionalType == CONDITIONAL_TYPE_DYNAMIC	? "v_condition${NAME_SPEC} > 0.0"
1476								: DE_NULL;
1477
1478	DE_ASSERT(conditionalTerm != DE_NULL);
1479
1480	if (conditionalUsage == CONDITIONAL_USAGE_FIRST_HALF)
1481		resultTemplate += string("") +
1482			"	if (" + conditionalTerm + ")\n"
1483			"	{\n";
1484
1485	for (int i = 0; i < numLookups; i++)
1486	{
1487		if (conditionalUsage == CONDITIONAL_USAGE_FIRST_HALF)
1488		{
1489			if (i < (numLookups + 1) / 2)
1490				resultTemplate += "\t";
1491		}
1492		else if (conditionalUsage == CONDITIONAL_USAGE_EVERY_OTHER)
1493		{
1494			if (i % 2 == 0)
1495				resultTemplate += string("") +
1496					"	if (" + conditionalTerm + ")\n"
1497					"\t";
1498		}
1499
1500		resultTemplate +=
1501			"	color += texture2D(u_sampler" + de::toString(i) + "${NAME_SPEC}, v_coords${NAME_SPEC});\n";
1502
1503		if (conditionalUsage == CONDITIONAL_USAGE_FIRST_HALF && i == (numLookups - 1) / 2)
1504			resultTemplate += "\t}\n";
1505	}
1506
1507	resultTemplate +=
1508		"	gl_FragColor = color/" + de::toString(numLookups) + ".0 + ${FLOAT01};\n" +
1509		"${SEMANTIC_ERROR}"
1510		"}\n"
1511		"${INVALID_CHAR}";
1512
1513	return resultTemplate;
1514}
1515
1516// Function for generating the shader attributes of a texture lookup case.
1517static vector<ShaderCompilerCase::AttribSpec> textureLookupShaderAttributes (const string& nameSpecialization, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
1518{
1519	vector<ShaderCompilerCase::AttribSpec> result;
1520
1521	result.push_back(ShaderCompilerCase::AttribSpec("a_position" + nameSpecialization,
1522													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
1523																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
1524																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
1525																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
1526
1527	result.push_back(ShaderCompilerCase::AttribSpec("a_coords" + nameSpecialization,
1528													combineVec4ToVec16(Vec4(0.0f, 0.0f, 0.0f, 0.0f),
1529																	   Vec4(0.0f, 1.0f, 0.0f, 0.0f),
1530																	   Vec4(1.0f, 0.0f, 0.0f, 0.0f),
1531																	   Vec4(1.0f, 1.0f, 0.0f, 0.0f))));
1532
1533	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_DYNAMIC)
1534		result.push_back(ShaderCompilerCase::AttribSpec("a_condition" + nameSpecialization,
1535														combineVec4ToVec16(Vec4(1.0f), Vec4(1.0f), Vec4(1.0f), Vec4(1.0f))));
1536
1537	return result;
1538}
1539
1540// Function for generating the shader uniforms of a texture lookup case.
1541static vector<ShaderCompilerCase::UniformSpec> textureLookupShaderUniforms (const string& nameSpecialization, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
1542{
1543	vector<ShaderCompilerCase::UniformSpec> result;
1544
1545	for (int i = 0; i < numLookups; i++)
1546		result.push_back(ShaderCompilerCase::UniformSpec("u_sampler" + de::toString(i) + nameSpecialization,
1547														 ShaderCompilerCase::UniformSpec::TYPE_TEXTURE_UNIT,
1548														 (float)i));
1549
1550	if (conditionalUsage != CONDITIONAL_USAGE_NONE && conditionalType == CONDITIONAL_TYPE_UNIFORM)
1551		result.push_back(ShaderCompilerCase::UniformSpec("u_condition" + nameSpecialization,
1552														 ShaderCompilerCase::UniformSpec::TYPE_FLOAT,
1553														 1.0f));
1554
1555	return result;
1556}
1557
1558static string mandelbrotVertexTemplate (void)
1559{
1560	const char* resultTemplate =
1561		"uniform highp mat4 u_mvp${NAME_SPEC};\n"
1562		"\n"
1563		"attribute highp vec4 a_vertex${NAME_SPEC};\n"
1564		"attribute highp vec4 a_coord${NAME_SPEC};\n"
1565		"\n"
1566		"varying mediump vec2 v_coord${NAME_SPEC};\n"
1567		"\n"
1568		"void main(void)\n"
1569		"{\n"
1570		"	gl_Position = u_mvp${NAME_SPEC} * a_vertex${NAME_SPEC} * (0.95 + 0.05*${FLOAT01});\n"
1571		"\n"
1572		"	float xMin = -2.0;\n"
1573		"	float xMax = +0.5;\n"
1574		"	float yMin = -1.5;\n"
1575		"	float yMax = +1.5;\n"
1576		"\n"
1577		"	v_coord${NAME_SPEC}.x = a_coord${NAME_SPEC}.x * (xMax - xMin) + xMin;\n"
1578		"	v_coord${NAME_SPEC}.y = a_coord${NAME_SPEC}.y * (yMax - yMin) + yMin;\n"
1579		"${SEMANTIC_ERROR}"
1580		"}\n"
1581		"${INVALID_CHAR}";
1582
1583	return resultTemplate;
1584}
1585
1586static string mandelbrotFragmentTemplate (int numFractalIterations)
1587{
1588	string resultTemplate =
1589		"varying mediump vec2 v_coord${NAME_SPEC};\n"
1590		"\n"
1591		"precision mediump float;\n"
1592		"\n"
1593		"#define NUM_ITERS " + de::toString(numFractalIterations) + "\n"
1594		"\n"
1595		"void main (void)\n"
1596		"{\n"
1597		"	vec2 coords = v_coord${NAME_SPEC};\n"
1598		"	float u_limit = 2.0 * 2.0;\n"
1599		"	vec2 tmp = vec2(0, 0);\n"
1600		"	int iter;\n"
1601		"\n"
1602		"	for (iter = 0; iter < NUM_ITERS; iter++)\n"
1603		"	{\n"
1604		"		tmp = vec2((tmp.x + tmp.y) * (tmp.x - tmp.y), 2.0 * (tmp.x * tmp.y)) + coords;\n"
1605		"\n"
1606		"		if (dot(tmp, tmp) > u_limit)\n"
1607		"			break;\n"
1608		"	}\n"
1609		"\n"
1610		"	vec3 color = vec3(float(iter) * (1.0 / float(NUM_ITERS)));\n"
1611		"\n"
1612		"	gl_FragColor = vec4(color, 1.0) + ${FLOAT01};\n"
1613		"${SEMANTIC_ERROR}"
1614		"}\n"
1615		"${INVALID_CHAR}";
1616
1617	return resultTemplate;
1618}
1619
1620static vector<ShaderCompilerCase::AttribSpec> mandelbrotShaderAttributes (const string& nameSpecialization)
1621{
1622	vector<ShaderCompilerCase::AttribSpec> result;
1623
1624	result.push_back(ShaderCompilerCase::AttribSpec("a_vertex" + nameSpecialization,
1625													combineVec4ToVec16(Vec4(-1.0f, -1.0f,  0.0f,  1.0f),
1626																	   Vec4(-1.0f,  1.0f,  0.0f,  1.0f),
1627																	   Vec4( 1.0f, -1.0f,  0.0f,  1.0f),
1628																	   Vec4( 1.0f,  1.0f,  0.0f,  1.0f))));
1629
1630	result.push_back(ShaderCompilerCase::AttribSpec("a_coord" + nameSpecialization,
1631													combineVec4ToVec16(Vec4(0.0f, 0.0f, 0.0f, 1.0f),
1632																	   Vec4(0.0f, 1.0f, 0.0f, 1.0f),
1633																	   Vec4(1.0f, 0.0f, 0.0f, 1.0f),
1634																	   Vec4(1.0f, 1.0f, 0.0f, 1.0f))));
1635
1636	return result;
1637}
1638
1639static vector<ShaderCompilerCase::UniformSpec> mandelbrotShaderUniforms (const string& nameSpecialization)
1640{
1641	vector<ShaderCompilerCase::UniformSpec> result;
1642
1643	result.push_back(ShaderCompilerCase::UniformSpec("u_mvp" + nameSpecialization,
1644													 ShaderCompilerCase::UniformSpec::TYPE_MAT4,
1645													 arrTo16(Mat4(1.0f).getColumnMajorData())));
1646
1647	return result;
1648}
1649
1650ShaderCompilerCase::ShaderCompilerCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments)
1651	: TestCase								(context, tcu::NODETYPE_PERFORMANCE, name, description)
1652	, m_viewportWidth						(0)
1653	, m_viewportHeight						(0)
1654	, m_avoidCache							(avoidCache)
1655	, m_addWhitespaceAndComments			(addWhitespaceAndComments)
1656	, m_startHash							((deUint32)(deUint64Hash(deGetTime()) ^ deUint64Hash(deGetMicroseconds()) ^ deInt32Hash(caseID)))
1657{
1658	int cmdLineIterCount = context.getTestContext().getCommandLine().getTestIterationCount();
1659	m_minimumMeasurementCount = cmdLineIterCount > 0 ? cmdLineIterCount : DEFAULT_MINIMUM_MEASUREMENT_COUNT;
1660	m_maximumMeasurementCount = m_minimumMeasurementCount*3;
1661}
1662
1663ShaderCompilerCase::~ShaderCompilerCase (void)
1664{
1665}
1666
1667deUint32 ShaderCompilerCase::getSpecializationID (int measurementNdx) const
1668{
1669	if (m_avoidCache)
1670		return m_startHash ^ (deUint32)deInt32Hash((deInt32)measurementNdx);
1671	else
1672		return m_startHash;
1673}
1674
1675void ShaderCompilerCase::init (void)
1676{
1677	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
1678	const tcu::RenderTarget&	renderTarget	= m_context.getRenderContext().getRenderTarget();
1679
1680	m_viewportWidth		= deMin32(MAX_VIEWPORT_WIDTH, renderTarget.getWidth());
1681	m_viewportHeight	= deMin32(MAX_VIEWPORT_HEIGHT, renderTarget.getHeight());
1682
1683	gl.viewport(0, 0, m_viewportWidth, m_viewportHeight);
1684}
1685
1686ShaderCompilerCase::ShadersAndProgram ShaderCompilerCase::createShadersAndProgram (void) const
1687{
1688	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
1689	ShadersAndProgram		result;
1690
1691	result.vertShader	= gl.createShader(GL_VERTEX_SHADER);
1692	result.fragShader	= gl.createShader(GL_FRAGMENT_SHADER);
1693	result.program		= gl.createProgram();
1694
1695	gl.attachShader(result.program, result.vertShader);
1696	gl.attachShader(result.program, result.fragShader);
1697
1698	return result;
1699}
1700
1701void ShaderCompilerCase::setShaderSources (deUint32 vertShader, deUint32 fragShader, const ProgramContext& progCtx) const
1702{
1703	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1704	const char* vertShaderSourceCStr = progCtx.vertShaderSource.c_str();
1705	const char* fragShaderSourceCStr = progCtx.fragShaderSource.c_str();
1706	gl.shaderSource(vertShader, 1, &vertShaderSourceCStr, DE_NULL);
1707	gl.shaderSource(fragShader, 1, &fragShaderSourceCStr, DE_NULL);
1708}
1709
1710bool ShaderCompilerCase::compileShader (deUint32 shader) const
1711{
1712	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1713	GLint status = 0;
1714	gl.compileShader(shader);
1715	gl.getShaderiv(shader, GL_COMPILE_STATUS, &status);
1716	return status != 0;
1717}
1718
1719bool ShaderCompilerCase::linkAndUseProgram (deUint32 program) const
1720{
1721	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1722	GLint linkStatus = 0;
1723
1724	gl.linkProgram(program);
1725	gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
1726
1727	if (linkStatus != 0)
1728		gl.useProgram(program);
1729
1730	return linkStatus != 0;
1731}
1732
1733void ShaderCompilerCase::setShaderInputs (deUint32 program, const ProgramContext& progCtx) const
1734{
1735	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1736
1737	// Setup attributes.
1738
1739	for (int attribNdx = 0; attribNdx < (int)progCtx.vertexAttributes.size(); attribNdx++)
1740	{
1741		int location = gl.getAttribLocation(program, progCtx.vertexAttributes[attribNdx].name.c_str());
1742		if (location >= 0)
1743		{
1744			gl.enableVertexAttribArray(location);
1745			gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, progCtx.vertexAttributes[attribNdx].value.getPtr());
1746		}
1747	}
1748
1749	// Setup uniforms.
1750
1751	for (int uniformNdx = 0; uniformNdx < (int)progCtx.uniforms.size(); uniformNdx++)
1752	{
1753		int location = gl.getUniformLocation(program, progCtx.uniforms[uniformNdx].name.c_str());
1754		if (location >= 0)
1755		{
1756			const float* floatPtr = progCtx.uniforms[uniformNdx].value.getPtr();
1757
1758			switch (progCtx.uniforms[uniformNdx].type)
1759			{
1760				case UniformSpec::TYPE_FLOAT:			gl.uniform1fv(location, 1, floatPtr);								break;
1761				case UniformSpec::TYPE_VEC2:			gl.uniform2fv(location, 1, floatPtr);								break;
1762				case UniformSpec::TYPE_VEC3:			gl.uniform3fv(location, 1, floatPtr);								break;
1763				case UniformSpec::TYPE_VEC4:			gl.uniform4fv(location, 1, floatPtr);								break;
1764				case UniformSpec::TYPE_MAT3:			gl.uniformMatrix3fv(location, 1, GL_FALSE, floatPtr);				break;
1765				case UniformSpec::TYPE_MAT4:			gl.uniformMatrix4fv(location, 1, GL_FALSE, floatPtr);				break;
1766				case UniformSpec::TYPE_TEXTURE_UNIT:	gl.uniform1i(location, (GLint)deRoundFloatToInt32(*floatPtr));		break;
1767				default:
1768					DE_ASSERT(DE_FALSE);
1769			}
1770		}
1771	}
1772}
1773
1774void ShaderCompilerCase::draw (void) const
1775{
1776	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1777
1778	static const deUint8 indices[] =
1779	{
1780		0, 1, 2,
1781		2, 1, 3
1782	};
1783
1784	gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1785	gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, indices);
1786
1787	// \note Read one pixel to force compilation.
1788	deUint32 pixel;
1789	gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
1790}
1791
1792void ShaderCompilerCase::cleanup (const ShadersAndProgram& shadersAndProgram, const ProgramContext& progCtx, bool linkSuccess) const
1793{
1794	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1795
1796	if (linkSuccess)
1797	{
1798		for (int attribNdx = 0; attribNdx < (int)progCtx.vertexAttributes.size(); attribNdx++)
1799		{
1800			int location = gl.getAttribLocation(shadersAndProgram.program, progCtx.vertexAttributes[attribNdx].name.c_str());
1801			if (location >= 0)
1802				gl.disableVertexAttribArray(location);
1803		}
1804	}
1805
1806	gl.useProgram(0);
1807	gl.detachShader(shadersAndProgram.program, shadersAndProgram.vertShader);
1808	gl.detachShader(shadersAndProgram.program, shadersAndProgram.fragShader);
1809	gl.deleteShader(shadersAndProgram.vertShader);
1810	gl.deleteShader(shadersAndProgram.fragShader);
1811	gl.deleteProgram(shadersAndProgram.program);
1812}
1813
1814void ShaderCompilerCase::logProgramData (const BuildInfo& buildInfo, const ProgramContext& progCtx) const
1815{
1816	m_testCtx.getLog() << TestLog::ShaderProgram(buildInfo.linkSuccess, buildInfo.logs.link)
1817					   << TestLog::Shader(QP_SHADER_TYPE_VERTEX,	progCtx.vertShaderSource, buildInfo.vertCompileSuccess, buildInfo.logs.vert)
1818					   << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT,	progCtx.fragShaderSource, buildInfo.fragCompileSuccess, buildInfo.logs.frag)
1819					   << TestLog::EndShaderProgram;
1820}
1821
1822ShaderCompilerCase::Logs ShaderCompilerCase::getLogs (const ShadersAndProgram& shadersAndProgram) const
1823{
1824	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
1825	Logs					result;
1826
1827	result.vert = getShaderInfoLog(gl, shadersAndProgram.vertShader);
1828	result.frag = getShaderInfoLog(gl, shadersAndProgram.fragShader);
1829	result.link = getProgramInfoLog(gl, shadersAndProgram.program);
1830
1831	return result;
1832}
1833
1834bool ShaderCompilerCase::goodEnoughMeasurements (const vector<Measurement>& measurements) const
1835{
1836	if ((int)measurements.size() < m_minimumMeasurementCount)
1837		return false;
1838	else
1839	{
1840		if ((int)measurements.size() >= m_maximumMeasurementCount)
1841			return true;
1842		else
1843		{
1844			vector<deInt64> totalTimesWithoutDraw;
1845			for (int i = 0; i < (int)measurements.size(); i++)
1846				totalTimesWithoutDraw.push_back(measurements[i].totalTimeWithoutDraw());
1847			return vectorFloatRelativeMedianAbsoluteDeviation(vectorLowestPercentage(totalTimesWithoutDraw, 0.5f)) < RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD;
1848		}
1849	}
1850}
1851
1852ShaderCompilerCase::IterateResult ShaderCompilerCase::iterate (void)
1853{
1854	// Before actual measurements, compile and draw with a dummy shader to avoid possible initial slowdowns in the actual test.
1855	{
1856		deUint32		specID = getSpecializationID(0);
1857		ProgramContext	progCtx;
1858		progCtx.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, SHADER_VALIDITY_VALID);
1859		progCtx.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, SHADER_VALIDITY_VALID);
1860		progCtx.vertexAttributes = singleValueShaderAttributes(getNameSpecialization(specID));
1861
1862		ShadersAndProgram shadersAndProgram = createShadersAndProgram();
1863		setShaderSources(shadersAndProgram.vertShader, shadersAndProgram.fragShader, progCtx);
1864
1865		BuildInfo buildInfo;
1866		buildInfo.vertCompileSuccess	= compileShader(shadersAndProgram.vertShader);
1867		buildInfo.fragCompileSuccess	= compileShader(shadersAndProgram.fragShader);
1868		buildInfo.linkSuccess			= linkAndUseProgram(shadersAndProgram.program);
1869		if (!(buildInfo.vertCompileSuccess && buildInfo.fragCompileSuccess && buildInfo.linkSuccess))
1870		{
1871			buildInfo.logs = getLogs(shadersAndProgram);
1872			logProgramData(buildInfo, progCtx);
1873			cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
1874			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation failed");
1875			return STOP;
1876		}
1877		setShaderInputs(shadersAndProgram.program, progCtx);
1878		draw();
1879		cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
1880	}
1881
1882	vector<Measurement>		measurements;
1883	// \note These are logged after measurements are done.
1884	ProgramContext			latestProgramContext;
1885	BuildInfo				latestBuildInfo;
1886
1887	if (WARMUP_CPU_AT_BEGINNING_OF_CASE)
1888		tcu::warmupCPU();
1889
1890	// Actual test measurements.
1891	while (!goodEnoughMeasurements(measurements))
1892	{
1893		// Create shaders, compile & link, set shader inputs and draw. Time measurement is done at relevant points.
1894		// \note Setting inputs and drawing are done twice in order to find out the time for actual compiling.
1895
1896		// \note Shader data (sources and inputs) are generated and GL shader and program objects are created before any time measurements.
1897		ProgramContext		progCtx				= generateShaderData((int)measurements.size());
1898		ShadersAndProgram	shadersAndProgram	= createShadersAndProgram();
1899		BuildInfo			buildInfo;
1900
1901		if (m_addWhitespaceAndComments)
1902		{
1903			const deUint32 hash = m_startHash ^ (deUint32)deInt32Hash((deInt32)measurements.size());
1904			progCtx.vertShaderSource = strWithWhiteSpaceAndComments(progCtx.vertShaderSource, hash);
1905			progCtx.fragShaderSource = strWithWhiteSpaceAndComments(progCtx.fragShaderSource, hash);
1906		}
1907
1908		if (WARMUP_CPU_BEFORE_EACH_MEASUREMENT)
1909			tcu::warmupCPU();
1910
1911		// \note Do NOT do anything too hefty between the first and last deGetMicroseconds() here (other than the gl calls); it would disturb the measurement.
1912
1913		deUint64 startTime = deGetMicroseconds();
1914
1915		setShaderSources(shadersAndProgram.vertShader, shadersAndProgram.fragShader, progCtx);
1916		deUint64 shaderSourceSetEndTime = deGetMicroseconds();
1917
1918		buildInfo.vertCompileSuccess = compileShader(shadersAndProgram.vertShader);
1919		deUint64 vertexShaderCompileEndTime = deGetMicroseconds();
1920
1921		buildInfo.fragCompileSuccess = compileShader(shadersAndProgram.fragShader);
1922		deUint64 fragmentShaderCompileEndTime = deGetMicroseconds();
1923
1924		buildInfo.linkSuccess = linkAndUseProgram(shadersAndProgram.program);
1925		deUint64 programLinkEndTime = deGetMicroseconds();
1926
1927		// Check compilation and linking status here, after all compilation and linking gl calls are made.
1928		if (!(buildInfo.vertCompileSuccess && buildInfo.fragCompileSuccess && buildInfo.linkSuccess))
1929		{
1930			buildInfo.logs = getLogs(shadersAndProgram);
1931			logProgramData(buildInfo, progCtx);
1932			cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
1933			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation failed");
1934			return STOP;
1935		}
1936
1937		setShaderInputs(shadersAndProgram.program, progCtx);
1938		deUint64 firstShaderInputSetEndTime = deGetMicroseconds();
1939
1940		// Draw for the first time.
1941		draw();
1942		deUint64 firstDrawEndTime = deGetMicroseconds();
1943
1944		// Set inputs and draw again.
1945
1946		setShaderInputs(shadersAndProgram.program, progCtx);
1947		deUint64 secondShaderInputSetEndTime = deGetMicroseconds();
1948
1949		draw();
1950		deUint64 secondDrawEndTime = deGetMicroseconds();
1951
1952		// De-initializations (detach shaders etc.).
1953
1954		buildInfo.logs = getLogs(shadersAndProgram);
1955		cleanup(shadersAndProgram, progCtx, buildInfo.linkSuccess);
1956
1957		// Output measurement log later (after last measurement).
1958
1959		measurements.push_back(Measurement((deInt64)(shaderSourceSetEndTime			- startTime),
1960										   (deInt64)(vertexShaderCompileEndTime		- shaderSourceSetEndTime),
1961										   (deInt64)(fragmentShaderCompileEndTime	- vertexShaderCompileEndTime),
1962										   (deInt64)(programLinkEndTime				- fragmentShaderCompileEndTime),
1963										   (deInt64)(firstShaderInputSetEndTime		- programLinkEndTime),
1964										   (deInt64)(firstDrawEndTime				- firstShaderInputSetEndTime),
1965										   (deInt64)(secondShaderInputSetEndTime	- firstDrawEndTime),
1966										   (deInt64)(secondDrawEndTime				- secondShaderInputSetEndTime)));
1967
1968		latestBuildInfo			= buildInfo;
1969		latestProgramContext	= progCtx;
1970
1971		m_testCtx.touchWatchdog(); // \note Measurements may take a while in a bad case.
1972	}
1973
1974	// End of test case, log information about measurements.
1975	{
1976		TestLog& log = m_testCtx.getLog();
1977
1978		vector<deInt64> sourceSetTimes;
1979		vector<deInt64> vertexCompileTimes;
1980		vector<deInt64> fragmentCompileTimes;
1981		vector<deInt64> programLinkTimes;
1982		vector<deInt64> firstInputSetTimes;
1983		vector<deInt64> firstDrawTimes;
1984		vector<deInt64> secondInputTimes;
1985		vector<deInt64> secondDrawTimes;
1986		vector<deInt64> firstPhaseTimes;
1987		vector<deInt64> secondPhaseTimes;
1988		vector<deInt64> totalTimesWithoutDraw;
1989		vector<deInt64> specializationTimes;
1990
1991		if (!m_avoidCache)
1992			log << TestLog::Message << "Note: Testing cache hits, so the medians and averages exclude the first iteration." << TestLog::EndMessage;
1993
1994		log << TestLog::Message << "Note: \"Specialization time\" means first draw time minus second draw time." << TestLog::EndMessage
1995			<< TestLog::Message << "Note: \"Compilation time\" means the time up to (and including) linking, plus specialization time." << TestLog::EndMessage;
1996
1997		log << TestLog::Section("IterationMeasurements", "Iteration measurements of compilation and linking times");
1998
1999		DE_ASSERT((int)measurements.size() > (m_avoidCache ? 0 : 1));
2000
2001		for (int ndx = 0; ndx < (int)measurements.size(); ndx++)
2002		{
2003			const Measurement& curMeas = measurements[ndx];
2004
2005			// Subtract time of second phase (second input setup and draw) from first (from start to end of first draw).
2006			// \note Cap if second phase seems unreasonably high (higher than first input set and draw).
2007			deInt64 timeWithoutDraw		= curMeas.totalTimeWithoutDraw();
2008
2009			// Specialization time = first draw - second draw time. Again, cap at 0 if second draw was longer than first draw.
2010			deInt64 specializationTime	= de::max<deInt64>(0, curMeas.firstDrawTime - curMeas.secondDrawTime);
2011
2012			if (ndx > 0 || m_avoidCache) // \note When allowing cache hits, don't account for the first measurement when calculating median or average.
2013			{
2014				sourceSetTimes.push_back		(curMeas.sourceSetTime);
2015				vertexCompileTimes.push_back	(curMeas.vertexCompileTime);
2016				fragmentCompileTimes.push_back	(curMeas.fragmentCompileTime);
2017				programLinkTimes.push_back		(curMeas.programLinkTime);
2018				firstInputSetTimes.push_back	(curMeas.firstInputSetTime);
2019				firstDrawTimes.push_back		(curMeas.firstDrawTime);
2020				firstPhaseTimes.push_back		(curMeas.firstPhase());
2021				secondDrawTimes.push_back		(curMeas.secondDrawTime);
2022				secondInputTimes.push_back		(curMeas.secondInputSetTime);
2023				secondPhaseTimes.push_back		(curMeas.secondPhase());
2024				totalTimesWithoutDraw.push_back	(timeWithoutDraw);
2025				specializationTimes.push_back	(specializationTime);
2026			}
2027
2028			// Log this measurement.
2029			log << TestLog::Float("Measurement" + de::toString(ndx) + "CompilationTime",
2030								  "Measurement " + de::toString(ndx) + " compilation time",
2031								  "ms", QP_KEY_TAG_TIME, (float)timeWithoutDraw / 1000.0f)
2032				<< TestLog::Float("Measurement" + de::toString(ndx) + "SpecializationTime",
2033								  "Measurement " + de::toString(ndx) + " specialization time",
2034								  "ms", QP_KEY_TAG_TIME, (float)specializationTime / 1000.0f);
2035		}
2036
2037		// Log some statistics.
2038
2039		for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
2040		{
2041			bool				isEntireRange				= entireRangeOrLowestHalf == 0;
2042			string				statNamePrefix				= isEntireRange ? "" : "LowestHalf";
2043			vector<deInt64>		rangeTotalTimes				= isEntireRange ? totalTimesWithoutDraw	: vectorLowestPercentage(totalTimesWithoutDraw,	0.5f);
2044			vector<deInt64>		rangeSpecializationTimes	= isEntireRange ? specializationTimes	: vectorLowestPercentage(specializationTimes,	0.5f);
2045
2046#define LOG_COMPILE_SPECIALIZE_TIME_STAT(NAME, DESC, FUNC)																													\
2047	log << TestLog::Float(statNamePrefix + "CompilationTime" + (NAME), (DESC) + string(" of compilation time"), "ms", QP_KEY_TAG_TIME, (FUNC)(rangeTotalTimes)/1000.0f)		\
2048		<< TestLog::Float(statNamePrefix + "SpecializationTime" + (NAME), (DESC) + string(" of specialization time"), "ms", QP_KEY_TAG_TIME, (FUNC)(rangeSpecializationTimes)/1000.0f)
2049
2050#define LOG_COMPILE_SPECIALIZE_RELATIVE_STAT(NAME, DESC, FUNC)																										\
2051	log << TestLog::Float(statNamePrefix + "CompilationTime" + (NAME), (DESC) + string(" of compilation time"), "", QP_KEY_TAG_NONE, (FUNC)(rangeTotalTimes))		\
2052		<< TestLog::Float(statNamePrefix + "SpecializationTime" + (NAME), (DESC) + string(" of specialization time"), "", QP_KEY_TAG_NONE, (FUNC)(rangeSpecializationTimes))
2053
2054			log << TestLog::Message << "\nStatistics computed from "
2055									<< (isEntireRange ? "all" : "only the lowest 50%")
2056									<< " of the above measurements:"
2057									<< TestLog::EndMessage;
2058
2059			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Median",							"Median",								vectorFloatMedian);
2060			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Average",							"Average",								vectorFloatAverage);
2061			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Minimum",							"Minimum",								vectorFloatMinimum);
2062			LOG_COMPILE_SPECIALIZE_TIME_STAT		("Maximum",							"Maximum",								vectorFloatMaximum);
2063			LOG_COMPILE_SPECIALIZE_TIME_STAT		("MedianAbsoluteDeviation",			"Median absolute deviation",			vectorFloatMedianAbsoluteDeviation);
2064			LOG_COMPILE_SPECIALIZE_RELATIVE_STAT	("RelativeMedianAbsoluteDeviation",	"Relative median absolute deviation",	vectorFloatRelativeMedianAbsoluteDeviation);
2065			LOG_COMPILE_SPECIALIZE_TIME_STAT		("StandardDeviation",				"Standard deviation",					vectorFloatStandardDeviation);
2066			LOG_COMPILE_SPECIALIZE_RELATIVE_STAT	("RelativeStandardDeviation",		"Relative standard deviation",			vectorFloatRelativeStandardDeviation);
2067			LOG_COMPILE_SPECIALIZE_TIME_STAT		("MaxMinusMin",						"Max-min",								vectorFloatMaximumMinusMinimum);
2068			LOG_COMPILE_SPECIALIZE_RELATIVE_STAT	("RelativeMaxMinusMin",				"Relative max-min",						vectorFloatRelativeMaximumMinusMinimum);
2069
2070#undef LOG_COMPILE_SPECIALIZE_RELATIVE_STAT
2071#undef LOG_COMPILE_SPECIALIZE_TIME_STAT
2072
2073			if (!isEntireRange && vectorFloatRelativeMedianAbsoluteDeviation(rangeTotalTimes) > RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD)
2074				log << TestLog::Message << "\nWARNING: couldn't achieve relative median absolute deviation under threshold value "
2075										<< RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD
2076										<< " for compilation time of the lowest 50% of measurements" << TestLog::EndMessage;
2077		}
2078
2079		log << TestLog::EndSection; // End section IterationMeasurements
2080
2081		for (int medianOrAverage = 0; medianOrAverage < 2; medianOrAverage++)
2082		{
2083			typedef float (*VecFunc)(const vector<deInt64>&);
2084
2085			bool	isMedian						= medianOrAverage == 0;
2086			string	singular						= isMedian ? "Median" : "Average";
2087			string	plural							= singular + "s";
2088			VecFunc	func							= isMedian ? (VecFunc) vectorFloatMedian<deInt64> : (VecFunc) vectorFloatAverage<deInt64>;
2089
2090			log << TestLog::Section(plural + "PerPhase", plural + " per phase");
2091
2092			for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
2093			{
2094				bool	isEntireRange	= entireRangeOrLowestHalf == 0;
2095				string	statNamePrefix	= isEntireRange ? "" : "LowestHalf";
2096				float	rangeSizeRatio	= isEntireRange ? 1.0f : 0.5f;
2097
2098#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);
2099
2100				log << TestLog::Message << (isEntireRange ? "For all measurements:" : "\nFor only the lowest 50% of the measurements:") << TestLog::EndMessage;
2101				LOG_TIME("ShaderSourceSetTime",			"shader source set time",			sourceSetTimes);
2102				LOG_TIME("VertexShaderCompileTime",		"vertex shader compile time",		vertexCompileTimes);
2103				LOG_TIME("FragmentShaderCompileTime",	"fragment shader compile time",		fragmentCompileTimes);
2104				LOG_TIME("ProgramLinkTime",				"program link time",				programLinkTimes);
2105				LOG_TIME("FirstShaderInputSetTime",		"first shader input set time",		firstInputSetTimes);
2106				LOG_TIME("FirstDrawTime",				"first draw time",					firstDrawTimes);
2107				LOG_TIME("SecondShaderInputSetTime",	"second shader input set time",		secondInputTimes);
2108				LOG_TIME("SecondDrawTime",				"second draw time",					secondDrawTimes);
2109
2110#undef LOG_TIME
2111			}
2112
2113			log << TestLog::EndSection;
2114		}
2115
2116		// Set result.
2117
2118		{
2119			log << TestLog::Message << "Note: test result is the first quartile (i.e. median of the lowest half of measurements) of compilation times" << TestLog::EndMessage;
2120			float result = vectorFloatFirstQuartile(totalTimesWithoutDraw) / 1000.0f;
2121			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(result, 2).c_str());
2122		}
2123
2124		// Log shaders.
2125
2126		if (m_avoidCache || m_addWhitespaceAndComments)
2127		{
2128			string msg = "Note: the following shaders are the ones from the last iteration; ";
2129
2130			if (m_avoidCache)
2131				msg += "variables' names and some constant expressions";
2132			if (m_addWhitespaceAndComments)
2133				msg += string(m_avoidCache ? " as well as " : "") + "whitespace and comments";
2134
2135			msg += " differ between iterations.";
2136
2137			log << TestLog::Message << msg.c_str() << TestLog::EndMessage;
2138		}
2139
2140		logProgramData(latestBuildInfo, latestProgramContext);
2141
2142		return STOP;
2143	}
2144}
2145
2146ShaderCompilerLightCase::ShaderCompilerLightCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, int numLights, LightType lightType)
2147	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
2148	, m_numLights			(numLights)
2149	, m_isVertexCase		(isVertexCase)
2150	, m_lightType			(lightType)
2151	, m_texture				(DE_NULL)
2152{
2153}
2154
2155ShaderCompilerLightCase::~ShaderCompilerLightCase (void)
2156{
2157	ShaderCompilerLightCase::deinit();
2158}
2159
2160void ShaderCompilerLightCase::deinit (void)
2161{
2162	delete m_texture;
2163	m_texture = DE_NULL;
2164}
2165
2166void ShaderCompilerLightCase::init (void)
2167{
2168	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2169
2170	// Setup texture.
2171
2172	DE_ASSERT(m_texture == DE_NULL);
2173
2174	m_texture = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, TEXTURE_WIDTH, TEXTURE_HEIGHT);
2175
2176	tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_texture->getRefTexture().getFormat());
2177
2178	m_texture->getRefTexture().allocLevel(0);
2179	tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(0), fmtInfo.valueMin, fmtInfo.valueMax);
2180
2181	gl.activeTexture(GL_TEXTURE0);
2182	gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture());
2183	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2184	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2185	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2186	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2187	m_texture->upload();
2188
2189	ShaderCompilerCase::init();
2190}
2191
2192ShaderCompilerCase::ProgramContext ShaderCompilerLightCase::generateShaderData (int measurementNdx) const
2193{
2194	deUint32		specID		= getSpecializationID(measurementNdx);
2195	string			nameSpec	= getNameSpecialization(specID);
2196	ProgramContext	result;
2197
2198	result.vertShaderSource		= specializeShaderSource(lightVertexTemplate(m_numLights, m_isVertexCase, m_lightType), specID, SHADER_VALIDITY_VALID);
2199	result.fragShaderSource		= specializeShaderSource(lightFragmentTemplate(m_numLights, m_isVertexCase, m_lightType), specID, SHADER_VALIDITY_VALID);
2200	result.vertexAttributes		= lightShaderAttributes(nameSpec);
2201	result.uniforms				= lightShaderUniforms(nameSpec, m_numLights, m_lightType);
2202
2203	return result;
2204}
2205
2206ShaderCompilerTextureCase::ShaderCompilerTextureCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
2207	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
2208	, m_numLookups			(numLookups)
2209	, m_conditionalUsage	(conditionalUsage)
2210	, m_conditionalType		(conditionalType)
2211{
2212}
2213
2214ShaderCompilerTextureCase::~ShaderCompilerTextureCase (void)
2215{
2216	ShaderCompilerTextureCase::deinit();
2217}
2218
2219void ShaderCompilerTextureCase::deinit (void)
2220{
2221	for (vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
2222		delete *i;
2223	m_textures.clear();
2224}
2225
2226void ShaderCompilerTextureCase::init (void)
2227{
2228	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2229
2230	// Setup texture.
2231
2232	DE_ASSERT(m_textures.empty());
2233
2234	m_textures.reserve(m_numLookups);
2235
2236	for (int i = 0; i < m_numLookups; i++)
2237	{
2238		glu::Texture2D*			tex		= new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, TEXTURE_WIDTH, TEXTURE_HEIGHT);
2239		tcu::TextureFormatInfo	fmtInfo	= tcu::getTextureFormatInfo(tex->getRefTexture().getFormat());
2240
2241		tex->getRefTexture().allocLevel(0);
2242		tcu::fillWithComponentGradients(tex->getRefTexture().getLevel(0), fmtInfo.valueMin, fmtInfo.valueMax);
2243
2244		gl.activeTexture(GL_TEXTURE0 + i);
2245		gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
2246		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2247		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2248		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2249		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2250		tex->upload();
2251
2252		m_textures.push_back(tex);
2253	}
2254
2255	ShaderCompilerCase::init();
2256}
2257
2258ShaderCompilerCase::ProgramContext ShaderCompilerTextureCase::generateShaderData (int measurementNdx) const
2259{
2260	deUint32		specID		= getSpecializationID(measurementNdx);
2261	string			nameSpec	= getNameSpecialization(specID);
2262	ProgramContext	result;
2263
2264	result.vertShaderSource		= specializeShaderSource(textureLookupVertexTemplate(m_conditionalUsage, m_conditionalType), specID, SHADER_VALIDITY_VALID);
2265	result.fragShaderSource		= specializeShaderSource(textureLookupFragmentTemplate(m_numLookups, m_conditionalUsage, m_conditionalType), specID, SHADER_VALIDITY_VALID);
2266	result.vertexAttributes		= textureLookupShaderAttributes(nameSpec, m_conditionalUsage, m_conditionalType);
2267	result.uniforms				= textureLookupShaderUniforms(nameSpec, m_numLookups, m_conditionalUsage, m_conditionalType);
2268
2269	return result;
2270}
2271
2272ShaderCompilerLoopCase::ShaderCompilerLoopCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, LoopType type, int numLoopIterations, int nestingDepth)
2273	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
2274	, m_numLoopIterations	(numLoopIterations)
2275	, m_nestingDepth		(nestingDepth)
2276	, m_isVertexCase		(isVertexCase)
2277	, m_type				(type)
2278{
2279}
2280
2281ShaderCompilerLoopCase::~ShaderCompilerLoopCase (void)
2282{
2283}
2284
2285ShaderCompilerCase::ProgramContext ShaderCompilerLoopCase::generateShaderData (int measurementNdx) const
2286{
2287	deUint32		specID		= getSpecializationID(measurementNdx);
2288	string			nameSpec	= getNameSpecialization(specID);
2289	ProgramContext	result;
2290
2291	result.vertShaderSource		= specializeShaderSource(loopVertexTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, SHADER_VALIDITY_VALID);
2292	result.fragShaderSource		= specializeShaderSource(loopFragmentTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, SHADER_VALIDITY_VALID);
2293
2294	result.vertexAttributes		= loopShaderAttributes(nameSpec, m_type, m_numLoopIterations);
2295	result.uniforms				= loopShaderUniforms(nameSpec, m_type, m_numLoopIterations);
2296
2297	return result;
2298}
2299
2300ShaderCompilerOperCase::ShaderCompilerOperCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, const char* oper, int numOperations)
2301	: ShaderCompilerCase	(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
2302	, m_oper				(oper)
2303	, m_numOperations		(numOperations)
2304	, m_isVertexCase		(isVertexCase)
2305{
2306}
2307
2308ShaderCompilerOperCase::~ShaderCompilerOperCase (void)
2309{
2310}
2311
2312ShaderCompilerCase::ProgramContext ShaderCompilerOperCase::generateShaderData (int measurementNdx) const
2313{
2314	deUint32		specID		= getSpecializationID(measurementNdx);
2315	string			nameSpec	= getNameSpecialization(specID);
2316	ProgramContext	result;
2317
2318	if (m_isVertexCase)
2319	{
2320		result.vertShaderSource = specializeShaderSource(binaryOpVertexTemplate(m_numOperations, m_oper.c_str()), specID, SHADER_VALIDITY_VALID);
2321		result.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, SHADER_VALIDITY_VALID);
2322	}
2323	else
2324	{
2325		result.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, SHADER_VALIDITY_VALID);
2326		result.fragShaderSource = specializeShaderSource(binaryOpFragmentTemplate(m_numOperations, m_oper.c_str()), specID, SHADER_VALIDITY_VALID);
2327	}
2328
2329	result.vertexAttributes = singleValueShaderAttributes(nameSpec);
2330
2331	result.uniforms.clear(); // No uniforms used.
2332
2333	return result;
2334}
2335
2336ShaderCompilerMandelbrotCase::ShaderCompilerMandelbrotCase (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numFractalIterations)
2337	: ShaderCompilerCase		(context, name, description, caseID, avoidCache, addWhitespaceAndComments)
2338	, m_numFractalIterations	(numFractalIterations)
2339{
2340}
2341
2342ShaderCompilerMandelbrotCase::~ShaderCompilerMandelbrotCase (void)
2343{
2344}
2345
2346ShaderCompilerCase::ProgramContext ShaderCompilerMandelbrotCase::generateShaderData (int measurementNdx) const
2347{
2348	deUint32		specID		= getSpecializationID(measurementNdx);
2349	string			nameSpec	= getNameSpecialization(specID);
2350	ProgramContext	result;
2351
2352	result.vertShaderSource = specializeShaderSource(mandelbrotVertexTemplate(), specID, SHADER_VALIDITY_VALID);
2353	result.fragShaderSource = specializeShaderSource(mandelbrotFragmentTemplate(m_numFractalIterations), specID, SHADER_VALIDITY_VALID);
2354
2355	result.vertexAttributes = mandelbrotShaderAttributes(nameSpec);
2356	result.uniforms = mandelbrotShaderUniforms(nameSpec);
2357
2358	return result;
2359}
2360
2361InvalidShaderCompilerCase::InvalidShaderCompilerCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType)
2362	: TestCase						(context, tcu::NODETYPE_PERFORMANCE, name, description)
2363	, m_invalidityType				(invalidityType)
2364	, m_startHash					((deUint32)(deUint64Hash(deGetTime()) ^ deUint64Hash(deGetMicroseconds()) ^ deInt32Hash(caseID)))
2365{
2366	int cmdLineIterCount = context.getTestContext().getCommandLine().getTestIterationCount();
2367	m_minimumMeasurementCount = cmdLineIterCount > 0 ? cmdLineIterCount : DEFAULT_MINIMUM_MEASUREMENT_COUNT;
2368	m_maximumMeasurementCount = 3*m_minimumMeasurementCount;
2369}
2370
2371InvalidShaderCompilerCase::~InvalidShaderCompilerCase (void)
2372{
2373}
2374
2375deUint32 InvalidShaderCompilerCase::getSpecializationID (int measurementNdx) const
2376{
2377	return m_startHash ^ (deUint32)deInt32Hash((deInt32)measurementNdx);
2378}
2379
2380InvalidShaderCompilerCase::Shaders InvalidShaderCompilerCase::createShaders (void) const
2381{
2382	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
2383	Shaders					result;
2384
2385	result.vertShader = gl.createShader(GL_VERTEX_SHADER);
2386	result.fragShader = gl.createShader(GL_FRAGMENT_SHADER);
2387
2388	return result;
2389}
2390
2391void InvalidShaderCompilerCase::setShaderSources (const Shaders& shaders, const ProgramContext& progCtx) const
2392{
2393	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2394	const char* vertShaderSourceCStr = progCtx.vertShaderSource.c_str();
2395	const char* fragShaderSourceCStr = progCtx.fragShaderSource.c_str();
2396	gl.shaderSource(shaders.vertShader, 1, &vertShaderSourceCStr, DE_NULL);
2397	gl.shaderSource(shaders.fragShader, 1, &fragShaderSourceCStr, DE_NULL);
2398}
2399
2400bool InvalidShaderCompilerCase::compileShader (deUint32 shader) const
2401{
2402	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2403	GLint status;
2404	gl.compileShader(shader);
2405	gl.getShaderiv(shader, GL_COMPILE_STATUS, &status);
2406	return status != 0;
2407}
2408
2409void InvalidShaderCompilerCase::logProgramData (const BuildInfo& buildInfo, const ProgramContext& progCtx) const
2410{
2411	m_testCtx.getLog() << TestLog::ShaderProgram(false, "(No linking done)")
2412					   << TestLog::Shader(QP_SHADER_TYPE_VERTEX,	progCtx.vertShaderSource, buildInfo.vertCompileSuccess, buildInfo.logs.vert)
2413					   << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT,	progCtx.fragShaderSource, buildInfo.fragCompileSuccess, buildInfo.logs.frag)
2414					   << TestLog::EndShaderProgram;
2415}
2416
2417InvalidShaderCompilerCase::Logs InvalidShaderCompilerCase::getLogs (const Shaders& shaders) const
2418{
2419	const glw::Functions&	gl = m_context.getRenderContext().getFunctions();
2420	Logs					result;
2421
2422	result.vert = getShaderInfoLog(gl, shaders.vertShader);
2423	result.frag = getShaderInfoLog(gl, shaders.fragShader);
2424
2425	return result;
2426}
2427
2428void InvalidShaderCompilerCase::cleanup (const Shaders& shaders) const
2429{
2430	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2431
2432	gl.deleteShader(shaders.vertShader);
2433	gl.deleteShader(shaders.fragShader);
2434}
2435
2436bool InvalidShaderCompilerCase::goodEnoughMeasurements (const vector<Measurement>& measurements) const
2437{
2438	if ((int)measurements.size() < m_minimumMeasurementCount)
2439		return false;
2440	else
2441	{
2442		if ((int)measurements.size() >= m_maximumMeasurementCount)
2443			return true;
2444		else
2445		{
2446			vector<deInt64> totalTimes;
2447			for (int i = 0; i < (int)measurements.size(); i++)
2448				totalTimes.push_back(measurements[i].totalTime());
2449			return vectorFloatRelativeMedianAbsoluteDeviation(vectorLowestPercentage(totalTimes, 0.5f)) < RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD;
2450		}
2451	}
2452}
2453
2454InvalidShaderCompilerCase::IterateResult InvalidShaderCompilerCase::iterate (void)
2455{
2456	ShaderValidity shaderValidity = m_invalidityType == INVALIDITY_INVALID_CHAR		? SHADER_VALIDITY_INVALID_CHAR
2457								  : m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
2458								  : SHADER_VALIDITY_LAST;
2459
2460	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
2461
2462	// Before actual measurements, compile a dummy shader to avoid possible initial slowdowns in the actual test.
2463	{
2464		deUint32		specID = getSpecializationID(0);
2465		ProgramContext	progCtx;
2466		progCtx.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, shaderValidity);
2467		progCtx.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, shaderValidity);
2468
2469		Shaders shaders = createShaders();
2470		setShaderSources(shaders, progCtx);
2471
2472		BuildInfo buildInfo;
2473		buildInfo.vertCompileSuccess = compileShader(shaders.vertShader);
2474		buildInfo.fragCompileSuccess = compileShader(shaders.fragShader);
2475		if (buildInfo.vertCompileSuccess || buildInfo.fragCompileSuccess)
2476		{
2477			buildInfo.logs = getLogs(shaders);
2478			logProgramData(buildInfo, progCtx);
2479			cleanup(shaders);
2480			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation of a shader erroneously succeeded");
2481			return STOP;
2482		}
2483		cleanup(shaders);
2484	}
2485
2486	vector<Measurement>		measurements;
2487	// \note These are logged after measurements are done.
2488	ProgramContext			latestProgramContext;
2489	BuildInfo				latestBuildInfo;
2490
2491	if (WARMUP_CPU_AT_BEGINNING_OF_CASE)
2492		tcu::warmupCPU();
2493
2494	// Actual test measurements.
2495	while (!goodEnoughMeasurements(measurements))
2496	{
2497		// Create shader and compile. Measure time.
2498
2499		// \note Shader sources are generated and GL shader objects are created before any time measurements.
2500		ProgramContext	progCtx		= generateShaderSources((int)measurements.size());
2501		Shaders			shaders		= createShaders();
2502		BuildInfo		buildInfo;
2503
2504		if (WARMUP_CPU_BEFORE_EACH_MEASUREMENT)
2505			tcu::warmupCPU();
2506
2507		// \note Do NOT do anything too hefty between the first and last deGetMicroseconds() here (other than the gl calls); it would disturb the measurement.
2508
2509		deUint64 startTime = deGetMicroseconds();
2510
2511		setShaderSources(shaders, progCtx);
2512		deUint64 shaderSourceSetEndTime = deGetMicroseconds();
2513
2514		buildInfo.vertCompileSuccess = compileShader(shaders.vertShader);
2515		deUint64 vertexShaderCompileEndTime = deGetMicroseconds();
2516
2517		buildInfo.fragCompileSuccess = compileShader(shaders.fragShader);
2518		deUint64 fragmentShaderCompileEndTime = deGetMicroseconds();
2519
2520		buildInfo.logs = getLogs(shaders);
2521
2522		// Both shader compilations should have failed.
2523		if (buildInfo.vertCompileSuccess || buildInfo.fragCompileSuccess)
2524		{
2525			logProgramData(buildInfo, progCtx);
2526			cleanup(shaders);
2527			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation of a shader erroneously succeeded");
2528			return STOP;
2529		}
2530
2531		// De-initializations (delete shaders).
2532
2533		cleanup(shaders);
2534
2535		// Output measurement log later (after last measurement).
2536
2537		measurements.push_back(Measurement((deInt64)(shaderSourceSetEndTime			- startTime),
2538										   (deInt64)(vertexShaderCompileEndTime		- shaderSourceSetEndTime),
2539										   (deInt64)(fragmentShaderCompileEndTime	- vertexShaderCompileEndTime)));
2540
2541		latestBuildInfo			= buildInfo;
2542		latestProgramContext	= progCtx;
2543
2544		m_testCtx.touchWatchdog(); // \note Measurements may take a while in a bad case.
2545	}
2546
2547	// End of test case, log information about measurements.
2548	{
2549		TestLog& log = m_testCtx.getLog();
2550
2551		vector<deInt64> sourceSetTimes;
2552		vector<deInt64> vertexCompileTimes;
2553		vector<deInt64> fragmentCompileTimes;
2554		vector<deInt64> totalTimes;
2555
2556		log << TestLog::Section("IterationMeasurements", "Iteration measurements of compilation times");
2557
2558		for (int ndx = 0; ndx < (int)measurements.size(); ndx++)
2559		{
2560			sourceSetTimes.push_back		(measurements[ndx].sourceSetTime);
2561			vertexCompileTimes.push_back	(measurements[ndx].vertexCompileTime);
2562			fragmentCompileTimes.push_back	(measurements[ndx].fragmentCompileTime);
2563			totalTimes.push_back			(measurements[ndx].totalTime());
2564
2565			// Log this measurement.
2566			log << TestLog::Float("Measurement" + de::toString(ndx) + "Time",
2567								  "Measurement " + de::toString(ndx) + " time",
2568								  "ms", QP_KEY_TAG_TIME, (float)measurements[ndx].totalTime()/1000.0f);
2569		}
2570
2571		// Log some statistics.
2572
2573		for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
2574		{
2575			bool				isEntireRange	= entireRangeOrLowestHalf == 0;
2576			string				statNamePrefix	= isEntireRange ? "" : "LowestHalf";
2577			vector<deInt64>		rangeTimes		= isEntireRange ? totalTimes : vectorLowestPercentage(totalTimes, 0.5f);
2578
2579			log << TestLog::Message << "\nStatistics computed from "
2580									<< (isEntireRange ? "all" : "only the lowest 50%")
2581									<< " of the above measurements:"
2582									<< TestLog::EndMessage;
2583
2584#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)
2585#define LOG_RELATIVE_STAT(NAME, DESC, FUNC)		log << TestLog::Float(statNamePrefix + "TotalTime" + (NAME), (DESC) + string(" of total time"), "",		QP_KEY_TAG_NONE, (FUNC)(rangeTimes))
2586
2587			LOG_TIME_STAT		("Median",							"Median",								vectorFloatMedian);
2588			LOG_TIME_STAT		("Average",							"Average",								vectorFloatAverage);
2589			LOG_TIME_STAT		("Minimum",							"Minimum",								vectorFloatMinimum);
2590			LOG_TIME_STAT		("Maximum",							"Maximum",								vectorFloatMaximum);
2591			LOG_TIME_STAT		("MedianAbsoluteDeviation",			"Median absolute deviation",			vectorFloatMedianAbsoluteDeviation);
2592			LOG_RELATIVE_STAT	("RelativeMedianAbsoluteDeviation",	"Relative median absolute deviation",	vectorFloatRelativeMedianAbsoluteDeviation);
2593			LOG_TIME_STAT		("StandardDeviation",				"Standard deviation",					vectorFloatStandardDeviation);
2594			LOG_RELATIVE_STAT	("RelativeStandardDeviation",		"Relative standard deviation",			vectorFloatRelativeStandardDeviation);
2595			LOG_TIME_STAT		("MaxMinusMin",						"Max-min",								vectorFloatMaximumMinusMinimum);
2596			LOG_RELATIVE_STAT	("RelativeMaxMinusMin",				"Relative max-min",						vectorFloatRelativeMaximumMinusMinimum);
2597
2598#undef LOG_TIME_STAT
2599#undef LOG_RELATIVE_STAT
2600
2601			if (!isEntireRange && vectorFloatRelativeMedianAbsoluteDeviation(rangeTimes) > RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD)
2602				log << TestLog::Message << "\nWARNING: couldn't achieve relative median absolute deviation under threshold value " << RELATIVE_MEDIAN_ABSOLUTE_DEVIATION_THRESHOLD << TestLog::EndMessage;
2603		}
2604
2605		log << TestLog::EndSection; // End section IterationMeasurements
2606
2607		for (int medianOrAverage = 0; medianOrAverage < 2; medianOrAverage++)
2608		{
2609			typedef float (*VecFunc)(const vector<deInt64>&);
2610
2611			bool	isMedian						= medianOrAverage == 0;
2612			string	singular						= isMedian ? "Median" : "Average";
2613			string	plural							= singular + "s";
2614			VecFunc func							= isMedian ? (VecFunc) vectorFloatMedian<deInt64> : (VecFunc) vectorFloatAverage<deInt64>;
2615
2616			log << TestLog::Section(plural + "PerPhase", plural + " per phase");
2617
2618			for (int entireRangeOrLowestHalf = 0; entireRangeOrLowestHalf < 2; entireRangeOrLowestHalf++)
2619			{
2620				bool	isEntireRange	= entireRangeOrLowestHalf == 0;
2621				string	statNamePrefix	= isEntireRange ? "" : "LowestHalf";
2622				float	rangeSizeRatio	= isEntireRange ? 1.0f : 0.5f;
2623
2624#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);
2625
2626				log << TestLog::Message << (isEntireRange ? "For all measurements:" : "\nFor only the lowest 50% of the measurements:") << TestLog::EndMessage;
2627				LOG_TIME("ShaderSourceSetTime",			"shader source set time",			sourceSetTimes);
2628				LOG_TIME("VertexShaderCompileTime",		"vertex shader compile time",		vertexCompileTimes);
2629				LOG_TIME("FragmentShaderCompileTime",	"fragment shader compile time",		fragmentCompileTimes);
2630
2631#undef LOG_TIME
2632			}
2633
2634			log << TestLog::EndSection;
2635		}
2636
2637		// Set result.
2638
2639		{
2640			log << TestLog::Message << "Note: test result is the first quartile (i.e. median of the lowest half of measurements) of total times" << TestLog::EndMessage;
2641			float result = vectorFloatFirstQuartile(totalTimes) / 1000.0f;
2642			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(result, 2).c_str());
2643		}
2644
2645		// Log shaders.
2646
2647		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;
2648
2649		logProgramData(latestBuildInfo, latestProgramContext);
2650
2651		return STOP;
2652	}
2653}
2654
2655InvalidShaderCompilerLightCase::InvalidShaderCompilerLightCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, int numLights, LightType lightType)
2656	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
2657	, m_isVertexCase			(isVertexCase)
2658	, m_numLights				(numLights)
2659	, m_lightType				(lightType)
2660{
2661}
2662
2663InvalidShaderCompilerLightCase::~InvalidShaderCompilerLightCase (void)
2664{
2665}
2666
2667InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerLightCase::generateShaderSources (int measurementNdx) const
2668{
2669	deUint32		specID			= getSpecializationID(measurementNdx);
2670	ProgramContext	result;
2671	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
2672									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
2673									: SHADER_VALIDITY_LAST;
2674
2675	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
2676
2677	result.vertShaderSource = specializeShaderSource(lightVertexTemplate(m_numLights, m_isVertexCase, m_lightType), specID, shaderValidity);
2678	result.fragShaderSource = specializeShaderSource(lightFragmentTemplate(m_numLights, m_isVertexCase, m_lightType), specID, shaderValidity);
2679
2680	return result;
2681}
2682
2683InvalidShaderCompilerTextureCase::InvalidShaderCompilerTextureCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType)
2684	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
2685	, m_numLookups				(numLookups)
2686	, m_conditionalUsage		(conditionalUsage)
2687	, m_conditionalType			(conditionalType)
2688{
2689}
2690
2691InvalidShaderCompilerTextureCase::~InvalidShaderCompilerTextureCase (void)
2692{
2693}
2694
2695InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerTextureCase::generateShaderSources (int measurementNdx) const
2696{
2697	deUint32		specID			= getSpecializationID(measurementNdx);
2698	ProgramContext	result;
2699	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
2700									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
2701									: SHADER_VALIDITY_LAST;
2702
2703	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
2704
2705	result.vertShaderSource = specializeShaderSource(textureLookupVertexTemplate(m_conditionalUsage, m_conditionalType), specID, shaderValidity);
2706	result.fragShaderSource = specializeShaderSource(textureLookupFragmentTemplate(m_numLookups, m_conditionalUsage, m_conditionalType), specID, shaderValidity);
2707
2708	return result;
2709}
2710
2711InvalidShaderCompilerLoopCase::InvalidShaderCompilerLoopCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, LoopType type, int numLoopIterations, int nestingDepth)
2712	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
2713	, m_isVertexCase			(isVertexCase)
2714	, m_numLoopIterations		(numLoopIterations)
2715	, m_nestingDepth			(nestingDepth)
2716	, m_type					(type)
2717{
2718}
2719
2720InvalidShaderCompilerLoopCase::~InvalidShaderCompilerLoopCase (void)
2721{
2722}
2723
2724InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerLoopCase::generateShaderSources (int measurementNdx) const
2725{
2726	deUint32		specID			= getSpecializationID(measurementNdx);
2727	ProgramContext	result;
2728	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
2729									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
2730									: SHADER_VALIDITY_LAST;
2731
2732	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
2733
2734	result.vertShaderSource = specializeShaderSource(loopVertexTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, shaderValidity);
2735	result.fragShaderSource = specializeShaderSource(loopFragmentTemplate(m_type, m_isVertexCase, m_numLoopIterations, m_nestingDepth), specID, shaderValidity);
2736
2737	return result;
2738}
2739
2740InvalidShaderCompilerOperCase::InvalidShaderCompilerOperCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, const char* oper, int numOperations)
2741	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
2742	, m_isVertexCase			(isVertexCase)
2743	, m_oper					(oper)
2744	, m_numOperations			(numOperations)
2745{
2746}
2747
2748InvalidShaderCompilerOperCase::~InvalidShaderCompilerOperCase (void)
2749{
2750}
2751
2752InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerOperCase::generateShaderSources (int measurementNdx) const
2753{
2754	deUint32		specID			= getSpecializationID(measurementNdx);
2755	ProgramContext	result;
2756	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
2757									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
2758									: SHADER_VALIDITY_LAST;
2759
2760	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
2761
2762	if (m_isVertexCase)
2763	{
2764		result.vertShaderSource = specializeShaderSource(binaryOpVertexTemplate(m_numOperations, m_oper.c_str()), specID, shaderValidity);
2765		result.fragShaderSource = specializeShaderSource(singleVaryingFragmentTemplate(), specID, shaderValidity);
2766	}
2767	else
2768	{
2769		result.vertShaderSource = specializeShaderSource(singleVaryingVertexTemplate(), specID, shaderValidity);
2770		result.fragShaderSource = specializeShaderSource(binaryOpFragmentTemplate(m_numOperations, m_oper.c_str()), specID, shaderValidity);
2771	}
2772
2773	return result;
2774}
2775
2776InvalidShaderCompilerMandelbrotCase::InvalidShaderCompilerMandelbrotCase (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numFractalIterations)
2777	: InvalidShaderCompilerCase	(context, name, description, caseID, invalidityType)
2778	, m_numFractalIterations	(numFractalIterations)
2779{
2780}
2781
2782InvalidShaderCompilerMandelbrotCase::~InvalidShaderCompilerMandelbrotCase (void)
2783{
2784}
2785
2786InvalidShaderCompilerCase::ProgramContext InvalidShaderCompilerMandelbrotCase::generateShaderSources (int measurementNdx) const
2787{
2788	deUint32		specID			= getSpecializationID(measurementNdx);
2789	ProgramContext	result;
2790	ShaderValidity	shaderValidity	= m_invalidityType == INVALIDITY_INVALID_CHAR	? SHADER_VALIDITY_INVALID_CHAR
2791									: m_invalidityType == INVALIDITY_SEMANTIC_ERROR	? SHADER_VALIDITY_SEMANTIC_ERROR
2792									: SHADER_VALIDITY_LAST;
2793
2794	DE_ASSERT(shaderValidity != SHADER_VALIDITY_LAST);
2795
2796	result.vertShaderSource = specializeShaderSource(mandelbrotVertexTemplate(), specID, shaderValidity);
2797	result.fragShaderSource = specializeShaderSource(mandelbrotFragmentTemplate(m_numFractalIterations), specID, shaderValidity);
2798
2799	return result;
2800}
2801
2802void addShaderCompilationPerformanceCases (TestCaseGroup& parentGroup)
2803{
2804	Context&	context		= parentGroup.getContext();
2805	int			caseID		= 0; // Increment this after adding each case. Used for avoiding cache hits between cases.
2806
2807	TestCaseGroup* validGroup			= new TestCaseGroup(context, "valid_shader",	"Valid Shader Compiler Cases");
2808	TestCaseGroup* invalidGroup			= new TestCaseGroup(context, "invalid_shader",	"Invalid Shader Compiler Cases");
2809	TestCaseGroup* cacheGroup			= new TestCaseGroup(context, "cache",			"Allow shader caching");
2810	parentGroup.addChild(validGroup);
2811	parentGroup.addChild(invalidGroup);
2812	parentGroup.addChild(cacheGroup);
2813
2814	TestCaseGroup* invalidCharGroup		= new TestCaseGroup(context, "invalid_char",	"Invalid Character Shader Compiler Cases");
2815	TestCaseGroup* semanticErrorGroup	= new TestCaseGroup(context, "semantic_error",	"Semantic Error Shader Compiler Cases");
2816	invalidGroup->addChild(invalidCharGroup);
2817	invalidGroup->addChild(semanticErrorGroup);
2818
2819	// Lighting shader compilation cases.
2820
2821	{
2822		static const int lightCounts[] = { 1, 2, 4, 8 };
2823
2824		TestCaseGroup* validLightingGroup			= new TestCaseGroup(context, "lighting", "Shader Compiler Lighting Cases");
2825		TestCaseGroup* invalidCharLightingGroup		= new TestCaseGroup(context, "lighting", "Invalid Character Shader Compiler Lighting Cases");
2826		TestCaseGroup* semanticErrorLightingGroup	= new TestCaseGroup(context, "lighting", "Semantic Error Shader Compiler Lighting Cases");
2827		TestCaseGroup* cacheLightingGroup			= new TestCaseGroup(context, "lighting", "Shader Compiler Lighting Cache Cases");
2828		validGroup->addChild(validLightingGroup);
2829		invalidCharGroup->addChild(invalidCharLightingGroup);
2830		semanticErrorGroup->addChild(semanticErrorLightingGroup);
2831		cacheGroup->addChild(cacheLightingGroup);
2832
2833		for (int lightType = 0; lightType < (int)LIGHT_LAST; lightType++)
2834		{
2835			const char* lightTypeName = lightType == (int)LIGHT_DIRECTIONAL	? "directional"
2836									  : lightType == (int)LIGHT_POINT		? "point"
2837									  : DE_NULL;
2838
2839			DE_ASSERT(lightTypeName != DE_NULL);
2840
2841			for (int isFrag = 0; isFrag <= 1; isFrag++)
2842			{
2843				bool		isVertex	= isFrag == 0;
2844				const char*	vertFragStr	= isVertex ? "vertex" : "fragment";
2845
2846				for (int lightCountNdx = 0; lightCountNdx < DE_LENGTH_OF_ARRAY(lightCounts); lightCountNdx++)
2847				{
2848					int numLights = lightCounts[lightCountNdx];
2849
2850					string caseName = string("") + lightTypeName + "_" + de::toString(numLights) + "_lights_" + vertFragStr;
2851
2852					// Valid shader case, no-cache and cache versions.
2853
2854					validLightingGroup->addChild(new ShaderCompilerLightCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, isVertex, numLights, (LightType)lightType));
2855					cacheLightingGroup->addChild(new ShaderCompilerLightCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, isVertex, numLights, (LightType)lightType));
2856
2857					// Invalid shader cases.
2858
2859					for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
2860					{
2861						TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharLightingGroup
2862														: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorLightingGroup
2863														: DE_NULL;
2864
2865						DE_ASSERT(curInvalidGroup != DE_NULL);
2866
2867						curInvalidGroup->addChild(new InvalidShaderCompilerLightCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, isVertex, numLights, (LightType)lightType));
2868					}
2869				}
2870			}
2871		}
2872	}
2873
2874	// Texture lookup shader compilation cases.
2875
2876	{
2877		static const int texLookupCounts[] = { 1, 2, 4, 8 };
2878
2879		TestCaseGroup* validTexGroup			= new TestCaseGroup(context, "texture", "Shader Compiler Texture Lookup Cases");
2880		TestCaseGroup* invalidCharTexGroup		= new TestCaseGroup(context, "texture", "Invalid Character Shader Compiler Texture Lookup Cases");
2881		TestCaseGroup* semanticErrorTexGroup	= new TestCaseGroup(context, "texture", "Semantic Error Shader Compiler Texture Lookup Cases");
2882		TestCaseGroup* cacheTexGroup			= new TestCaseGroup(context, "texture", "Shader Compiler Texture Lookup Cache Cases");
2883		validGroup->addChild(validTexGroup);
2884		invalidCharGroup->addChild(invalidCharTexGroup);
2885		semanticErrorGroup->addChild(semanticErrorTexGroup);
2886		cacheGroup->addChild(cacheTexGroup);
2887
2888		for (int conditionalUsage = 0; conditionalUsage < (int)CONDITIONAL_USAGE_LAST; conditionalUsage++)
2889		{
2890			const char* conditionalUsageName = conditionalUsage == (int)CONDITIONAL_USAGE_NONE			? "no_conditionals"
2891											 : conditionalUsage == (int)CONDITIONAL_USAGE_FIRST_HALF	? "first_half"
2892											 : conditionalUsage == (int)CONDITIONAL_USAGE_EVERY_OTHER	? "every_other"
2893											 : DE_NULL;
2894
2895			DE_ASSERT(conditionalUsageName != DE_NULL);
2896
2897			int lastConditionalType = conditionalUsage == (int)CONDITIONAL_USAGE_NONE ? 1 : (int)CONDITIONAL_TYPE_LAST;
2898
2899			for (int conditionalType = 0; conditionalType < lastConditionalType; conditionalType++)
2900			{
2901				const char* conditionalTypeName = conditionalType == (int)CONDITIONAL_TYPE_STATIC	? "static_conditionals"
2902												: conditionalType == (int)CONDITIONAL_TYPE_UNIFORM	? "uniform_conditionals"
2903												: conditionalType == (int)CONDITIONAL_TYPE_DYNAMIC	? "dynamic_conditionals"
2904												: DE_NULL;
2905
2906				DE_ASSERT(conditionalTypeName != DE_NULL);
2907
2908				for (int lookupCountNdx = 0; lookupCountNdx < DE_LENGTH_OF_ARRAY(texLookupCounts); lookupCountNdx++)
2909				{
2910					int numLookups = texLookupCounts[lookupCountNdx];
2911
2912					string caseName = de::toString(numLookups) + "_lookups_" + conditionalUsageName + (conditionalUsage == (int)CONDITIONAL_USAGE_NONE ? "" : string("_") + conditionalTypeName);
2913
2914					// Valid shader case, no-cache and cache versions.
2915
2916					validTexGroup->addChild(new ShaderCompilerTextureCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, numLookups, (ConditionalUsage)conditionalUsage, (ConditionalType)conditionalType));
2917					cacheTexGroup->addChild(new ShaderCompilerTextureCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, numLookups, (ConditionalUsage)conditionalUsage, (ConditionalType)conditionalType));
2918
2919					// Invalid shader cases.
2920
2921					for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
2922					{
2923						TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharTexGroup
2924														: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorTexGroup
2925														: DE_NULL;
2926
2927						DE_ASSERT(curInvalidGroup != DE_NULL);
2928
2929						curInvalidGroup->addChild(new InvalidShaderCompilerTextureCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, numLookups, (ConditionalUsage)conditionalUsage, (ConditionalType)conditionalType));
2930					}
2931				}
2932			}
2933		}
2934	}
2935
2936	// Loop shader compilation cases.
2937
2938	{
2939		static const int loopIterCounts[]		= { 10, 100, 1000 };
2940		static const int maxLoopNestingDepth	= 3;
2941		static const int maxTotalLoopIterations	= 2000; // If <loop iteration count> ** <loop nesting depth> (where ** is exponentiation) exceeds this, don't generate the case.
2942
2943		TestCaseGroup* validLoopGroup			= new TestCaseGroup(context, "loop", "Shader Compiler Loop Cases");
2944		TestCaseGroup* invalidCharLoopGroup		= new TestCaseGroup(context, "loop", "Invalid Character Shader Compiler Loop Cases");
2945		TestCaseGroup* semanticErrorLoopGroup	= new TestCaseGroup(context, "loop", "Semantic Error Shader Compiler Loop Cases");
2946		TestCaseGroup* cacheLoopGroup			= new TestCaseGroup(context, "loop", "Shader Compiler Loop Cache Cases");
2947		validGroup->addChild(validLoopGroup);
2948		invalidCharGroup->addChild(invalidCharLoopGroup);
2949		semanticErrorGroup->addChild(semanticErrorLoopGroup);
2950		cacheGroup->addChild(cacheLoopGroup);
2951
2952		for (int loopType = 0; loopType < (int)LOOP_LAST; loopType++)
2953		{
2954			const char* loopTypeName = loopType == (int)LOOP_TYPE_STATIC	? "static"
2955									 : loopType == (int)LOOP_TYPE_UNIFORM	? "uniform"
2956									 : loopType == (int)LOOP_TYPE_DYNAMIC	? "dynamic"
2957									 : DE_NULL;
2958
2959			DE_ASSERT(loopTypeName != DE_NULL);
2960
2961			TestCaseGroup* validLoopTypeGroup			= new TestCaseGroup(context, loopTypeName, "");
2962			TestCaseGroup* invalidCharLoopTypeGroup		= new TestCaseGroup(context, loopTypeName, "");
2963			TestCaseGroup* semanticErrorLoopTypeGroup	= new TestCaseGroup(context, loopTypeName, "");
2964			TestCaseGroup* cacheLoopTypeGroup			= new TestCaseGroup(context, loopTypeName, "");
2965			validLoopGroup->addChild(validLoopTypeGroup);
2966			invalidCharLoopGroup->addChild(invalidCharLoopTypeGroup);
2967			semanticErrorLoopGroup->addChild(semanticErrorLoopTypeGroup);
2968			cacheLoopGroup->addChild(cacheLoopTypeGroup);
2969
2970			for (int isFrag = 0; isFrag <= 1; isFrag++)
2971			{
2972				bool		isVertex	= isFrag == 0;
2973				const char*	vertFragStr	= isVertex ? "vertex" : "fragment";
2974
2975				// \note Non-static loop cases with different iteration counts have identical shaders, so only make one of each.
2976				int loopIterCountMaxNdx = loopType != (int)LOOP_TYPE_STATIC ? 1 : DE_LENGTH_OF_ARRAY(loopIterCounts);
2977
2978				for (int nestingDepth = 1; nestingDepth <= maxLoopNestingDepth; nestingDepth++)
2979				{
2980					for (int loopIterCountNdx = 0; loopIterCountNdx < loopIterCountMaxNdx; loopIterCountNdx++)
2981					{
2982						int numIterations = loopIterCounts[loopIterCountNdx];
2983
2984						if (deFloatPow((float)numIterations, (float)nestingDepth) > (float)maxTotalLoopIterations)
2985							continue; // Don't generate too heavy tasks.
2986
2987						string validCaseName = de::toString(numIterations) + "_iterations_" + de::toString(nestingDepth) + "_levels_" + vertFragStr;
2988
2989						// Valid shader case, no-cache and cache versions.
2990
2991						validLoopTypeGroup->addChild(new ShaderCompilerLoopCase(context, validCaseName.c_str(), "", caseID++, true  /* avoid cache */, false, isVertex, (LoopType)loopType, numIterations, nestingDepth));
2992						cacheLoopTypeGroup->addChild(new ShaderCompilerLoopCase(context, validCaseName.c_str(), "", caseID++, false /* allow cache */, false, isVertex, (LoopType)loopType, numIterations, nestingDepth));
2993
2994						// Invalid shader cases.
2995
2996						for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
2997						{
2998							TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharLoopTypeGroup
2999															: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorLoopTypeGroup
3000															: DE_NULL;
3001
3002							DE_ASSERT(curInvalidGroup != DE_NULL);
3003
3004							string invalidCaseName = de::toString(nestingDepth) + "_levels_" + vertFragStr;
3005
3006							if (loopType == (int)LOOP_TYPE_STATIC)
3007								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).
3008
3009							curInvalidGroup->addChild(new InvalidShaderCompilerLoopCase(context, invalidCaseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, isVertex, (LoopType)loopType, numIterations, nestingDepth));
3010						}
3011					}
3012				}
3013			}
3014		}
3015	}
3016
3017	// Multiplication shader compilation cases.
3018
3019	{
3020		static const int multiplicationCounts[] = { 10, 100, 1000 };
3021
3022		TestCaseGroup* validMulGroup			= new TestCaseGroup(context, "multiplication", "Shader Compiler Multiplication Cases");
3023		TestCaseGroup* invalidCharMulGroup		= new TestCaseGroup(context, "multiplication", "Invalid Character Shader Compiler Multiplication Cases");
3024		TestCaseGroup* semanticErrorMulGroup	= new TestCaseGroup(context, "multiplication", "Semantic Error Shader Compiler Multiplication Cases");
3025		TestCaseGroup* cacheMulGroup			= new TestCaseGroup(context, "multiplication", "Shader Compiler Multiplication Cache Cases");
3026		validGroup->addChild(validMulGroup);
3027		invalidCharGroup->addChild(invalidCharMulGroup);
3028		semanticErrorGroup->addChild(semanticErrorMulGroup);
3029		cacheGroup->addChild(cacheMulGroup);
3030
3031		for (int isFrag = 0; isFrag <= 1; isFrag++)
3032		{
3033			bool		isVertex	= isFrag == 0;
3034			const char*	vertFragStr	= isVertex ? "vertex" : "fragment";
3035
3036			for (int operCountNdx = 0; operCountNdx < DE_LENGTH_OF_ARRAY(multiplicationCounts); operCountNdx++)
3037			{
3038				int numOpers = multiplicationCounts[operCountNdx];
3039
3040				string caseName = de::toString(numOpers) + "_operations_" + vertFragStr;
3041
3042				// Valid shader case, no-cache and cache versions.
3043
3044				validMulGroup->addChild(new ShaderCompilerOperCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, isVertex, "*", numOpers));
3045				cacheMulGroup->addChild(new ShaderCompilerOperCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, isVertex, "*", numOpers));
3046
3047				// Invalid shader cases.
3048
3049				for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
3050				{
3051					TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharMulGroup
3052													: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorMulGroup
3053													: DE_NULL;
3054
3055					DE_ASSERT(curInvalidGroup != DE_NULL);
3056
3057					curInvalidGroup->addChild(new InvalidShaderCompilerOperCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, isVertex, "*", numOpers));
3058				}
3059			}
3060		}
3061	}
3062
3063	// Mandelbrot shader compilation cases.
3064
3065	{
3066		static const int mandelbrotIterationCounts[] = { 32, 64, 128 };
3067
3068		TestCaseGroup* validMandelbrotGroup			= new TestCaseGroup(context, "mandelbrot", "Shader Compiler Mandelbrot Fractal Cases");
3069		TestCaseGroup* invalidCharMandelbrotGroup	= new TestCaseGroup(context, "mandelbrot", "Invalid Character Shader Compiler Mandelbrot Fractal Cases");
3070		TestCaseGroup* semanticErrorMandelbrotGroup	= new TestCaseGroup(context, "mandelbrot", "Semantic Error Shader Compiler Mandelbrot Fractal Cases");
3071		TestCaseGroup* cacheMandelbrotGroup			= new TestCaseGroup(context, "mandelbrot", "Shader Compiler Mandelbrot Fractal Cache Cases");
3072		validGroup->addChild(validMandelbrotGroup);
3073		invalidCharGroup->addChild(invalidCharMandelbrotGroup);
3074		semanticErrorGroup->addChild(semanticErrorMandelbrotGroup);
3075		cacheGroup->addChild(cacheMandelbrotGroup);
3076
3077		for (int iterCountNdx = 0; iterCountNdx < DE_LENGTH_OF_ARRAY(mandelbrotIterationCounts); iterCountNdx++)
3078		{
3079			int		numFractalIterations	= mandelbrotIterationCounts[iterCountNdx];
3080			string	caseName				= de::toString(numFractalIterations) + "_iterations";
3081
3082			// Valid shader case, no-cache and cache versions.
3083
3084			validMandelbrotGroup->addChild(new ShaderCompilerMandelbrotCase(context, caseName.c_str(), "", caseID++, true  /* avoid cache */, false, numFractalIterations));
3085			cacheMandelbrotGroup->addChild(new ShaderCompilerMandelbrotCase(context, caseName.c_str(), "", caseID++, false /* allow cache */, false, numFractalIterations));
3086
3087			// Invalid shader cases.
3088
3089			for (int invalidityType = 0; invalidityType < (int)InvalidShaderCompilerCase::INVALIDITY_LAST; invalidityType++)
3090			{
3091				TestCaseGroup* curInvalidGroup	= invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_INVALID_CHAR		? invalidCharMandelbrotGroup
3092												: invalidityType == (int)InvalidShaderCompilerCase::INVALIDITY_SEMANTIC_ERROR	? semanticErrorMandelbrotGroup
3093												: DE_NULL;
3094
3095				DE_ASSERT(curInvalidGroup != DE_NULL);
3096
3097				curInvalidGroup->addChild(new InvalidShaderCompilerMandelbrotCase(context, caseName.c_str(), "", caseID++, (InvalidShaderCompilerCase::InvalidityType)invalidityType, numFractalIterations));
3098			}
3099		}
3100	}
3101
3102	// Cases testing cache behaviour when whitespace and comments are added.
3103
3104	{
3105		TestCaseGroup* whitespaceCommentCacheGroup = new TestCaseGroup(context, "cache_whitespace_comment", "Cases testing the effect of whitespace and comments on caching");
3106		parentGroup.addChild(whitespaceCommentCacheGroup);
3107
3108		// \note Add just a small subset of the cases that were added above for the main performance tests.
3109
3110		// Cases with both vertex and fragment variants.
3111		for (int isFrag = 0; isFrag <= 1; isFrag++)
3112		{
3113			bool	isVertex		= isFrag == 0;
3114			string	vtxFragSuffix	= isVertex ? "_vertex" : "_fragment";
3115			string	dirLightName	= "directional_2_lights" + vtxFragSuffix;
3116			string	loopName		= "static_loop_100_iterations" + vtxFragSuffix;
3117			string	multCase		= "multiplication_100_operations" + vtxFragSuffix;
3118
3119			whitespaceCommentCacheGroup->addChild(new ShaderCompilerLightCase(context, dirLightName.c_str(), "", caseID++, false, true, isVertex, 2, LIGHT_DIRECTIONAL));
3120			whitespaceCommentCacheGroup->addChild(new ShaderCompilerLoopCase(context, loopName.c_str(), "", caseID++, false, true, isVertex, LOOP_TYPE_STATIC, 100, 1));
3121			whitespaceCommentCacheGroup->addChild(new ShaderCompilerOperCase(context, multCase.c_str(), "", caseID++, false, true, isVertex, "*", 100));
3122		}
3123
3124		// Cases that don't have vertex and fragment variants.
3125		whitespaceCommentCacheGroup->addChild(new ShaderCompilerTextureCase(context, "texture_4_lookups", "", caseID++, false, true, 4, CONDITIONAL_USAGE_NONE, CONDITIONAL_TYPE_STATIC));
3126		whitespaceCommentCacheGroup->addChild(new ShaderCompilerMandelbrotCase(context, "mandelbrot_32_operations", "", caseID++, false, true, 32));
3127	}
3128}
3129
3130} // Performance
3131} // gles2
3132} // deqp
3133