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