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