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 Optimized vs unoptimized shader performance tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3pShaderOptimizationTests.hpp"
25 #include "glsShaderPerformanceMeasurer.hpp"
26 #include "gluRenderContext.hpp"
27 #include "gluShaderProgram.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuVector.hpp"
30 #include "tcuStringTemplate.hpp"
31 #include "deSharedPtr.hpp"
32 #include "deStringUtil.hpp"
33 #include "deMath.h"
34
35 #include "glwFunctions.hpp"
36
37 #include <vector>
38 #include <string>
39 #include <map>
40
41 using glu::ShaderProgram;
42 using tcu::TestLog;
43 using tcu::Vec4;
44 using de::SharedPtr;
45 using de::toString;
46
47 using std::vector;
48 using std::string;
49
50 namespace deqp
51 {
52
53 using gls::ShaderPerformanceMeasurer;
54
55 namespace gles3
56 {
57 namespace Performance
58 {
59
singleMap(const string & key,const string & value)60 static inline std::map<string, string> singleMap (const string& key, const string& value)
61 {
62 std::map<string, string> res;
63 res[key] = value;
64 return res;
65 }
66
repeat(const string & str,int numRepeats,const string & delim="")67 static inline string repeat (const string& str, int numRepeats, const string& delim = "")
68 {
69 string result = str;
70 for (int i = 1; i < numRepeats; i++)
71 result += delim + str;
72 return result;
73 }
74
repeatIndexedTemplate(const string & strTempl,int numRepeats,const string & delim="",int ndxStart=0)75 static inline string repeatIndexedTemplate (const string& strTempl, int numRepeats, const string& delim = "", int ndxStart = 0)
76 {
77 const tcu::StringTemplate templ(strTempl);
78 string result;
79 std::map<string, string> params;
80
81 for (int i = 0; i < numRepeats; i++)
82 {
83 params["PREV_NDX"] = toString(i + ndxStart - 1);
84 params["NDX"] = toString(i + ndxStart);
85
86 result += (i > 0 ? delim : "") + templ.specialize(params);
87 }
88
89 return result;
90 }
91
92 namespace
93 {
94
95 enum CaseShaderType
96 {
97 CASESHADERTYPE_VERTEX = 0,
98 CASESHADERTYPE_FRAGMENT,
99
100 CASESHADERTYPE_LAST
101 };
102
getShaderPrecision(CaseShaderType shaderType)103 static inline string getShaderPrecision (CaseShaderType shaderType)
104 {
105 switch (shaderType)
106 {
107 case CASESHADERTYPE_VERTEX: return "highp";
108 case CASESHADERTYPE_FRAGMENT: return "highp";
109 default:
110 DE_ASSERT(false);
111 return DE_NULL;
112 }
113 }
114
115 struct ProgramData
116 {
117 glu::ProgramSources sources;
118 vector<gls::AttribSpec> attributes; //!< \note Shouldn't contain a_position; that one is set by gls::ShaderPerformanceMeasurer.
119
ProgramDatadeqp::gles3::Performance::__anonc0a0acb40111::ProgramData120 ProgramData (void) {}
ProgramDatadeqp::gles3::Performance::__anonc0a0acb40111::ProgramData121 ProgramData (const glu::ProgramSources& sources_, const vector<gls::AttribSpec>& attributes_ = vector<gls::AttribSpec>()) : sources(sources_), attributes(attributes_) {}
ProgramDatadeqp::gles3::Performance::__anonc0a0acb40111::ProgramData122 ProgramData (const glu::ProgramSources& sources_, const gls::AttribSpec& attribute) : sources(sources_), attributes(1, attribute) {}
123 };
124
125 //! Shader boilerplate helper; most cases have similar basic shader structure.
defaultProgramData(CaseShaderType shaderType,const string & funcDefs,const string & mainStatements)126 static inline ProgramData defaultProgramData (CaseShaderType shaderType, const string& funcDefs, const string& mainStatements)
127 {
128 const bool isVertexCase = shaderType == CASESHADERTYPE_VERTEX;
129 const bool isFragmentCase = shaderType == CASESHADERTYPE_FRAGMENT;
130 const string vtxPrec = getShaderPrecision(CASESHADERTYPE_VERTEX);
131 const string fragPrec = getShaderPrecision(CASESHADERTYPE_FRAGMENT);
132
133 return ProgramData(glu::ProgramSources() << glu::VertexSource( "#version 300 es\n"
134 "in " + vtxPrec + " vec4 a_position;\n"
135 "in " + vtxPrec + " vec4 a_value;\n"
136 "out " + fragPrec + " vec4 v_value;\n"
137 + (isVertexCase ? funcDefs : "") +
138 "void main (void)\n"
139 "{\n"
140 " gl_Position = a_position;\n"
141 " " + vtxPrec + " vec4 value = a_value;\n"
142 + (isVertexCase ? mainStatements : "") +
143 " v_value = value;\n"
144 "}\n")
145
146 << glu::FragmentSource( "#version 300 es\n"
147 "layout (location = 0) out " + fragPrec + " vec4 o_color;\n"
148 "in " + fragPrec + " vec4 v_value;\n"
149 + (isFragmentCase ? funcDefs : "") +
150 "void main (void)\n"
151 "{\n"
152 " " + fragPrec + " vec4 value = v_value;\n"
153 + (isFragmentCase ? mainStatements : "") +
154 " o_color = value;\n"
155 "}\n"),
156 gls::AttribSpec("a_value",
157 Vec4(1.0f, 0.0f, 0.0f, 0.0f),
158 Vec4(0.0f, 1.0f, 0.0f, 0.0f),
159 Vec4(0.0f, 0.0f, 1.0f, 0.0f),
160 Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
161 }
162
defaultProgramData(CaseShaderType shaderType,const string & mainStatements)163 static inline ProgramData defaultProgramData (CaseShaderType shaderType, const string& mainStatements)
164 {
165 return defaultProgramData(shaderType, "", mainStatements);
166 }
167
168 class ShaderOptimizationCase : public TestCase
169 {
170 public:
ShaderOptimizationCase(Context & context,const char * name,const char * description,CaseShaderType caseShaderType)171 ShaderOptimizationCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType)
172 : TestCase (context, tcu::NODETYPE_PERFORMANCE, name, description)
173 , m_caseShaderType (caseShaderType)
174 , m_state (STATE_LAST)
175 , m_measurer (context.getRenderContext(), caseShaderType == CASESHADERTYPE_VERTEX ? gls::CASETYPE_VERTEX
176 : caseShaderType == CASESHADERTYPE_FRAGMENT ? gls::CASETYPE_FRAGMENT
177 : gls::CASETYPE_LAST)
178 , m_unoptimizedResult (-1.0f, -1.0f)
179 , m_optimizedResult (-1.0f, -1.0f)
180 {
181 }
182
~ShaderOptimizationCase(void)183 virtual ~ShaderOptimizationCase (void) {}
184
185 void init (void);
186 IterateResult iterate (void);
187
188 protected:
189 virtual ProgramData generateProgramData (bool optimized) const = 0;
190
191 const CaseShaderType m_caseShaderType;
192
193 private:
194 enum State
195 {
196 STATE_INIT_UNOPTIMIZED = 0,
197 STATE_MEASURE_UNOPTIMIZED,
198 STATE_INIT_OPTIMIZED,
199 STATE_MEASURE_OPTIMIZED,
200 STATE_FINISHED,
201
202 STATE_LAST
203 };
204
programData(bool optimized)205 ProgramData& programData (bool optimized) { return optimized ? m_optimizedData : m_unoptimizedData; }
program(bool optimized)206 SharedPtr<const ShaderProgram>& program (bool optimized) { return optimized ? m_optimizedProgram : m_unoptimizedProgram; }
result(bool optimized)207 ShaderPerformanceMeasurer::Result& result (bool optimized) { return optimized ? m_optimizedResult : m_unoptimizedResult; }
208
209 State m_state;
210 ShaderPerformanceMeasurer m_measurer;
211
212 ProgramData m_unoptimizedData;
213 ProgramData m_optimizedData;
214 SharedPtr<const ShaderProgram> m_unoptimizedProgram;
215 SharedPtr<const ShaderProgram> m_optimizedProgram;
216 ShaderPerformanceMeasurer::Result m_unoptimizedResult;
217 ShaderPerformanceMeasurer::Result m_optimizedResult;
218 };
219
init(void)220 void ShaderOptimizationCase::init (void)
221 {
222 const glu::RenderContext& renderCtx = m_context.getRenderContext();
223 TestLog& log = m_testCtx.getLog();
224
225 m_measurer.logParameters(log);
226
227 for (int ndx = 0; ndx < 2; ndx++)
228 {
229 const bool optimized = ndx == 1;
230
231 programData(optimized) = generateProgramData(optimized);
232
233 for (int i = 0; i < (int)programData(optimized).attributes.size(); i++)
234 DE_ASSERT(programData(optimized).attributes[i].name != "a_position"); // \note Position attribute is set by m_measurer.
235
236 program(optimized) = SharedPtr<const ShaderProgram>(new ShaderProgram(renderCtx, programData(optimized).sources));
237
238 {
239 const tcu::ScopedLogSection section(log, optimized ? "OptimizedProgram" : "UnoptimizedProgram",
240 optimized ? "Hand-optimized program" : "Unoptimized program");
241 log << *program(optimized);
242 }
243
244 if (!program(optimized)->isOk())
245 TCU_FAIL("Shader compilation failed");
246 }
247
248 m_state = STATE_INIT_UNOPTIMIZED;
249 }
250
iterate(void)251 ShaderOptimizationCase::IterateResult ShaderOptimizationCase::iterate (void)
252 {
253 TestLog& log = m_testCtx.getLog();
254
255 if (m_state == STATE_INIT_UNOPTIMIZED || m_state == STATE_INIT_OPTIMIZED)
256 {
257 const bool optimized = m_state == STATE_INIT_OPTIMIZED;
258 m_measurer.init(program(optimized)->getProgram(), programData(optimized).attributes, 1);
259 m_state = optimized ? STATE_MEASURE_OPTIMIZED : STATE_MEASURE_UNOPTIMIZED;
260
261 return CONTINUE;
262 }
263 else if (m_state == STATE_MEASURE_UNOPTIMIZED || m_state == STATE_MEASURE_OPTIMIZED)
264 {
265 m_measurer.iterate();
266
267 if (m_measurer.isFinished())
268 {
269 const bool optimized = m_state == STATE_MEASURE_OPTIMIZED;
270 const tcu::ScopedLogSection section (log, optimized ? "OptimizedResult" : "UnoptimizedResult",
271 optimized ? "Measurement results for hand-optimized program" : "Measurement result for unoptimized program");
272 m_measurer.logMeasurementInfo(log);
273 result(optimized) = m_measurer.getResult();
274 m_measurer.deinit();
275 m_state = optimized ? STATE_FINISHED : STATE_INIT_OPTIMIZED;
276 }
277
278 return CONTINUE;
279 }
280 else
281 {
282 DE_ASSERT(m_state == STATE_FINISHED);
283
284 const float unoptimizedRelevantResult = m_caseShaderType == CASESHADERTYPE_VERTEX ? m_unoptimizedResult.megaVertPerSec : m_unoptimizedResult.megaFragPerSec;
285 const float optimizedRelevantResult = m_caseShaderType == CASESHADERTYPE_VERTEX ? m_optimizedResult.megaVertPerSec : m_optimizedResult.megaFragPerSec;
286 const char* const relevantResultName = m_caseShaderType == CASESHADERTYPE_VERTEX ? "vertex" : "fragment";
287 const float ratio = unoptimizedRelevantResult / optimizedRelevantResult;
288 const int handOptimizationGain = (int)deFloatRound(100.0f/ratio) - 100;
289
290 log << TestLog::Message << "Unoptimized / optimized " << relevantResultName << " performance ratio: " << ratio << TestLog::EndMessage;
291
292 if (handOptimizationGain >= 0)
293 log << TestLog::Message << "Note: " << handOptimizationGain << "% performance gain was achieved with hand-optimized version" << TestLog::EndMessage;
294 else
295 log << TestLog::Message << "Note: hand-optimization degraded performance by " << -handOptimizationGain << "%" << TestLog::EndMessage;
296
297 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(ratio, 2).c_str());
298
299 return STOP;
300 }
301 }
302
303 class LoopUnrollCase : public ShaderOptimizationCase
304 {
305 public:
306 enum CaseType
307 {
308 CASETYPE_INDEPENDENT = 0,
309 CASETYPE_DEPENDENT,
310
311 CASETYPE_LAST
312 };
313
LoopUnrollCase(Context & context,const char * name,const char * description,CaseShaderType caseShaderType,CaseType caseType,int numRepetitions)314 LoopUnrollCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType, int numRepetitions)
315 : ShaderOptimizationCase (context, name, description, caseShaderType)
316 , m_numRepetitions (numRepetitions)
317 , m_caseType (caseType)
318 {
319 }
320
321 protected:
generateProgramData(bool optimized) const322 ProgramData generateProgramData (bool optimized) const
323 {
324 const string repetition = optimized ? repeatIndexedTemplate("\t" + expressionTemplate(m_caseType) + ";\n", m_numRepetitions)
325 : loop(m_numRepetitions, expressionTemplate(m_caseType));
326
327 return defaultProgramData(m_caseShaderType, "\t" + getShaderPrecision(m_caseShaderType) + " vec4 valueOrig = value;\n" + repetition);
328 }
329
330 private:
331 const int m_numRepetitions;
332 const CaseType m_caseType;
333
expressionTemplate(CaseType caseType)334 static inline string expressionTemplate (CaseType caseType)
335 {
336 switch (caseType)
337 {
338 case CASETYPE_INDEPENDENT: return "value += sin(float(${NDX}+1)*valueOrig)";
339 case CASETYPE_DEPENDENT: return "value = sin(value)";
340 default:
341 DE_ASSERT(false);
342 return DE_NULL;
343 }
344 }
345
loop(int iterations,const string & innerExpr)346 static inline string loop (int iterations, const string& innerExpr)
347 {
348 return "\tfor (int i = 0; i < " + toString(iterations) + "; i++)\n\t\t" + tcu::StringTemplate(innerExpr).specialize(singleMap("NDX", "i")) + ";\n";
349 }
350 };
351
352 class LoopInvariantCodeMotionCase : public ShaderOptimizationCase
353 {
354 public:
LoopInvariantCodeMotionCase(Context & context,const char * name,const char * description,CaseShaderType caseShaderType,int numLoopIterations)355 LoopInvariantCodeMotionCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, int numLoopIterations)
356 : ShaderOptimizationCase (context, name, description, caseShaderType)
357 , m_numLoopIterations (numLoopIterations)
358 {
359 }
360
361 protected:
generateProgramData(bool optimized) const362 ProgramData generateProgramData (bool optimized) const
363 {
364 float scale = 0.0f;
365 for (int i = 0; i < m_numLoopIterations; i++)
366 scale += 3.2f*(float)i + 4.6f;
367 scale = 1.0f / scale;
368
369 const string precision = getShaderPrecision(m_caseShaderType);
370 const string statements = optimized ? " " + precision + " vec4 valueOrig = value;\n"
371 " " + precision + " vec4 y = sin(cos(sin(valueOrig)));\n"
372 " for (int i = 0; i < " + toString(m_numLoopIterations) + "; i++)\n"
373 " {\n"
374 " " + precision + " float x = 3.2*float(i) + 4.6;\n"
375 " value += x*y;\n"
376 " }\n"
377 " value *= " + toString(scale) + ";\n"
378
379 : " " + precision + " vec4 valueOrig = value;\n"
380 " for (int i = 0; i < " + toString(m_numLoopIterations) + "; i++)\n"
381 " {\n"
382 " " + precision + " float x = 3.2*float(i) + 4.6;\n"
383 " " + precision + " vec4 y = sin(cos(sin(valueOrig)));\n"
384 " value += x*y;\n"
385 " }\n"
386 " value *= " + toString(scale) + ";\n";
387
388 return defaultProgramData(m_caseShaderType, statements);
389 }
390
391 private:
392 const int m_numLoopIterations;
393 };
394
395 class FunctionInliningCase : public ShaderOptimizationCase
396 {
397 public:
FunctionInliningCase(Context & context,const char * name,const char * description,CaseShaderType caseShaderType,int callNestingDepth)398 FunctionInliningCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, int callNestingDepth)
399 : ShaderOptimizationCase (context, name, description, caseShaderType)
400 , m_callNestingDepth (callNestingDepth)
401 {
402 }
403
404 protected:
generateProgramData(bool optimized) const405 ProgramData generateProgramData (bool optimized) const
406 {
407 const string precision = getShaderPrecision(m_caseShaderType);
408 const string expression = "value*vec4(0.8, 0.7, 0.6, 0.9)";
409 const string maybeFuncDefs = optimized ? "" : funcDefinitions(m_callNestingDepth, precision, expression);
410 const string mainValueStatement = (optimized ? "\tvalue = " + expression : "\tvalue = func" + toString(m_callNestingDepth-1) + "(value)") + ";\n";
411
412 return defaultProgramData(m_caseShaderType, maybeFuncDefs, mainValueStatement);
413 }
414
415 private:
416 const int m_callNestingDepth;
417
funcDefinitions(int callNestingDepth,const string & precision,const string & expression)418 static inline string funcDefinitions (int callNestingDepth, const string& precision, const string& expression)
419 {
420 string result = precision + " vec4 func0 (" + precision + " vec4 value) { return " + expression + "; }\n";
421
422 for (int i = 1; i < callNestingDepth; i++)
423 result += precision + " vec4 func" + toString(i) + " (" + precision + " vec4 v) { return func" + toString(i-1) + "(v); }\n";
424
425 return result;
426 }
427 };
428
429 class ConstantPropagationCase : public ShaderOptimizationCase
430 {
431 public:
432 enum CaseType
433 {
434 CASETYPE_BUILT_IN_FUNCTIONS = 0,
435 CASETYPE_ARRAY,
436 CASETYPE_STRUCT,
437
438 CASETYPE_LAST
439 };
440
ConstantPropagationCase(Context & context,const char * name,const char * description,CaseShaderType caseShaderType,CaseType caseType,bool useConstantExpressionsOnly)441 ConstantPropagationCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType, bool useConstantExpressionsOnly)
442 : ShaderOptimizationCase (context, name, description, caseShaderType)
443 , m_caseType (caseType)
444 , m_useConstantExpressionsOnly (useConstantExpressionsOnly)
445 {
446 }
447
448 protected:
generateProgramData(bool optimized) const449 ProgramData generateProgramData (bool optimized) const
450 {
451 const bool isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX;
452 const string precision = getShaderPrecision(m_caseShaderType);
453 const string statements = m_caseType == CASETYPE_BUILT_IN_FUNCTIONS ? builtinFunctionsCaseStatements (optimized, m_useConstantExpressionsOnly, precision, isVertexCase)
454 : m_caseType == CASETYPE_ARRAY ? arrayCaseStatements (optimized, m_useConstantExpressionsOnly, precision, isVertexCase)
455 : m_caseType == CASETYPE_STRUCT ? structCaseStatements (optimized, m_useConstantExpressionsOnly, precision, isVertexCase)
456 : DE_NULL;
457
458 return defaultProgramData(m_caseShaderType, statements);
459 }
460
461 private:
462 const CaseType m_caseType;
463 const bool m_useConstantExpressionsOnly;
464
builtinFunctionsCaseStatements(bool optimized,bool constantExpressionsOnly,const string & precision,bool useHeavierWorkload)465 static inline string builtinFunctionsCaseStatements (bool optimized, bool constantExpressionsOnly, const string& precision, bool useHeavierWorkload)
466 {
467 const string constMaybe = constantExpressionsOnly ? "const " : "";
468 const int numSinRows = useHeavierWorkload ? 12 : 1;
469
470 return optimized ? " value = vec4(0.4, 0.5, 0.6, 0.7) * value; // NOTE: factor doesn't necessarily match the one in unoptimized shader, but shouldn't make a difference performance-wise\n"
471
472 : " " + constMaybe + precision + " vec4 a = vec4(sin(0.7), cos(0.2), sin(0.9), abs(-0.5));\n"
473 " " + constMaybe + precision + " vec4 b = cos(a) + fract(3.0*a.xzzw);\n"
474 " " + constMaybe + "bvec4 c = bvec4(true, false, true, true);\n"
475 " " + constMaybe + precision + " vec4 d = exp(b + vec4(c));\n"
476 " " + constMaybe + precision + " vec4 e0 = inversesqrt(mix(d+a, d+b, a));\n"
477 + repeatIndexedTemplate(" " + constMaybe + precision + " vec4 e${NDX} = sin(sin(sin(sin(e${PREV_NDX}))));\n", numSinRows, "", 1) +
478 " " + constMaybe + precision + " vec4 f = abs(e" + toString(numSinRows) + ");\n" +
479 " value = f*value;\n";
480 }
481
arrayCaseStatements(bool optimized,bool constantExpressionsOnly,const string & precision,bool useHeavierWorkload)482 static inline string arrayCaseStatements (bool optimized, bool constantExpressionsOnly, const string& precision, bool useHeavierWorkload)
483 {
484 const string constMaybe = constantExpressionsOnly ? "const " : "";
485 const int numSinRows = useHeavierWorkload ? 12 : 1;
486
487 return optimized ? " value = vec4(0.4, 0.5, 0.6, 0.7) * value; // NOTE: factor doesn't necessarily match the one in unoptimized shader, but shouldn't make a difference performance-wise\n"
488
489 : " const int arrLen = 4;\n"
490 + (constantExpressionsOnly ?
491 " const " + precision + " vec4 arr[arrLen] =\n"
492 " vec4[](vec4(0.1, 0.5, 0.9, 1.3),\n"
493 " vec4(0.2, 0.6, 1.0, 1.4),\n"
494 " vec4(0.3, 0.7, 1.1, 1.5),\n"
495 " vec4(0.4, 0.8, 1.2, 1.6));\n"
496
497 : " " + precision + " vec4 arr[arrLen];\n"
498 " arr[0] = vec4(0.1, 0.5, 0.9, 1.3);\n"
499 " arr[1] = vec4(0.2, 0.6, 1.0, 1.4);\n"
500 " arr[2] = vec4(0.3, 0.7, 1.1, 1.5);\n"
501 " arr[3] = vec4(0.4, 0.8, 1.2, 1.6);\n"
502 ) +
503 " " + constMaybe + precision + " vec4 a = (arr[0] + arr[1] + arr[2] + arr[3]) * (1.0 / float(arr.length()));\n"
504 " " + constMaybe + precision + " vec4 b0 = cos(sin(a));\n"
505 + repeatIndexedTemplate(" " + constMaybe + precision + " vec4 b${NDX} = sin(sin(sin(sin(b${PREV_NDX}))));\n", numSinRows, "", 1) +
506 " " + constMaybe + precision + " vec4 c = abs(b" + toString(numSinRows) + ");\n" +
507 " value = c*value;\n";
508 }
509
structCaseStatements(bool optimized,bool constantExpressionsOnly,const string & precision,bool useHeavierWorkload)510 static inline string structCaseStatements (bool optimized, bool constantExpressionsOnly, const string& precision, bool useHeavierWorkload)
511 {
512 const string constMaybe = constantExpressionsOnly ? "const " : "";
513 const int numSinRows = useHeavierWorkload ? 12 : 1;
514
515 return optimized ? " value = vec4(0.4, 0.5, 0.6, 0.7) * value; // NOTE: factor doesn't necessarily match the one in unoptimized shader, but shouldn't make a difference performance-wise\n"
516
517 : " struct S\n"
518 " {\n"
519 " " + precision + " vec4 a;\n"
520 " " + precision + " vec4 b;\n"
521 " " + precision + " vec4 c;\n"
522 " " + precision + " vec4 d;\n"
523 " };\n"
524 "\n"
525 " " + constMaybe + "S s =\n"
526 " S(vec4(0.1, 0.5, 0.9, 1.3),\n"
527 " vec4(0.2, 0.6, 1.0, 1.4),\n"
528 " vec4(0.3, 0.7, 1.1, 1.5),\n"
529 " vec4(0.4, 0.8, 1.2, 1.6));\n"
530 " " + constMaybe + precision + " vec4 a = (s.a + s.b + s.c + s.d) * 0.25;\n"
531 " " + constMaybe + precision + " vec4 b0 = cos(sin(a));\n"
532 + repeatIndexedTemplate(" " + constMaybe + precision + " vec4 b${NDX} = sin(sin(sin(sin(b${PREV_NDX}))));\n", numSinRows, "", 1) +
533 " " + constMaybe + precision + " vec4 c = abs(b" + toString(numSinRows) + ");\n" +
534 " value = c*value;\n";
535 }
536 };
537
538 class CommonSubexpressionCase : public ShaderOptimizationCase
539 {
540 public:
541 enum CaseType
542 {
543 CASETYPE_SINGLE_STATEMENT = 0,
544 CASETYPE_MULTIPLE_STATEMENTS,
545 CASETYPE_STATIC_BRANCH,
546 CASETYPE_LOOP,
547
548 CASETYPE_LAST
549 };
550
CommonSubexpressionCase(Context & context,const char * name,const char * description,CaseShaderType caseShaderType,CaseType caseType)551 CommonSubexpressionCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType)
552 : ShaderOptimizationCase (context, name, description, caseShaderType)
553 , m_caseType (caseType)
554 {
555 }
556
557 protected:
generateProgramData(bool optimized) const558 ProgramData generateProgramData (bool optimized) const
559 {
560 const bool isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX;
561 const string precision = getShaderPrecision(m_caseShaderType);
562 const string statements = m_caseType == CASETYPE_SINGLE_STATEMENT ? singleStatementCaseStatements (optimized, precision, isVertexCase)
563 : m_caseType == CASETYPE_MULTIPLE_STATEMENTS ? multipleStatementsCaseStatements (optimized, precision, isVertexCase)
564 : m_caseType == CASETYPE_STATIC_BRANCH ? staticBranchCaseStatements (optimized, precision, isVertexCase)
565 : m_caseType == CASETYPE_LOOP ? loopCaseStatements (optimized, precision, isVertexCase)
566 : DE_NULL;
567
568 return defaultProgramData(m_caseShaderType, statements);
569 }
570
571 private:
572 const CaseType m_caseType;
573
singleStatementCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)574 static inline string singleStatementCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
575 {
576 const int numTopLevelRepeats = useHeavierWorkload ? 4 : 1;
577
578 return optimized ? " " + precision + " vec4 s = sin(value);\n"
579 " " + precision + " vec4 cs = cos(s);\n"
580 " " + precision + " vec4 d = fract(s + cs) + sqrt(s + exp(cs));\n"
581 " value = " + repeat("d", numTopLevelRepeats, "+") + ";\n"
582
583 : " value = " + repeat("fract(sin(value) + cos(sin(value))) + sqrt(sin(value) + exp(cos(sin(value))))", numTopLevelRepeats, "\n\t + ") + ";\n";
584 }
585
multipleStatementsCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)586 static inline string multipleStatementsCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
587 {
588 const int numTopLevelRepeats = useHeavierWorkload ? 4 : 2;
589 DE_ASSERT(numTopLevelRepeats >= 2);
590
591 return optimized ? " " + precision + " vec4 a = sin(value) + cos(exp(value));\n"
592 " " + precision + " vec4 b = cos(cos(a));\n"
593 " a = fract(exp(sqrt(b)));\n"
594 "\n"
595 + repeat("\tvalue += a*b;\n", numTopLevelRepeats)
596
597 : repeatIndexedTemplate( " " + precision + " vec4 a${NDX} = sin(value) + cos(exp(value));\n"
598 " " + precision + " vec4 b${NDX} = cos(cos(a${NDX}));\n"
599 " a${NDX} = fract(exp(sqrt(b${NDX})));\n"
600 "\n",
601 numTopLevelRepeats) +
602
603 repeatIndexedTemplate( " value += a${NDX}*b${NDX};\n", numTopLevelRepeats);
604 }
605
staticBranchCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)606 static inline string staticBranchCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
607 {
608 const int numTopLevelRepeats = useHeavierWorkload ? 4 : 2;
609 DE_ASSERT(numTopLevelRepeats >= 2);
610
611 if (optimized)
612 {
613 return " " + precision + " vec4 a = sin(value) + cos(exp(value));\n"
614 " " + precision + " vec4 b = cos(a);\n"
615 " b = cos(b);\n"
616 " a = fract(exp(sqrt(b)));\n"
617 "\n"
618 + repeat(" value += a*b;\n", numTopLevelRepeats);
619 }
620 else
621 {
622 string result;
623
624 for (int i = 0; i < numTopLevelRepeats; i++)
625 {
626 result += " " + precision + " vec4 a" + toString(i) + " = sin(value) + cos(exp(value));\n"
627 " " + precision + " vec4 b" + toString(i) + " = cos(a" + toString(i) + ");\n";
628
629 if (i % 3 == 0)
630 result += " if (1 < 2)\n"
631 " b" + toString(i) + " = cos(b" + toString(i) + ");\n";
632 else if (i % 3 == 1)
633 result += " b" + toString(i) + " = cos(b" + toString(i) + ");\n";
634 else if (i % 3 == 2)
635 result += " if (2 < 1);\n"
636 " else\n"
637 " b" + toString(i) + " = cos(b" + toString(i) + ");\n";
638 else
639 DE_ASSERT(false);
640
641 result += " a" + toString(i) + " = fract(exp(sqrt(b" + toString(i) + ")));\n\n";
642 }
643
644 result += repeatIndexedTemplate(" value += a${NDX}*b${NDX};\n", numTopLevelRepeats);
645
646 return result;
647 }
648 }
649
loopCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)650 static inline string loopCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
651 {
652 const int numLoopIterations = useHeavierWorkload ? 32 : 4;
653
654 return optimized ? " " + precision + " vec4 acc = value;\n"
655 " for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
656 " acc = sin(acc);\n"
657 "\n"
658 " value += acc;\n"
659 " value += acc;\n"
660
661 : " " + precision + " vec4 acc0 = value;\n"
662 " for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
663 " acc0 = sin(acc0);\n"
664 "\n"
665 " " + precision + " vec4 acc1 = value;\n"
666 " for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
667 " acc1 = sin(acc1);\n"
668 "\n"
669 " value += acc0;\n"
670 " value += acc1;\n";
671 }
672 };
673
674 class DeadCodeEliminationCase : public ShaderOptimizationCase
675 {
676 public:
677 enum CaseType
678 {
679 CASETYPE_DEAD_BRANCH_SIMPLE = 0,
680 CASETYPE_DEAD_BRANCH_COMPLEX,
681 CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST,
682 CASETYPE_DEAD_BRANCH_FUNC_CALL,
683 CASETYPE_UNUSED_VALUE_BASIC,
684 CASETYPE_UNUSED_VALUE_LOOP,
685 CASETYPE_UNUSED_VALUE_DEAD_BRANCH,
686 CASETYPE_UNUSED_VALUE_AFTER_RETURN,
687 CASETYPE_UNUSED_VALUE_MUL_ZERO,
688
689 CASETYPE_LAST
690 };
691
DeadCodeEliminationCase(Context & context,const char * name,const char * description,CaseShaderType caseShaderType,CaseType caseType)692 DeadCodeEliminationCase (Context& context, const char* name, const char* description, CaseShaderType caseShaderType, CaseType caseType)
693 : ShaderOptimizationCase (context, name, description, caseShaderType)
694 , m_caseType (caseType)
695 {
696 }
697
698 protected:
generateProgramData(bool optimized) const699 ProgramData generateProgramData (bool optimized) const
700 {
701 const bool isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX;
702 const string precision = getShaderPrecision(m_caseShaderType);
703 const string funcDefs = m_caseType == CASETYPE_DEAD_BRANCH_FUNC_CALL ? deadBranchFuncCallCaseFuncDefs (optimized, precision)
704 : m_caseType == CASETYPE_UNUSED_VALUE_AFTER_RETURN ? unusedValueAfterReturnCaseFuncDefs (optimized, precision, isVertexCase)
705 : "";
706
707 const string statements = m_caseType == CASETYPE_DEAD_BRANCH_SIMPLE ? deadBranchSimpleCaseStatements (optimized, isVertexCase)
708 : m_caseType == CASETYPE_DEAD_BRANCH_COMPLEX ? deadBranchComplexCaseStatements (optimized, precision, true, isVertexCase)
709 : m_caseType == CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST ? deadBranchComplexCaseStatements (optimized, precision, false, isVertexCase)
710 : m_caseType == CASETYPE_DEAD_BRANCH_FUNC_CALL ? deadBranchFuncCallCaseStatements (optimized, isVertexCase)
711 : m_caseType == CASETYPE_UNUSED_VALUE_BASIC ? unusedValueBasicCaseStatements (optimized, precision, isVertexCase)
712 : m_caseType == CASETYPE_UNUSED_VALUE_LOOP ? unusedValueLoopCaseStatements (optimized, precision, isVertexCase)
713 : m_caseType == CASETYPE_UNUSED_VALUE_DEAD_BRANCH ? unusedValueDeadBranchCaseStatements (optimized, precision, isVertexCase)
714 : m_caseType == CASETYPE_UNUSED_VALUE_AFTER_RETURN ? unusedValueAfterReturnCaseStatements ()
715 : m_caseType == CASETYPE_UNUSED_VALUE_MUL_ZERO ? unusedValueMulZeroCaseStatements (optimized, precision, isVertexCase)
716 : DE_NULL;
717
718 return defaultProgramData(m_caseShaderType, funcDefs, statements);
719 }
720
721 private:
722 const CaseType m_caseType;
723
deadBranchSimpleCaseStatements(bool optimized,bool useHeavierWorkload)724 static inline string deadBranchSimpleCaseStatements (bool optimized, bool useHeavierWorkload)
725 {
726 const int numLoopIterations = useHeavierWorkload ? 16 : 4;
727
728 return optimized ? " value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
729
730 : " value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
731 " if (2 < 1)\n"
732 " {\n"
733 " value = cos(exp(sin(value))*log(sqrt(value)));\n"
734 " for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
735 " value = sin(value);\n"
736 " }\n";
737 }
738
deadBranchComplexCaseStatements(bool optimized,const string & precision,bool useConst,bool useHeavierWorkload)739 static inline string deadBranchComplexCaseStatements (bool optimized, const string& precision, bool useConst, bool useHeavierWorkload)
740 {
741 const string constMaybe = useConst ? "const " : "";
742 const int numLoopIterations = useHeavierWorkload ? 16 : 4;
743
744 return optimized ? " value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
745
746 : " value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
747 " " + constMaybe + precision + " vec4 a = vec4(sin(0.7), cos(0.2), sin(0.9), abs(-0.5));\n"
748 " " + constMaybe + precision + " vec4 b = cos(a) + fract(3.0*a.xzzw);\n"
749 " " + constMaybe + "bvec4 c = bvec4(true, false, true, true);\n"
750 " " + constMaybe + precision + " vec4 d = exp(b + vec4(c));\n"
751 " " + constMaybe + precision + " vec4 e = 1.8*abs(sin(sin(inversesqrt(mix(d+a, d+b, a)))));\n"
752 " if (e.x > 1.0)\n"
753 " {\n"
754 " value = cos(exp(sin(value))*log(sqrt(value)));\n"
755 " for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
756 " value = sin(value);\n"
757 " }\n";
758 }
759
deadBranchFuncCallCaseFuncDefs(bool optimized,const string & precision)760 static inline string deadBranchFuncCallCaseFuncDefs (bool optimized, const string& precision)
761 {
762 return optimized ? "" : precision + " float func (" + precision + " float x) { return 2.0*x; }\n";
763 }
764
deadBranchFuncCallCaseStatements(bool optimized,bool useHeavierWorkload)765 static inline string deadBranchFuncCallCaseStatements (bool optimized, bool useHeavierWorkload)
766 {
767 const int numLoopIterations = useHeavierWorkload ? 16 : 4;
768
769 return optimized ? " value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
770
771 : " value = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
772 " if (func(0.3) > 1.0)\n"
773 " {\n"
774 " value = cos(exp(sin(value))*log(sqrt(value)));\n"
775 " for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
776 " value = sin(value);\n"
777 " }\n";
778 }
779
unusedValueBasicCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)780 static inline string unusedValueBasicCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
781 {
782 const int numSinRows = useHeavierWorkload ? 12 : 1;
783
784 return optimized ? " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
785 " value = used;\n"
786
787 : " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
788 " " + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value))) + used;\n"
789 + repeat(" unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
790 " value = used;\n";
791 }
792
unusedValueLoopCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)793 static inline string unusedValueLoopCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
794 {
795 const int numLoopIterations = useHeavierWorkload ? 16 : 4;
796
797 return optimized ? " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
798 " value = used;\n"
799
800 : " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
801 " " + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value)));\n"
802 " for (int i = 0; i < " + toString(numLoopIterations) + "; i++)\n"
803 " unused = sin(unused + used);\n"
804 " value = used;\n";
805 }
806
unusedValueAfterReturnCaseFuncDefs(bool optimized,const string & precision,bool useHeavierWorkload)807 static inline string unusedValueAfterReturnCaseFuncDefs (bool optimized, const string& precision, bool useHeavierWorkload)
808 {
809 const int numSinRows = useHeavierWorkload ? 12 : 1;
810
811 return optimized ? precision + " vec4 func (" + precision + " vec4 v)\n"
812 "{\n"
813 " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * v;\n"
814 " return used;\n"
815 "}\n"
816
817 : precision + " vec4 func (" + precision + " vec4 v)\n"
818 "{\n"
819 " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * v;\n"
820 " " + precision + " vec4 unused = cos(exp(sin(v))*log(sqrt(v)));\n"
821 + repeat(" unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
822 " return used;\n"
823 " used = used*unused;"
824 " return used;\n"
825 "}\n";
826 }
827
unusedValueAfterReturnCaseStatements(void)828 static inline string unusedValueAfterReturnCaseStatements (void)
829 {
830 return " value = func(value);\n";
831 }
832
unusedValueDeadBranchCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)833 static inline string unusedValueDeadBranchCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
834 {
835 const int numSinRows = useHeavierWorkload ? 12 : 1;
836
837 return optimized ? " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
838 " value = used;\n"
839
840 : " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
841 " " + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value)));\n"
842 + repeat(" unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
843 " if (2 < 1)\n"
844 " used = used*unused;\n"
845 " value = used;\n";
846 }
847
unusedValueMulZeroCaseStatements(bool optimized,const string & precision,bool useHeavierWorkload)848 static inline string unusedValueMulZeroCaseStatements (bool optimized, const string& precision, bool useHeavierWorkload)
849 {
850 const int numSinRows = useHeavierWorkload ? 12 : 1;
851
852 return optimized ? " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
853 " value = used;\n"
854
855 : " " + precision + " vec4 used = vec4(0.6, 0.7, 0.8, 0.9) * value;\n"
856 " " + precision + " vec4 unused = cos(exp(sin(value))*log(sqrt(value)));\n"
857 + repeat(" unused = sin(sin(sin(sin(unused))));\n", numSinRows) +
858 " value = used + unused*float(1-1);\n";
859 }
860 };
861
862 } // anonymous
863
ShaderOptimizationTests(Context & context)864 ShaderOptimizationTests::ShaderOptimizationTests (Context& context)
865 : TestCaseGroup(context, "optimization", "Shader Optimization Performance Tests")
866 {
867 }
868
~ShaderOptimizationTests(void)869 ShaderOptimizationTests::~ShaderOptimizationTests (void)
870 {
871 }
872
init(void)873 void ShaderOptimizationTests::init (void)
874 {
875 TestCaseGroup* const unrollGroup = new TestCaseGroup(m_context, "loop_unrolling", "Loop Unrolling Cases");
876 TestCaseGroup* const loopInvariantCodeMotionGroup = new TestCaseGroup(m_context, "loop_invariant_code_motion", "Loop-Invariant Code Motion Cases");
877 TestCaseGroup* const inlineGroup = new TestCaseGroup(m_context, "function_inlining", "Function Inlining Cases");
878 TestCaseGroup* const constantPropagationGroup = new TestCaseGroup(m_context, "constant_propagation", "Constant Propagation Cases");
879 TestCaseGroup* const commonSubexpressionGroup = new TestCaseGroup(m_context, "common_subexpression_elimination", "Common Subexpression Elimination Cases");
880 TestCaseGroup* const deadCodeEliminationGroup = new TestCaseGroup(m_context, "dead_code_elimination", "Dead Code Elimination Cases");
881 addChild(unrollGroup);
882 addChild(loopInvariantCodeMotionGroup);
883 addChild(inlineGroup);
884 addChild(constantPropagationGroup);
885 addChild(commonSubexpressionGroup);
886 addChild(deadCodeEliminationGroup);
887
888 for (int caseShaderTypeI = 0; caseShaderTypeI < CASESHADERTYPE_LAST; caseShaderTypeI++)
889 {
890 const CaseShaderType caseShaderType = (CaseShaderType)caseShaderTypeI;
891 const char* const caseShaderTypeSuffix = caseShaderType == CASESHADERTYPE_VERTEX ? "_vertex"
892 : caseShaderType == CASESHADERTYPE_FRAGMENT ? "_fragment"
893 : DE_NULL;
894
895 // Loop unrolling cases.
896
897 {
898 static const int loopIterationCounts[] = { 4, 8, 32 };
899
900 for (int caseTypeI = 0; caseTypeI < LoopUnrollCase::CASETYPE_LAST; caseTypeI++)
901 {
902 const LoopUnrollCase::CaseType caseType = (LoopUnrollCase::CaseType)caseTypeI;
903 const string caseTypeName = caseType == LoopUnrollCase::CASETYPE_INDEPENDENT ? "independent_iterations"
904 : caseType == LoopUnrollCase::CASETYPE_DEPENDENT ? "dependent_iterations"
905 : DE_NULL;
906 const string caseTypeDesc = caseType == LoopUnrollCase::CASETYPE_INDEPENDENT ? "loop iterations don't depend on each other"
907 : caseType == LoopUnrollCase::CASETYPE_DEPENDENT ? "loop iterations depend on each other"
908 : DE_NULL;
909
910 for (int loopIterNdx = 0; loopIterNdx < DE_LENGTH_OF_ARRAY(loopIterationCounts); loopIterNdx++)
911 {
912 const int loopIterations = loopIterationCounts[loopIterNdx];
913 const string name = caseTypeName + "_" + toString(loopIterations) + caseShaderTypeSuffix;
914 const string description = toString(loopIterations) + " iterations; " + caseTypeDesc;
915
916 unrollGroup->addChild(new LoopUnrollCase(m_context, name.c_str(), description.c_str(), caseShaderType, caseType, loopIterations));
917 }
918 }
919 }
920
921 // Loop-invariant code motion cases.
922
923 {
924 static const int loopIterationCounts[] = { 4, 8, 32 };
925
926 for (int loopIterNdx = 0; loopIterNdx < DE_LENGTH_OF_ARRAY(loopIterationCounts); loopIterNdx++)
927 {
928 const int loopIterations = loopIterationCounts[loopIterNdx];
929 const string name = toString(loopIterations) + "_iterations" + caseShaderTypeSuffix;
930
931 loopInvariantCodeMotionGroup->addChild(new LoopInvariantCodeMotionCase(m_context, name.c_str(), "", caseShaderType, loopIterations));
932 }
933 }
934
935 // Function inlining cases.
936
937 {
938 static const int callNestingDepths[] = { 4, 8, 32 };
939
940 for (int nestDepthNdx = 0; nestDepthNdx < DE_LENGTH_OF_ARRAY(callNestingDepths); nestDepthNdx++)
941 {
942 const int nestingDepth = callNestingDepths[nestDepthNdx];
943 const string name = toString(nestingDepth) + "_nested" + caseShaderTypeSuffix;
944
945 inlineGroup->addChild(new FunctionInliningCase(m_context, name.c_str(), "", caseShaderType, nestingDepth));
946 }
947 }
948
949 // Constant propagation cases.
950
951 for (int caseTypeI = 0; caseTypeI < ConstantPropagationCase::CASETYPE_LAST; caseTypeI++)
952 {
953 const ConstantPropagationCase::CaseType caseType = (ConstantPropagationCase::CaseType)caseTypeI;
954 const string caseTypeName = caseType == ConstantPropagationCase::CASETYPE_BUILT_IN_FUNCTIONS ? "built_in_functions"
955 : caseType == ConstantPropagationCase::CASETYPE_ARRAY ? "array"
956 : caseType == ConstantPropagationCase::CASETYPE_STRUCT ? "struct"
957 : DE_NULL;
958
959 for (int constantExpressionsOnlyI = 0; constantExpressionsOnlyI <= 1; constantExpressionsOnlyI++)
960 {
961 const bool constantExpressionsOnly = constantExpressionsOnlyI != 0;
962 const string name = caseTypeName + (constantExpressionsOnly ? "" : "_no_const") + caseShaderTypeSuffix;
963
964 constantPropagationGroup->addChild(new ConstantPropagationCase(m_context, name.c_str(), "", caseShaderType, caseType, constantExpressionsOnly));
965 }
966 }
967
968 // Common subexpression cases.
969
970 for (int caseTypeI = 0; caseTypeI < CommonSubexpressionCase::CASETYPE_LAST; caseTypeI++)
971 {
972 const CommonSubexpressionCase::CaseType caseType = (CommonSubexpressionCase::CaseType)caseTypeI;
973
974 const string caseTypeName = caseType == CommonSubexpressionCase::CASETYPE_SINGLE_STATEMENT ? "single_statement"
975 : caseType == CommonSubexpressionCase::CASETYPE_MULTIPLE_STATEMENTS ? "multiple_statements"
976 : caseType == CommonSubexpressionCase::CASETYPE_STATIC_BRANCH ? "static_branch"
977 : caseType == CommonSubexpressionCase::CASETYPE_LOOP ? "loop"
978 : DE_NULL;
979
980 const string description = caseType == CommonSubexpressionCase::CASETYPE_SINGLE_STATEMENT ? "A single statement containing multiple uses of same subexpression"
981 : caseType == CommonSubexpressionCase::CASETYPE_MULTIPLE_STATEMENTS ? "Multiple statements performing same computations"
982 : caseType == CommonSubexpressionCase::CASETYPE_STATIC_BRANCH ? "Multiple statements including a static conditional"
983 : caseType == CommonSubexpressionCase::CASETYPE_LOOP ? "Multiple loops performing the same computations"
984 : DE_NULL;
985
986 commonSubexpressionGroup->addChild(new CommonSubexpressionCase(m_context, (caseTypeName + caseShaderTypeSuffix).c_str(), description.c_str(), caseShaderType, caseType));
987 }
988
989 // Dead code elimination cases.
990
991 for (int caseTypeI = 0; caseTypeI < DeadCodeEliminationCase::CASETYPE_LAST; caseTypeI++)
992 {
993 const DeadCodeEliminationCase::CaseType caseType = (DeadCodeEliminationCase::CaseType)caseTypeI;
994 const char* const caseTypeName = caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_SIMPLE ? "dead_branch_simple"
995 : caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX ? "dead_branch_complex"
996 : caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST ? "dead_branch_complex_no_const"
997 : caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_FUNC_CALL ? "dead_branch_func_call"
998 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_BASIC ? "unused_value_basic"
999 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_LOOP ? "unused_value_loop"
1000 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_DEAD_BRANCH ? "unused_value_dead_branch"
1001 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_AFTER_RETURN ? "unused_value_after_return"
1002 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_MUL_ZERO ? "unused_value_mul_zero"
1003 : DE_NULL;
1004
1005 const char* const caseTypeDescription = caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_SIMPLE ? "Do computation inside a branch that is never taken (condition is simple false constant expression)"
1006 : caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX ? "Do computation inside a branch that is never taken (condition is complex false constant expression)"
1007 : caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_COMPLEX_NO_CONST ? "Do computation inside a branch that is never taken (condition is complex false expression, not constant expression but still compile-time computable)"
1008 : caseType == DeadCodeEliminationCase::CASETYPE_DEAD_BRANCH_FUNC_CALL ? "Do computation inside a branch that is never taken (condition is compile-time computable false expression containing function call to a simple inlineable function)"
1009 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_BASIC ? "Compute a value that is never used even statically"
1010 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_LOOP ? "Compute a value, using a loop, that is never used even statically"
1011 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_DEAD_BRANCH ? "Compute a value that is used only inside a statically dead branch"
1012 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_AFTER_RETURN ? "Compute a value that is used only after a return statement"
1013 : caseType == DeadCodeEliminationCase::CASETYPE_UNUSED_VALUE_MUL_ZERO ? "Compute a value that is used but multiplied by a zero constant expression"
1014 : DE_NULL;
1015
1016 deadCodeEliminationGroup->addChild(new DeadCodeEliminationCase(m_context, (string() + caseTypeName + caseShaderTypeSuffix).c_str(), caseTypeDescription, caseShaderType, caseType));
1017 }
1018 }
1019 }
1020
1021 } // Performance
1022 } // gles3
1023 } // deqp
1024