x11: Call XInitThreads()
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / performance / es2pShaderCompilationCases.cpp
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>
82 inline string toStringWithPadding (T value, int minLength)
83 {
84         std::ostringstream s;
85         s << std::setfill('0') << std::setw(minLength) << value;
86         return s.str();
87 }
88
89 // Add some whitespace and comments to str. They should depend on uniqueNumber.
90 static string strWithWhiteSpaceAndComments (const string& str, deUint32 uniqueNumber)
91 {
92         string res("");
93
94         // Find the first newline.
95         int firstLineEndNdx = 0;
96         while (firstLineEndNdx < (int)str.size() && str[firstLineEndNdx] != '\n')
97         {
98                 res += str[firstLineEndNdx];
99                 firstLineEndNdx++;
100         }
101         res += '\n';
102         DE_ASSERT(firstLineEndNdx < (int)str.size());
103
104         // Add the whitespaces and comments just after the first line.
105
106         de::Random              rnd             (uniqueNumber);
107         int                             numWS   = rnd.getInt(10, 20);
108
109         for (int i = 0; i < numWS; i++)
110                 res += " \t\n"[rnd.getInt(0, 2)];
111
112         res += "/* unique comment " + de::toString(uniqueNumber) + " */\n";
113         res += "// unique comment " + de::toString(uniqueNumber) + "\n";
114
115         for (int i = 0; i < numWS; i++)
116                 res += " \t\n"[rnd.getInt(0, 2)];
117
118         // Add the rest of the string.
119         res.append(&str.c_str()[firstLineEndNdx + 1]);
120
121         return res;
122 }
123
124 //! Helper for computing relative magnitudes while avoiding division by zero.
125 static float hackySafeRelativeResult (float x, float y)
126 {
127         // \note A possible case is that x is standard deviation, and y is average
128         //               (or similarly for median or some such). So, if y is 0, that
129         //               probably means that x is also 0(ish) (because in practice we're
130         //               dealing with non-negative values, in which case an average of 0
131         //               implies that the samples are all 0 - note that the same isn't
132         //               strictly true for things like median) so a relative result of 0
133         //               wouldn't be that far from the truth.
134         return y == 0.0f ? 0.0f : x/y;
135 }
136
137 template <typename T>
138 static float vectorFloatAverage (const vector<T>& v)
139 {
140         DE_ASSERT(!v.empty());
141         float result = 0.0f;
142         for (int i = 0; i < (int)v.size(); i++)
143                 result += (float)v[i];
144         return result / (float)v.size();
145 }
146
147 template <typename T>
148 static float vectorFloatMedian (const vector<T>& v)
149 {
150         DE_ASSERT(!v.empty());
151         vector<T> temp = v;
152         std::sort(temp.begin(), temp.end());
153         return temp.size() % 2 == 0
154                    ? 0.5f * ((float)temp[temp.size()/2-1] + (float)temp[temp.size()/2])
155                    : (float)temp[temp.size()/2];
156 }
157
158 template <typename T>
159 static float vectorFloatMinimum (const vector<T>& v)
160 {
161         DE_ASSERT(!v.empty());
162         return (float)*std::min_element(v.begin(), v.end());
163 }
164
165 template <typename T>
166 static float vectorFloatMaximum (const vector<T>& v)
167 {
168         DE_ASSERT(!v.empty());
169         return (float)*std::max_element(v.begin(), v.end());
170 }
171
172 template <typename T>
173 static float vectorFloatStandardDeviation (const vector<T>& v)
174 {
175         float average   = vectorFloatAverage(v);
176         float result    = 0.0f;
177         for (int i = 0; i < (int)v.size(); i++)
178         {
179                 float d = (float)v[i] - average;
180                 result += d*d;
181         }
182         return deFloatSqrt(result/(float)v.size());
183 }
184
185 template <typename T>
186 static float vectorFloatRelativeStandardDeviation (const vector<T>& v)
187 {
188         return hackySafeRelativeResult(vectorFloatStandardDeviation(v), vectorFloatAverage(v));
189 }
190
191 template <typename T>
192 static float vectorFloatMedianAbsoluteDeviation (const vector<T>& v)
193 {
194         float                   median                          = vectorFloatMedian(v);
195         vector<float>   absoluteDeviations      (v.size());
196
197         for (int i = 0; i < (int)v.size(); i++)
198                 absoluteDeviations[i] = deFloatAbs((float)v[i] - median);
199
200         return vectorFloatMedian(absoluteDeviations);
201 }
202
203 template <typename T>
204 static float vectorFloatRelativeMedianAbsoluteDeviation (const vector<T>& v)
205 {
206         return hackySafeRelativeResult(vectorFloatMedianAbsoluteDeviation(v), vectorFloatMedian(v));
207 }
208
209 template <typename T>
210 static float vectorFloatMaximumMinusMinimum (const vector<T>& v)
211 {
212         return vectorFloatMaximum(v) - vectorFloatMinimum(v);
213 }
214
215 template <typename T>
216 static float vectorFloatRelativeMaximumMinusMinimum (const vector<T>& v)
217 {
218         return hackySafeRelativeResult(vectorFloatMaximumMinusMinimum(v), vectorFloatMaximum(v));
219 }
220
221 template <typename T>
222 static vector<T> vectorLowestPercentage (const vector<T>& v, float factor)
223 {
224         DE_ASSERT(0.0f < factor && factor <= 1.0f);
225
226         int                     targetSize      = (int)(deFloatCeil(factor*(float)v.size()));
227         vector<T>       temp            = v;
228         std::sort(temp.begin(), temp.end());
229
230         while ((int)temp.size() > targetSize)
231                 temp.pop_back();
232
233         return temp;
234 }
235
236 template <typename T>
237 static float vectorFloatFirstQuartile (const vector<T>& v)
238 {
239         return vectorFloatMedian(vectorLowestPercentage(v, 0.5f));
240 }
241
242 // Helper function for combining 4 tcu::Vec4's into one tcu::Vector<float, 16>.
243 static tcu::Vector<float, 16> combineVec4ToVec16 (const Vec4& a0, const Vec4& a1, const Vec4& a2, const Vec4& a3)
244 {
245         tcu::Vector<float, 16> result;
246
247         for (int vecNdx = 0; vecNdx < 4; vecNdx++)
248         {
249                 const Vec4& srcVec = vecNdx == 0 ? a0 : vecNdx == 1 ? a1 : vecNdx == 2 ? a2 : a3;
250                 for (int i = 0; i < 4; i++)
251                         result[vecNdx*4 + i] = srcVec[i];
252         }
253
254         return result;
255 }
256
257 // Helper function for extending an n-sized (n <= 16) vector to a 16-sized vector (padded with zeros).
258 template <int Size>
259 static tcu::Vector<float, 16> vecTo16 (const tcu::Vector<float, Size>& vec)
260 {
261         DE_STATIC_ASSERT(Size <= 16);
262
263         tcu::Vector<float, 16> res(0.0f);
264
265         for (int i = 0; i < Size; i++)
266                 res[i] = vec[i];
267
268         return res;
269 }
270
271 // Helper function for extending an n-sized (n <= 16) array to a 16-sized vector (padded with zeros).
272 template <int Size>
273 static tcu::Vector<float, 16> arrTo16 (const tcu::Array<float, Size>& arr)
274 {
275         DE_STATIC_ASSERT(Size <= 16);
276
277         tcu::Vector<float, 16> res(0.0f);
278
279         for(int i = 0; i < Size; i++)
280                 res[i] = arr[i];
281
282         return res;
283 }
284
285 static string getShaderInfoLog (const glw::Functions& gl, deUint32 shader)
286 {
287         string                  result;
288         int                             infoLogLen = 0;
289         vector<char>    infoLogBuf;
290
291         gl.getShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
292         infoLogBuf.resize(infoLogLen + 1);
293         gl.getShaderInfoLog(shader, infoLogLen + 1, DE_NULL, &infoLogBuf[0]);
294         result = &infoLogBuf[0];
295
296         return result;
297 }
298
299 static string getProgramInfoLog (const glw::Functions& gl, deUint32 program)
300 {
301         string                  result;
302         int                             infoLogLen = 0;
303         vector<char>    infoLogBuf;
304
305         gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
306         infoLogBuf.resize(infoLogLen + 1);
307         gl.getProgramInfoLog(program, infoLogLen + 1, DE_NULL, &infoLogBuf[0]);
308         result = &infoLogBuf[0];
309
310         return result;
311 }
312
313 enum LightType
314 {
315         LIGHT_DIRECTIONAL = 0,
316         LIGHT_POINT,
317
318         LIGHT_LAST,
319 };
320
321 enum LoopType
322 {
323         LOOP_TYPE_STATIC = 0,
324         LOOP_TYPE_UNIFORM,
325         LOOP_TYPE_DYNAMIC,
326
327         LOOP_LAST
328 };
329
330 // For texture lookup cases: which texture lookups are inside a conditional statement.
331 enum ConditionalUsage
332 {
333         CONDITIONAL_USAGE_NONE = 0,             // No conditional statements.
334         CONDITIONAL_USAGE_FIRST_HALF,   // First numLookUps/2 lookups are inside a conditional statement.
335         CONDITIONAL_USAGE_EVERY_OTHER,  // First, third etc. lookups are inside conditional statements.
336
337         CONDITIONAL_USAGE_LAST
338 };
339
340 enum ConditionalType
341 {
342         CONDITIONAL_TYPE_STATIC = 0,
343         CONDITIONAL_TYPE_UNIFORM,
344         CONDITIONAL_TYPE_DYNAMIC,
345
346         CONDITIONAL_TYPE_LAST
347 };
348
349 // For the invalid shader compilation tests; what kind of invalidity a shader shall contain.
350 enum ShaderValidity
351 {
352         SHADER_VALIDITY_VALID = 0,
353         SHADER_VALIDITY_INVALID_CHAR,
354         SHADER_VALIDITY_SEMANTIC_ERROR,
355
356         SHADER_VALIDITY_LAST
357 };
358
359 class ShaderCompilerCase : public TestCase
360 {
361 public:
362         struct AttribSpec
363         {
364                 string                                  name;
365                 tcu::Vector<float, 16>  value;
366
367                 AttribSpec (const string& n, const tcu::Vector<float, 16>& v) : name(n), value(v) {}
368         };
369
370         struct UniformSpec
371         {
372                 enum Type
373                 {
374                         TYPE_FLOAT = 0,
375                         TYPE_VEC2,
376                         TYPE_VEC3,
377                         TYPE_VEC4,
378
379                         TYPE_MAT3,
380                         TYPE_MAT4,
381
382                         TYPE_TEXTURE_UNIT,
383
384                         TYPE_LAST
385                 };
386
387                 string                                  name;
388                 Type                                    type;
389                 tcu::Vector<float, 16>  value;
390
391                 UniformSpec (const string& n, Type t, float v)                                                  : name(n), type(t), value(v) {}
392                 UniformSpec (const string& n, Type t, const tcu::Vector<float, 16>& v)  : name(n), type(t), value(v) {}
393         };
394
395                                                                 ShaderCompilerCase              (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments);
396                                                                 ~ShaderCompilerCase             (void);
397
398         void                                            init                                    (void);
399
400         IterateResult                           iterate                                 (void);
401
402 protected:
403         struct ProgramContext
404         {
405                 string                                  vertShaderSource;
406                 string                                  fragShaderSource;
407                 vector<AttribSpec>              vertexAttributes;
408                 vector<UniformSpec>             uniforms;
409         };
410
411         deUint32                                        getSpecializationID             (int measurementNdx) const;             // Return an ID that depends on the case ID, current measurement index and time; used to specialize attribute names etc. (avoid shader caching).
412         virtual ProgramContext          generateShaderData              (int measurementNdx) const = 0; // Generate shader sources and inputs. Attribute etc. names depend on above name specialization.
413
414 private:
415         struct Measurement
416         {
417                 // \note All times in microseconds. 32-bit integers would probably suffice (would need over an hour of test case runtime to overflow), but better safe than sorry.
418                 deInt64 sourceSetTime;
419                 deInt64 vertexCompileTime;
420                 deInt64 fragmentCompileTime;
421                 deInt64 programLinkTime;
422                 deInt64 firstInputSetTime;
423                 deInt64 firstDrawTime;
424
425                 deInt64 secondInputSetTime;
426                 deInt64 secondDrawTime;
427
428                 deInt64 firstPhase                              (void) const { return sourceSetTime + vertexCompileTime + fragmentCompileTime + programLinkTime + firstInputSetTime + firstDrawTime; }
429                 deInt64 secondPhase                             (void) const { return secondInputSetTime + secondDrawTime; }
430
431                 deInt64 totalTimeWithoutDraw    (void) const { return firstPhase() - de::min(secondPhase(), firstInputSetTime + firstDrawTime); }
432
433                 Measurement (deInt64 sourceSetTime_,
434                                          deInt64 vertexCompileTime_,
435                                          deInt64 fragmentCompileTime_,
436                                          deInt64 programLinkTime_,
437                                          deInt64 firstInputSetTime_,
438                                          deInt64 firstDrawTime_,
439                                          deInt64 secondInputSetTime_,
440                                          deInt64 secondDrawTime_)
441                         : sourceSetTime                 (sourceSetTime_)
442                         , vertexCompileTime             (vertexCompileTime_)
443                         , fragmentCompileTime   (fragmentCompileTime_)
444                         , programLinkTime               (programLinkTime_)
445                         , firstInputSetTime             (firstInputSetTime_)
446                         , firstDrawTime                 (firstDrawTime_)
447                         , secondInputSetTime    (secondInputSetTime_)
448                         , secondDrawTime                (secondDrawTime_)
449                 {
450                 }
451         };
452
453         struct ShadersAndProgram
454         {
455                 deUint32 vertShader;
456                 deUint32 fragShader;
457                 deUint32 program;
458         };
459
460         struct Logs
461         {
462                 string vert;
463                 string frag;
464                 string link;
465         };
466
467         struct BuildInfo
468         {
469                 bool vertCompileSuccess;
470                 bool fragCompileSuccess;
471                 bool linkSuccess;
472
473                 Logs logs;
474         };
475
476         ShadersAndProgram                       createShadersAndProgram         (void) const;
477         void                                            setShaderSources                        (deUint32 vertShader, deUint32 fragShader, const ProgramContext&) const;
478         bool                                            compileShader                           (deUint32 shader) const;
479         bool                                            linkAndUseProgram                       (deUint32 program) const;
480         void                                            setShaderInputs                         (deUint32 program, const ProgramContext&) const;                                                        // Set attribute pointers and uniforms.
481         void                                            draw                                            (void) const;                                                                                                                           // Clear, draw and finish.
482         void                                            cleanup                                         (const ShadersAndProgram&, const ProgramContext&, bool linkSuccess) const;      // Do GL deinitializations.
483
484         Logs                                            getLogs                                         (const ShadersAndProgram&) const;
485         void                                            logProgramData                          (const BuildInfo&, const ProgramContext&) const;
486         bool                                            goodEnoughMeasurements          (const vector<Measurement>& measurements) const;
487
488         int                                                     m_viewportWidth;
489         int                                                     m_viewportHeight;
490
491         bool                                            m_avoidCache;                           // If true, avoid caching between measurements as well (and not only between test cases).
492         bool                                            m_addWhitespaceAndComments;     // If true, add random whitespace and comments to the source (good caching should ignore those).
493         deUint32                                        m_startHash;                            // A hash from case id and time, at the time of construction.
494
495         int                                                     m_minimumMeasurementCount;
496         int                                                     m_maximumMeasurementCount;
497 };
498
499 class ShaderCompilerLightCase : public ShaderCompilerCase
500 {
501 public:
502                                                         ShaderCompilerLightCase         (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, int numLights, LightType lightType);
503                                                         ~ShaderCompilerLightCase        (void);
504
505         void                                    init                                            (void);
506         void                                    deinit                                          (void);
507
508 protected:
509         ProgramContext                  generateShaderData                      (int measurementNdx) const;
510
511 private:
512         int                                             m_numLights;
513         bool                                    m_isVertexCase;
514         LightType                               m_lightType;
515         glu::Texture2D*                 m_texture;
516 };
517
518 class ShaderCompilerTextureCase : public ShaderCompilerCase
519 {
520 public:
521                                                                         ShaderCompilerTextureCase       (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType);
522                                                                         ~ShaderCompilerTextureCase      (void);
523
524         void                                                    init                                            (void);
525         void                                                    deinit                                          (void);
526
527 protected:
528         ProgramContext                                  generateShaderData                      (int measurementNdx) const;
529
530 private:
531         int                                                             m_numLookups;
532         vector<glu::Texture2D*>                 m_textures;
533         ConditionalUsage                                m_conditionalUsage;
534         ConditionalType                                 m_conditionalType;
535 };
536
537 class ShaderCompilerLoopCase : public ShaderCompilerCase
538 {
539 public:
540                                                 ShaderCompilerLoopCase  (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, LoopType type, int numLoopIterations, int nestingDepth);
541                                                 ~ShaderCompilerLoopCase (void);
542
543 protected:
544         ProgramContext          generateShaderData              (int measurementNdx) const;
545
546 private:
547         int                                     m_numLoopIterations;
548         int                                     m_nestingDepth;
549         bool                            m_isVertexCase;
550         LoopType                        m_type;
551 };
552
553 class ShaderCompilerOperCase : public ShaderCompilerCase
554 {
555 public:
556                                                 ShaderCompilerOperCase  (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, bool isVertexCase, const char* oper, int numOperations);
557                                                 ~ShaderCompilerOperCase (void);
558
559 protected:
560         ProgramContext          generateShaderData              (int measurementNdx) const;
561
562 private:
563         string                          m_oper;
564         int                                     m_numOperations;
565         bool                            m_isVertexCase;
566 };
567
568 class ShaderCompilerMandelbrotCase : public ShaderCompilerCase
569 {
570 public:
571                                                 ShaderCompilerMandelbrotCase    (Context& context, const char* name, const char* description, int caseID, bool avoidCache, bool addWhitespaceAndComments, int numFractalIterations);
572                                                 ~ShaderCompilerMandelbrotCase   (void);
573
574 protected:
575         ProgramContext          generateShaderData                              (int measurementNdx) const;
576
577 private:
578         int                                     m_numFractalIterations;
579 };
580
581 class InvalidShaderCompilerCase : public TestCase
582 {
583 public:
584         // \note Similar to the ShaderValidity enum, but doesn't have a VALID type.
585         enum InvalidityType
586         {
587                 INVALIDITY_INVALID_CHAR = 0,
588                 INVALIDITY_SEMANTIC_ERROR,
589
590                 INVALIDITY_LAST
591         };
592
593                                                 InvalidShaderCompilerCase       (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType);
594                                                 ~InvalidShaderCompilerCase      (void);
595
596         IterateResult           iterate                                         (void);
597
598 protected:
599         struct ProgramContext
600         {
601                 string vertShaderSource;
602                 string fragShaderSource;
603         };
604
605         deUint32                                getSpecializationID             (int measurementNdx) const;                     // Return an ID that depends on the case ID, current measurement index and time; used to specialize attribute names etc. (avoid shader caching).
606         virtual ProgramContext  generateShaderSources   (int measurementNdx) const = 0;         // Generate shader sources. Attribute etc. names depend on above name specialization.
607
608         InvalidityType                  m_invalidityType;
609
610 private:
611         struct Measurement
612         {
613                 // \note All times in microseconds. 32-bit integers would probably suffice (would need over an hour of test case runtime to overflow), but better safe than sorry.
614                 deInt64 sourceSetTime;
615                 deInt64 vertexCompileTime;
616                 deInt64 fragmentCompileTime;
617
618                 deInt64 totalTime (void) const { return sourceSetTime + vertexCompileTime + fragmentCompileTime; }
619
620                 Measurement (deInt64 sourceSetTime_,
621                                          deInt64 vertexCompileTime_,
622                                          deInt64 fragmentCompileTime_)
623                         : sourceSetTime                 (sourceSetTime_)
624                         , vertexCompileTime             (vertexCompileTime_)
625                         , fragmentCompileTime   (fragmentCompileTime_)
626                 {
627                 }
628         };
629
630         struct Shaders
631         {
632                 deUint32 vertShader;
633                 deUint32 fragShader;
634         };
635
636         struct Logs
637         {
638                 string vert;
639                 string frag;
640         };
641
642         struct BuildInfo
643         {
644                 bool vertCompileSuccess;
645                 bool fragCompileSuccess;
646
647                 Logs logs;
648         };
649
650         Shaders                                         createShaders                   (void) const;
651         void                                            setShaderSources                (const Shaders&, const ProgramContext&) const;
652         bool                                            compileShader                   (deUint32 shader) const;
653         void                                            cleanup                                 (const Shaders&) const;
654
655         Logs                                            getLogs                                 (const Shaders&) const;
656         void                                            logProgramData                  (const BuildInfo&, const ProgramContext&) const;
657         bool                                            goodEnoughMeasurements  (const vector<Measurement>& measurements) const;
658
659         deUint32                                        m_startHash; // A hash from case id and time, at the time of construction.
660
661         int                                                     m_minimumMeasurementCount;
662         int                                                     m_maximumMeasurementCount;
663 };
664
665 class InvalidShaderCompilerLightCase : public InvalidShaderCompilerCase
666 {
667 public:
668                                                         InvalidShaderCompilerLightCase  (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, int numLights, LightType lightType);
669                                                         ~InvalidShaderCompilerLightCase (void);
670
671 protected:
672         ProgramContext                  generateShaderSources                   (int measurementNdx) const;
673
674 private:
675         bool                                    m_isVertexCase;
676         int                                             m_numLights;
677         LightType                               m_lightType;
678 };
679
680 class InvalidShaderCompilerTextureCase : public InvalidShaderCompilerCase
681 {
682 public:
683                                                         InvalidShaderCompilerTextureCase        (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numLookups, ConditionalUsage conditionalUsage, ConditionalType conditionalType);
684                                                         ~InvalidShaderCompilerTextureCase       (void);
685
686 protected:
687         ProgramContext                  generateShaderSources                           (int measurementNdx) const;
688
689 private:
690         int                                             m_numLookups;
691         ConditionalUsage                m_conditionalUsage;
692         ConditionalType                 m_conditionalType;
693 };
694
695 class InvalidShaderCompilerLoopCase : public InvalidShaderCompilerCase
696 {
697 public:
698                                                 InvalidShaderCompilerLoopCase   (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool , LoopType type, int numLoopIterations, int nestingDepth);
699                                                 ~InvalidShaderCompilerLoopCase  (void);
700
701 protected:
702         ProgramContext          generateShaderSources                   (int measurementNdx) const;
703
704 private:
705         bool                            m_isVertexCase;
706         int                                     m_numLoopIterations;
707         int                                     m_nestingDepth;
708         LoopType                        m_type;
709 };
710
711 class InvalidShaderCompilerOperCase : public InvalidShaderCompilerCase
712 {
713 public:
714                                                 InvalidShaderCompilerOperCase   (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, bool isVertexCase, const char* oper, int numOperations);
715                                                 ~InvalidShaderCompilerOperCase  (void);
716
717 protected:
718         ProgramContext          generateShaderSources                   (int measurementNdx) const;
719
720 private:
721         bool                            m_isVertexCase;
722         string                          m_oper;
723         int                                     m_numOperations;
724 };
725
726 class InvalidShaderCompilerMandelbrotCase : public InvalidShaderCompilerCase
727 {
728 public:
729                                                 InvalidShaderCompilerMandelbrotCase             (Context& context, const char* name, const char* description, int caseID, InvalidityType invalidityType, int numFractalIterations);
730                                                 ~InvalidShaderCompilerMandelbrotCase    (void);
731
732 protected:
733         ProgramContext          generateShaderSources                                   (int measurementNdx) const;
734
735 private:
736         int                                     m_numFractalIterations;
737 };
738
739 static string getNameSpecialization (deUint32 id)
740 {
741         return "_" + toStringWithPadding(id, 10);
742 }
743
744 // Substitute StringTemplate parameters for attribute/uniform/varying name and constant expression specialization as well as possible shader compilation error causes.
745 static string specializeShaderSource (const string& shaderSourceTemplate, deUint32 cacheAvoidanceID, ShaderValidity validity)
746 {
747         std::map<string, string> params;
748         params["NAME_SPEC"]                     = getNameSpecialization(cacheAvoidanceID);
749         params["FLOAT01"]                       = de::floatToString((float)cacheAvoidanceID / (float)(std::numeric_limits<deUint32>::max()), 6);
750         params["SEMANTIC_ERROR"]        = validity != SHADER_VALIDITY_SEMANTIC_ERROR    ? "" : "\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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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
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
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
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
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
1663 ShaderCompilerCase::~ShaderCompilerCase (void)
1664 {
1665 }
1666
1667 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
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
1686 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
1701 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
1710 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
1719 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
1733 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
1774 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
1792 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
1814 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
1822 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
1834 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
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
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
2155 ShaderCompilerLightCase::~ShaderCompilerLightCase (void)
2156 {
2157         ShaderCompilerLightCase::deinit();
2158 }
2159
2160 void ShaderCompilerLightCase::deinit (void)
2161 {
2162         delete m_texture;
2163         m_texture = DE_NULL;
2164 }
2165
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
2192 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
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
2214 ShaderCompilerTextureCase::~ShaderCompilerTextureCase (void)
2215 {
2216         ShaderCompilerTextureCase::deinit();
2217 }
2218
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
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
2258 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
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
2281 ShaderCompilerLoopCase::~ShaderCompilerLoopCase (void)
2282 {
2283 }
2284
2285 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
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
2308 ShaderCompilerOperCase::~ShaderCompilerOperCase (void)
2309 {
2310 }
2311
2312 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
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
2342 ShaderCompilerMandelbrotCase::~ShaderCompilerMandelbrotCase (void)
2343 {
2344 }
2345
2346 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
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
2371 InvalidShaderCompilerCase::~InvalidShaderCompilerCase (void)
2372 {
2373 }
2374
2375 deUint32 InvalidShaderCompilerCase::getSpecializationID (int measurementNdx) const
2376 {
2377         return m_startHash ^ (deUint32)deInt32Hash((deInt32)measurementNdx);
2378 }
2379
2380 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
2391 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
2400 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
2409 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
2417 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
2428 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
2436 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
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
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
2663 InvalidShaderCompilerLightCase::~InvalidShaderCompilerLightCase (void)
2664 {
2665 }
2666
2667 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
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
2691 InvalidShaderCompilerTextureCase::~InvalidShaderCompilerTextureCase (void)
2692 {
2693 }
2694
2695 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
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
2720 InvalidShaderCompilerLoopCase::~InvalidShaderCompilerLoopCase (void)
2721 {
2722 }
2723
2724 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
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
2748 InvalidShaderCompilerOperCase::~InvalidShaderCompilerOperCase (void)
2749 {
2750 }
2751
2752 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
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
2782 InvalidShaderCompilerMandelbrotCase::~InvalidShaderCompilerMandelbrotCase (void)
2783 {
2784 }
2785
2786 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
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