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