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