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