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