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