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