xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fShaderLoopTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Texture wrap mode test case
22  *
23  * \todo [petri]
24  * - loop body cases (do different operations inside the loops)
25  * - more complex nested loops
26  *   * random generated?
27  *   * dataflow variations
28  *   * mixed loop types
29  * -
30  *//*--------------------------------------------------------------------*/
31 
32 #include "es3fShaderLoopTests.hpp"
33 #include "glsShaderLibrary.hpp"
34 #include "glsShaderRenderCase.hpp"
35 #include "gluShaderUtil.hpp"
36 #include "tcuStringTemplate.hpp"
37 
38 #include "deStringUtil.hpp"
39 #include "deInt32.h"
40 #include "deMemory.h"
41 
42 #include <map>
43 
44 using namespace std;
45 using namespace tcu;
46 using namespace glu;
47 using namespace deqp::gls;
48 
49 namespace deqp
50 {
51 namespace gles3
52 {
53 namespace Functional
54 {
55 
56 // Repeated with for, while, do-while. Examples given as 'for' loops.
57 // Repeated for const, uniform, dynamic loops.
58 enum LoopCase
59 {
60     LOOPCASE_EMPTY_BODY = 0,                          // for (...) { }
61     LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST, // for (...) { break; <body>; }
62     LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST,  // for (...) { <body>; break; }
63     LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK,         // for (...) { <body>; if (cond) break; }
64     LOOPCASE_SINGLE_STATEMENT,                        // for (...) statement;
65     LOOPCASE_COMPOUND_STATEMENT,                      // for (...) { statement; statement; }
66     LOOPCASE_SEQUENCE_STATEMENT,                      // for (...) statement, statement;
67     LOOPCASE_NO_ITERATIONS,                           // for (i=0; i<0; i++) ...
68     LOOPCASE_SINGLE_ITERATION,                        // for (i=0; i<1; i++) ...
69     LOOPCASE_SELECT_ITERATION_COUNT,                  // for (i=0; i<a?b:c; i++) ...
70     LOOPCASE_CONDITIONAL_CONTINUE,                    // for (...) { if (cond) continue; }
71     LOOPCASE_UNCONDITIONAL_CONTINUE,                  // for (...) { <body>; continue; }
72     LOOPCASE_ONLY_CONTINUE,                           // for (...) { continue; }
73     LOOPCASE_DOUBLE_CONTINUE,                         // for (...) { if (cond) continue; <body>; continue; }
74     LOOPCASE_CONDITIONAL_BREAK,                       // for (...) { if (cond) break; }
75     LOOPCASE_UNCONDITIONAL_BREAK,                     // for (...) { <body>; break; }
76     LOOPCASE_PRE_INCREMENT,                           // for (...; ++i) { <body>; }
77     LOOPCASE_POST_INCREMENT,                          // for (...; i++) { <body>; }
78     LOOPCASE_MIXED_BREAK_CONTINUE,
79     LOOPCASE_VECTOR_COUNTER,           // for (ivec3 ndx = ...; ndx.x < ndx.y; ndx.x += ndx.z) { ... }
80     LOOPCASE_101_ITERATIONS,           // loop for 101 iterations
81     LOOPCASE_SEQUENCE,                 // two loops in sequence
82     LOOPCASE_NESTED,                   // two nested loops
83     LOOPCASE_NESTED_SEQUENCE,          // two loops in sequence nested inside a third
84     LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow
85     LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow
86 
87     //LOOPCASE_MULTI_DECLARATION, // for (int i,j,k; ...) ...  -- illegal?
88 
89     LOOPCASE_LAST
90 };
91 
getLoopCaseName(LoopCase loopCase)92 static const char *getLoopCaseName(LoopCase loopCase)
93 {
94     static const char *s_names[] = {
95         "empty_body",
96         "infinite_with_unconditional_break_first",
97         "infinite_with_unconditional_break_last",
98         "infinite_with_conditional_break",
99         "single_statement",
100         "compound_statement",
101         "sequence_statement",
102         "no_iterations",
103         "single_iteration",
104         "select_iteration_count",
105         "conditional_continue",
106         "unconditional_continue",
107         "only_continue",
108         "double_continue",
109         "conditional_break",
110         "unconditional_break",
111         "pre_increment",
112         "post_increment",
113         "mixed_break_continue",
114         "vector_counter",
115         "101_iterations",
116         "sequence",
117         "nested",
118         "nested_sequence",
119         "nested_tricky_dataflow_1",
120         "nested_tricky_dataflow_2"
121         //"multi_declaration",
122     };
123 
124     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
125     DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
126     return s_names[(int)loopCase];
127 }
128 
129 // Complex loop cases.
130 
131 /*enum LoopBody
132 {
133     LOOPBODY_READ_UNIFORM = 0,
134     LOOPBODY_READ_UNIFORM_ARRAY,
135     LOOPBODY_READ_
136 };*/
137 
138 enum LoopType
139 {
140     LOOPTYPE_FOR = 0,
141     LOOPTYPE_WHILE,
142     LOOPTYPE_DO_WHILE,
143 
144     LOOPTYPE_LAST
145 };
146 
getLoopTypeName(LoopType loopType)147 static const char *getLoopTypeName(LoopType loopType)
148 {
149     static const char *s_names[] = {"for", "while", "do_while"};
150 
151     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
152     DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
153     return s_names[(int)loopType];
154 }
155 
156 enum LoopCountType
157 {
158     LOOPCOUNT_CONSTANT = 0,
159     LOOPCOUNT_UNIFORM,
160     LOOPCOUNT_DYNAMIC,
161 
162     LOOPCOUNT_LAST
163 };
164 
getLoopCountTypeName(LoopCountType countType)165 static const char *getLoopCountTypeName(LoopCountType countType)
166 {
167     static const char *s_names[] = {"constant", "uniform", "dynamic"};
168 
169     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
170     DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
171     return s_names[(int)countType];
172 }
173 
evalLoop0Iters(ShaderEvalContext & c)174 static void evalLoop0Iters(ShaderEvalContext &c)
175 {
176     c.color.xyz() = c.coords.swizzle(0, 1, 2);
177 }
evalLoop1Iters(ShaderEvalContext & c)178 static void evalLoop1Iters(ShaderEvalContext &c)
179 {
180     c.color.xyz() = c.coords.swizzle(1, 2, 3);
181 }
evalLoop2Iters(ShaderEvalContext & c)182 static void evalLoop2Iters(ShaderEvalContext &c)
183 {
184     c.color.xyz() = c.coords.swizzle(2, 3, 0);
185 }
evalLoop3Iters(ShaderEvalContext & c)186 static void evalLoop3Iters(ShaderEvalContext &c)
187 {
188     c.color.xyz() = c.coords.swizzle(3, 0, 1);
189 }
190 
getLoopEvalFunc(int numIters)191 static ShaderEvalFunc getLoopEvalFunc(int numIters)
192 {
193     switch (numIters % 4)
194     {
195     case 0:
196         return evalLoop0Iters;
197     case 1:
198         return evalLoop1Iters;
199     case 2:
200         return evalLoop2Iters;
201     case 3:
202         return evalLoop3Iters;
203     }
204 
205     DE_FATAL("Invalid loop iteration count.");
206     return NULL;
207 }
208 
209 // ShaderLoopCase
210 
211 class ShaderLoopCase : public ShaderRenderCase
212 {
213 public:
214     ShaderLoopCase(Context &context, const char *name, const char *description, bool isVertexCase,
215                    ShaderEvalFunc evalFunc, const char *vertShaderSource, const char *fragShaderSource);
216     virtual ~ShaderLoopCase(void);
217 
218 private:
219     ShaderLoopCase(const ShaderLoopCase &);            // not allowed!
220     ShaderLoopCase &operator=(const ShaderLoopCase &); // not allowed!
221 
222     virtual void setup(int programID);
223     virtual void setupUniforms(int programID, const Vec4 &constCoords);
224 };
225 
ShaderLoopCase(Context & context,const char * name,const char * description,bool isVertexCase,ShaderEvalFunc evalFunc,const char * vertShaderSource,const char * fragShaderSource)226 ShaderLoopCase::ShaderLoopCase(Context &context, const char *name, const char *description, bool isVertexCase,
227                                ShaderEvalFunc evalFunc, const char *vertShaderSource, const char *fragShaderSource)
228     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
229                        description, isVertexCase, evalFunc)
230 {
231     m_vertShaderSource = vertShaderSource;
232     m_fragShaderSource = fragShaderSource;
233 }
234 
~ShaderLoopCase(void)235 ShaderLoopCase::~ShaderLoopCase(void)
236 {
237 }
238 
setup(int programID)239 void ShaderLoopCase::setup(int programID)
240 {
241     DE_UNREF(programID);
242 }
243 
setupUniforms(int programID,const Vec4 & constCoords)244 void ShaderLoopCase::setupUniforms(int programID, const Vec4 &constCoords)
245 {
246     DE_UNREF(programID);
247     DE_UNREF(constCoords);
248 }
249 
250 // Test case creation.
251 
createGenericLoopCase(Context & context,const char * caseName,const char * description,bool isVertexCase,LoopType loopType,LoopCountType loopCountType,Precision loopCountPrecision,DataType loopCountDataType)252 static ShaderLoopCase *createGenericLoopCase(Context &context, const char *caseName, const char *description,
253                                              bool isVertexCase, LoopType loopType, LoopCountType loopCountType,
254                                              Precision loopCountPrecision, DataType loopCountDataType)
255 {
256     std::ostringstream vtx;
257     std::ostringstream frag;
258     std::ostringstream &op = isVertexCase ? vtx : frag;
259 
260     vtx << "#version 300 es\n";
261     frag << "#version 300 es\n";
262 
263     vtx << "in highp vec4 a_position;\n";
264     vtx << "in highp vec4 a_coords;\n";
265     frag << "layout(location = 0) out mediump vec4 o_color;\n";
266 
267     if (loopCountType == LOOPCOUNT_DYNAMIC)
268         vtx << "in mediump float a_one;\n";
269 
270     if (isVertexCase)
271     {
272         vtx << "out mediump vec3 v_color;\n";
273         frag << "in mediump vec3 v_color;\n";
274     }
275     else
276     {
277         vtx << "out mediump vec4 v_coords;\n";
278         frag << "in mediump vec4 v_coords;\n";
279 
280         if (loopCountType == LOOPCOUNT_DYNAMIC)
281         {
282             vtx << "out mediump float v_one;\n";
283             frag << "in mediump float v_one;\n";
284         }
285     }
286 
287     // \todo [petri] Pass numLoopIters from outside?
288     int numLoopIters  = 3;
289     bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
290 
291     if (isIntCounter)
292     {
293         if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
294             op << "uniform ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
295     }
296     else
297     {
298         if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
299             op << "uniform ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
300 
301         if (numLoopIters != 1)
302             op << "uniform ${COUNTER_PRECISION} float uf_one;\n";
303     }
304 
305     vtx << "\n";
306     vtx << "void main()\n";
307     vtx << "{\n";
308     vtx << "    gl_Position = a_position;\n";
309 
310     frag << "\n";
311     frag << "void main()\n";
312     frag << "{\n";
313 
314     if (isVertexCase)
315         vtx << "    ${PRECISION} vec4 coords = a_coords;\n";
316     else
317         frag << "    ${PRECISION} vec4 coords = v_coords;\n";
318 
319     if (loopCountType == LOOPCOUNT_DYNAMIC)
320     {
321         if (isIntCounter)
322         {
323             if (isVertexCase)
324                 vtx << "    ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
325             else
326                 frag << "    ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
327         }
328         else
329         {
330             if (isVertexCase)
331                 vtx << "    ${COUNTER_PRECISION} float one = a_one;\n";
332             else
333                 frag << "    ${COUNTER_PRECISION} float one = v_one;\n";
334         }
335     }
336 
337     // Read array.
338     op << "    ${PRECISION} vec4 res = coords;\n";
339 
340     // Loop iteration count.
341     string iterMaxStr;
342 
343     if (isIntCounter)
344     {
345         if (loopCountType == LOOPCOUNT_CONSTANT)
346             iterMaxStr = de::toString(numLoopIters);
347         else if (loopCountType == LOOPCOUNT_UNIFORM)
348             iterMaxStr = getIntUniformName(numLoopIters);
349         else if (loopCountType == LOOPCOUNT_DYNAMIC)
350             iterMaxStr = string(getIntUniformName(numLoopIters)) + "*one";
351         else
352             DE_ASSERT(false);
353     }
354     else
355     {
356         if (loopCountType == LOOPCOUNT_CONSTANT)
357             iterMaxStr = "1.0";
358         else if (loopCountType == LOOPCOUNT_UNIFORM)
359             iterMaxStr = "uf_one";
360         else if (loopCountType == LOOPCOUNT_DYNAMIC)
361             iterMaxStr = "uf_one*one";
362         else
363             DE_ASSERT(false);
364     }
365 
366     // Loop operations.
367     string initValue        = isIntCounter ? "0" : "0.05";
368     string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
369     string loopCmpStr       = ("ndx < " + iterMaxStr);
370     string incrementStr;
371     if (isIntCounter)
372         incrementStr = "ndx++";
373     else
374     {
375         if (loopCountType == LOOPCOUNT_CONSTANT)
376             incrementStr = string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
377         else if (loopCountType == LOOPCOUNT_UNIFORM)
378             incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters);
379         else if (loopCountType == LOOPCOUNT_DYNAMIC)
380             incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
381         else
382             DE_ASSERT(false);
383     }
384 
385     // Loop body.
386     string loopBody;
387 
388     loopBody = "        res = res.yzwx;\n";
389 
390     if (loopType == LOOPTYPE_FOR)
391     {
392         op << "    for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
393         op << "    {\n";
394         op << loopBody;
395         op << "    }\n";
396     }
397     else if (loopType == LOOPTYPE_WHILE)
398     {
399         op << "\t" << loopCountDeclStr + ";\n";
400         op << "    while (" + loopCmpStr + ")\n";
401         op << "    {\n";
402         op << loopBody;
403         op << "\t\t" + incrementStr + ";\n";
404         op << "    }\n";
405     }
406     else if (loopType == LOOPTYPE_DO_WHILE)
407     {
408         op << "\t" << loopCountDeclStr + ";\n";
409         op << "    do\n";
410         op << "    {\n";
411         op << loopBody;
412         op << "\t\t" + incrementStr + ";\n";
413         op << "    } while (" + loopCmpStr + ");\n";
414     }
415     else
416         DE_ASSERT(false);
417 
418     if (isVertexCase)
419     {
420         vtx << "    v_color = res.rgb;\n";
421         frag << "    o_color = vec4(v_color.rgb, 1.0);\n";
422     }
423     else
424     {
425         vtx << "    v_coords = a_coords;\n";
426         frag << "    o_color = vec4(res.rgb, 1.0);\n";
427 
428         if (loopCountType == LOOPCOUNT_DYNAMIC)
429             vtx << "    v_one = a_one;\n";
430     }
431 
432     vtx << "}\n";
433     frag << "}\n";
434 
435     // Fill in shader templates.
436     map<string, string> params;
437     params.insert(pair<string, string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
438     params.insert(pair<string, string>("PRECISION", "mediump"));
439     params.insert(pair<string, string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
440 
441     StringTemplate vertTemplate(vtx.str().c_str());
442     StringTemplate fragTemplate(frag.str().c_str());
443     string vertexShaderSource   = vertTemplate.specialize(params);
444     string fragmentShaderSource = fragTemplate.specialize(params);
445 
446     // Create the case.
447     ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
448     return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(),
449                               fragmentShaderSource.c_str());
450 }
451 
452 // \todo [petri] Generalize to float as well?
createSpecialLoopCase(Context & context,const char * caseName,const char * description,bool isVertexCase,LoopCase loopCase,LoopType loopType,LoopCountType loopCountType)453 static ShaderLoopCase *createSpecialLoopCase(Context &context, const char *caseName, const char *description,
454                                              bool isVertexCase, LoopCase loopCase, LoopType loopType,
455                                              LoopCountType loopCountType)
456 {
457     std::ostringstream vtx;
458     std::ostringstream frag;
459     std::ostringstream &op = isVertexCase ? vtx : frag;
460 
461     vtx << "#version 300 es\n";
462     frag << "#version 300 es\n";
463 
464     vtx << "in highp vec4 a_position;\n";
465     vtx << "in highp vec4 a_coords;\n";
466     frag << "layout(location = 0) out mediump vec4 o_color;\n";
467 
468     if (loopCountType == LOOPCOUNT_DYNAMIC)
469         vtx << "in mediump float a_one;\n";
470 
471     // Attribute and varyings.
472     if (isVertexCase)
473     {
474         vtx << "out mediump vec3 v_color;\n";
475         frag << "in mediump vec3 v_color;\n";
476     }
477     else
478     {
479         vtx << "out mediump vec4 v_coords;\n";
480         frag << "in mediump vec4 v_coords;\n";
481 
482         if (loopCountType == LOOPCOUNT_DYNAMIC)
483         {
484             vtx << "out mediump float v_one;\n";
485             frag << "in mediump float v_one;\n";
486         }
487     }
488 
489     if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT)
490         op << "uniform bool ub_true;\n";
491 
492     op << "uniform ${COUNTER_PRECISION} int ui_zero, ui_one, ui_two, ui_three, ui_four, ui_five, ui_six;\n";
493     if (loopCase == LOOPCASE_101_ITERATIONS)
494         op << "uniform ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
495 
496     int iterCount = 3; // value to use in loop
497     int numIters  = 3; // actual number of iterations
498 
499     vtx << "\n";
500     vtx << "void main()\n";
501     vtx << "{\n";
502     vtx << "    gl_Position = a_position;\n";
503 
504     frag << "\n";
505     frag << "void main()\n";
506     frag << "{\n";
507 
508     if (loopCountType == LOOPCOUNT_DYNAMIC)
509     {
510         if (isVertexCase)
511             vtx << "    ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
512         else
513             frag << "    ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
514     }
515 
516     if (isVertexCase)
517         vtx << "    ${PRECISION} vec4 coords = a_coords;\n";
518     else
519         frag << "    ${PRECISION} vec4 coords = v_coords;\n";
520 
521     // Read array.
522     op << "    ${PRECISION} vec4 res = coords;\n";
523 
524     // Handle all loop types.
525     string counterPrecisionStr = "mediump";
526     string forLoopStr;
527     string whileLoopStr;
528     string doWhileLoopPreStr;
529     string doWhileLoopPostStr;
530 
531     if (loopType == LOOPTYPE_FOR)
532     {
533         switch (loopCase)
534         {
535         case LOOPCASE_EMPTY_BODY:
536             numIters = 0;
537             op << "    ${FOR_LOOP} {}\n";
538             break;
539 
540         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
541             numIters = 0;
542             op << "    for (;;) { break; res = res.yzwx; }\n";
543             break;
544 
545         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
546             numIters = 1;
547             op << "    for (;;) { res = res.yzwx; break; }\n";
548             break;
549 
550         case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
551             numIters = 2;
552             op << "    ${COUNTER_PRECISION} int i = 0;\n";
553             op << "    for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
554             break;
555 
556         case LOOPCASE_SINGLE_STATEMENT:
557             op << "    ${FOR_LOOP} res = res.yzwx;\n";
558             break;
559 
560         case LOOPCASE_COMPOUND_STATEMENT:
561             iterCount = 2;
562             numIters  = 2 * iterCount;
563             op << "    ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
564             break;
565 
566         case LOOPCASE_SEQUENCE_STATEMENT:
567             iterCount = 2;
568             numIters  = 2 * iterCount;
569             op << "    ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
570             break;
571 
572         case LOOPCASE_NO_ITERATIONS:
573             iterCount = 0;
574             numIters  = 0;
575             op << "    ${FOR_LOOP} res = res.yzwx;\n";
576             break;
577 
578         case LOOPCASE_SINGLE_ITERATION:
579             iterCount = 1;
580             numIters  = 1;
581             op << "    ${FOR_LOOP} res = res.yzwx;\n";
582             break;
583 
584         case LOOPCASE_SELECT_ITERATION_COUNT:
585             op << "    for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
586             break;
587 
588         case LOOPCASE_CONDITIONAL_CONTINUE:
589             numIters = iterCount - 1;
590             op << "    ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
591             break;
592 
593         case LOOPCASE_UNCONDITIONAL_CONTINUE:
594             op << "    ${FOR_LOOP} { res = res.yzwx; continue; }\n";
595             break;
596 
597         case LOOPCASE_ONLY_CONTINUE:
598             numIters = 0;
599             op << "    ${FOR_LOOP} { continue; }\n";
600             break;
601 
602         case LOOPCASE_DOUBLE_CONTINUE:
603             numIters = iterCount - 1;
604             op << "    ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
605             break;
606 
607         case LOOPCASE_CONDITIONAL_BREAK:
608             numIters = 2;
609             op << "    ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
610             break;
611 
612         case LOOPCASE_UNCONDITIONAL_BREAK:
613             numIters = 1;
614             op << "    ${FOR_LOOP} { res = res.yzwx; break; }\n";
615             break;
616 
617         case LOOPCASE_PRE_INCREMENT:
618             op << "    for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
619             break;
620 
621         case LOOPCASE_POST_INCREMENT:
622             op << "    ${FOR_LOOP} { res = res.yzwx; }\n";
623             break;
624 
625         case LOOPCASE_MIXED_BREAK_CONTINUE:
626             numIters  = 2;
627             iterCount = 5;
628             op << "    ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
629             break;
630 
631         case LOOPCASE_VECTOR_COUNTER:
632             op << "    for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res "
633                   "= "
634                   "res.yzwx; }\n";
635             break;
636 
637         case LOOPCASE_101_ITERATIONS:
638             numIters = iterCount = 101;
639             op << "    ${FOR_LOOP} res = res.yzwx;\n";
640             break;
641 
642         case LOOPCASE_SEQUENCE:
643             iterCount = 5;
644             numIters  = 5;
645             op << "    ${COUNTER_PRECISION} int i;\n";
646             op << "    for (i = 0; i < ${TWO}; i++) { res = res.yzwx; }\n";
647             op << "    for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\n";
648             break;
649 
650         case LOOPCASE_NESTED:
651             numIters = 2 * iterCount;
652             op << "    for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
653             op << "    {\n";
654             op << "        for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
655             op << "            res = res.yzwx;\n";
656             op << "    }\n";
657             break;
658 
659         case LOOPCASE_NESTED_SEQUENCE:
660             numIters = 3 * iterCount;
661             op << "    for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
662             op << "    {\n";
663             op << "        for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
664             op << "            res = res.yzwx;\n";
665             op << "        for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
666             op << "            res = res.yzwx;\n";
667             op << "    }\n";
668             break;
669 
670         case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
671             numIters = 2;
672             op << "    ${FOR_LOOP}\n";
673             op << "    {\n";
674             op << "        res = coords; // ignore outer loop effect \n";
675             op << "        for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
676             op << "            res = res.yzwx;\n";
677             op << "    }\n";
678             break;
679 
680         case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
681             numIters = iterCount;
682             op << "    ${FOR_LOOP}\n";
683             op << "    {\n";
684             op << "        res = coords.wxyz;\n";
685             op << "        for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
686             op << "            res = res.yzwx;\n";
687             op << "        coords = res;\n";
688             op << "    }\n";
689             break;
690 
691         default:
692             DE_ASSERT(false);
693         }
694 
695         if (loopCountType == LOOPCOUNT_CONSTANT)
696             forLoopStr =
697                 string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
698         else if (loopCountType == LOOPCOUNT_UNIFORM)
699             forLoopStr =
700                 string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
701         else if (loopCountType == LOOPCOUNT_DYNAMIC)
702             forLoopStr = string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) +
703                          "; i++)";
704         else
705             DE_ASSERT(false);
706     }
707     else if (loopType == LOOPTYPE_WHILE)
708     {
709         switch (loopCase)
710         {
711         case LOOPCASE_EMPTY_BODY:
712             numIters = 0;
713             op << "    ${WHILE_LOOP} {}\n";
714             break;
715 
716         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
717             numIters = 0;
718             op << "    while (true) { break; res = res.yzwx; }\n";
719             break;
720 
721         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
722             numIters = 1;
723             op << "    while (true) { res = res.yzwx; break; }\n";
724             break;
725 
726         case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
727             numIters = 2;
728             op << "    ${COUNTER_PRECISION} int i = 0;\n";
729             op << "    while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
730             break;
731 
732         case LOOPCASE_SINGLE_STATEMENT:
733             op << "    ${WHILE_LOOP} res = res.yzwx;\n";
734             break;
735 
736         case LOOPCASE_COMPOUND_STATEMENT:
737             iterCount = 2;
738             numIters  = 2 * iterCount;
739             op << "    ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
740             break;
741 
742         case LOOPCASE_SEQUENCE_STATEMENT:
743             iterCount = 2;
744             numIters  = 2 * iterCount;
745             op << "    ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
746             break;
747 
748         case LOOPCASE_NO_ITERATIONS:
749             iterCount = 0;
750             numIters  = 0;
751             op << "    ${WHILE_LOOP} res = res.yzwx;\n";
752             break;
753 
754         case LOOPCASE_SINGLE_ITERATION:
755             iterCount = 1;
756             numIters  = 1;
757             op << "    ${WHILE_LOOP} res = res.yzwx;\n";
758             break;
759 
760         case LOOPCASE_SELECT_ITERATION_COUNT:
761             op << "    ${COUNTER_PRECISION} int i = 0;\n";
762             op << "    while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx; i++; }\n";
763             break;
764 
765         case LOOPCASE_CONDITIONAL_CONTINUE:
766             numIters = iterCount - 1;
767             op << "    ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
768             break;
769 
770         case LOOPCASE_UNCONDITIONAL_CONTINUE:
771             op << "    ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
772             break;
773 
774         case LOOPCASE_ONLY_CONTINUE:
775             numIters = 0;
776             op << "    ${WHILE_LOOP} { continue; }\n";
777             break;
778 
779         case LOOPCASE_DOUBLE_CONTINUE:
780             numIters = iterCount - 1;
781             op << "    ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
782             break;
783 
784         case LOOPCASE_CONDITIONAL_BREAK:
785             numIters = 2;
786             op << "    ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
787             break;
788 
789         case LOOPCASE_UNCONDITIONAL_BREAK:
790             numIters = 1;
791             op << "    ${WHILE_LOOP} { res = res.yzwx; break; }\n";
792             break;
793 
794         case LOOPCASE_PRE_INCREMENT:
795             numIters = iterCount - 1;
796             op << "    ${COUNTER_PRECISION} int i = 0;\n";
797             op << "    while (++i < ${ITER_COUNT}) { res = res.yzwx; }\n";
798             break;
799 
800         case LOOPCASE_POST_INCREMENT:
801             op << "    ${COUNTER_PRECISION} int i = 0;\n";
802             op << "    while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
803             break;
804 
805         case LOOPCASE_MIXED_BREAK_CONTINUE:
806             numIters  = 2;
807             iterCount = 5;
808             op << "    ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
809             break;
810 
811         case LOOPCASE_VECTOR_COUNTER:
812             op << "    ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
813             op << "    while (i.x < i.z) { res = res.yzwx; i.x += i.y; }\n";
814             break;
815 
816         case LOOPCASE_101_ITERATIONS:
817             numIters = iterCount = 101;
818             op << "    ${WHILE_LOOP} res = res.yzwx;\n";
819             break;
820 
821         case LOOPCASE_SEQUENCE:
822             iterCount = 6;
823             numIters  = iterCount - 1;
824             op << "    ${COUNTER_PRECISION} int i = 0;\n";
825             op << "    while (i++ < ${TWO}) { res = res.yzwx; }\n";
826             op << "    while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n"; // \note skips one iteration
827             break;
828 
829         case LOOPCASE_NESTED:
830             numIters = 2 * iterCount;
831             op << "    ${COUNTER_PRECISION} int i = 0;\n";
832             op << "    while (i++ < ${TWO})\n";
833             op << "    {\n";
834             op << "        ${COUNTER_PRECISION} int j = 0;\n";
835             op << "        while (j++ < ${ITER_COUNT})\n";
836             op << "            res = res.yzwx;\n";
837             op << "    }\n";
838             break;
839 
840         case LOOPCASE_NESTED_SEQUENCE:
841             numIters = 2 * iterCount;
842             op << "    ${COUNTER_PRECISION} int i = 0;\n";
843             op << "    while (i++ < ${ITER_COUNT})\n";
844             op << "    {\n";
845             op << "        ${COUNTER_PRECISION} int j = 0;\n";
846             op << "        while (j++ < ${ONE})\n";
847             op << "            res = res.yzwx;\n";
848             op << "        while (j++ < ${THREE})\n"; // \note skips one iteration
849             op << "            res = res.yzwx;\n";
850             op << "    }\n";
851             break;
852 
853         case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
854             numIters = 2;
855             op << "    ${WHILE_LOOP}\n";
856             op << "    {\n";
857             op << "        res = coords; // ignore outer loop effect \n";
858             op << "        ${COUNTER_PRECISION} int j = 0;\n";
859             op << "        while (j++ < ${TWO})\n";
860             op << "            res = res.yzwx;\n";
861             op << "    }\n";
862             break;
863 
864         case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
865             numIters = iterCount;
866             op << "    ${WHILE_LOOP}\n";
867             op << "    {\n";
868             op << "        res = coords.wxyz;\n";
869             op << "        ${COUNTER_PRECISION} int j = 0;\n";
870             op << "        while (j++ < ${TWO})\n";
871             op << "            res = res.yzwx;\n";
872             op << "        coords = res;\n";
873             op << "    }\n";
874             break;
875 
876         default:
877             DE_ASSERT(false);
878         }
879 
880         if (loopCountType == LOOPCOUNT_CONSTANT)
881             whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + "    while(i++ < " +
882                            de::toString(iterCount) + ")";
883         else if (loopCountType == LOOPCOUNT_UNIFORM)
884             whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + "    while(i++ < " +
885                            getIntUniformName(iterCount) + ")";
886         else if (loopCountType == LOOPCOUNT_DYNAMIC)
887             whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + "    while(i++ < one*" +
888                            getIntUniformName(iterCount) + ")";
889         else
890             DE_ASSERT(false);
891     }
892     else
893     {
894         DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
895 
896         switch (loopCase)
897         {
898         case LOOPCASE_EMPTY_BODY:
899             numIters = 0;
900             op << "    ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
901             break;
902 
903         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
904             numIters = 0;
905             op << "    do { break; res = res.yzwx; } while (true);\n";
906             break;
907 
908         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
909             numIters = 1;
910             op << "    do { res = res.yzwx; break; } while (true);\n";
911             break;
912 
913         case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
914             numIters = 2;
915             op << "    ${COUNTER_PRECISION} int i = 0;\n";
916             op << "    do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
917             break;
918 
919         case LOOPCASE_SINGLE_STATEMENT:
920             op << "    ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
921             break;
922 
923         case LOOPCASE_COMPOUND_STATEMENT:
924             iterCount = 2;
925             numIters  = 2 * iterCount;
926             op << "    ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
927             break;
928 
929         case LOOPCASE_SEQUENCE_STATEMENT:
930             iterCount = 2;
931             numIters  = 2 * iterCount;
932             op << "    ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
933             break;
934 
935         case LOOPCASE_NO_ITERATIONS:
936             DE_ASSERT(false);
937             break;
938 
939         case LOOPCASE_SINGLE_ITERATION:
940             iterCount = 1;
941             numIters  = 1;
942             op << "    ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
943             break;
944 
945         case LOOPCASE_SELECT_ITERATION_COUNT:
946             op << "    ${COUNTER_PRECISION} int i = 0;\n";
947             op << "    do { res = res.yzwx; } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
948             break;
949 
950         case LOOPCASE_CONDITIONAL_CONTINUE:
951             numIters = iterCount - 1;
952             op << "    ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; } ${DO_WHILE_POST}\n";
953             break;
954 
955         case LOOPCASE_UNCONDITIONAL_CONTINUE:
956             op << "    ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
957             break;
958 
959         case LOOPCASE_ONLY_CONTINUE:
960             numIters = 0;
961             op << "    ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
962             break;
963 
964         case LOOPCASE_DOUBLE_CONTINUE:
965             numIters = iterCount - 1;
966             op << "    ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
967             break;
968 
969         case LOOPCASE_CONDITIONAL_BREAK:
970             numIters = 2;
971             op << "    ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
972             break;
973 
974         case LOOPCASE_UNCONDITIONAL_BREAK:
975             numIters = 1;
976             op << "    ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
977             break;
978 
979         case LOOPCASE_PRE_INCREMENT:
980             op << "    ${COUNTER_PRECISION} int i = 0;\n";
981             op << "    do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
982             break;
983 
984         case LOOPCASE_POST_INCREMENT:
985             numIters = iterCount + 1;
986             op << "    ${COUNTER_PRECISION} int i = 0;\n";
987             op << "    do { res = res.yzwx; } while (i++ < ${ITER_COUNT});\n";
988             break;
989 
990         case LOOPCASE_MIXED_BREAK_CONTINUE:
991             numIters  = 2;
992             iterCount = 5;
993             op << "    ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } "
994                   "${DO_WHILE_POST}\n";
995             break;
996 
997         case LOOPCASE_VECTOR_COUNTER:
998             op << "    ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
999             op << "    do { res = res.yzwx; } while ((i.x += i.y) < i.z);\n";
1000             break;
1001 
1002         case LOOPCASE_101_ITERATIONS:
1003             numIters = iterCount = 101;
1004             op << "    ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1005             break;
1006 
1007         case LOOPCASE_SEQUENCE:
1008             iterCount = 5;
1009             numIters  = 5;
1010             op << "    ${COUNTER_PRECISION} int i = 0;\n";
1011             op << "    do { res = res.yzwx; } while (++i < ${TWO});\n";
1012             op << "    do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1013             break;
1014 
1015         case LOOPCASE_NESTED:
1016             numIters = 2 * iterCount;
1017             op << "    ${COUNTER_PRECISION} int i = 0;\n";
1018             op << "    do\n";
1019             op << "    {\n";
1020             op << "        ${COUNTER_PRECISION} int j = 0;\n";
1021             op << "        do\n";
1022             op << "            res = res.yzwx;\n";
1023             op << "        while (++j < ${ITER_COUNT});\n";
1024             op << "    } while (++i < ${TWO});\n";
1025             break;
1026 
1027         case LOOPCASE_NESTED_SEQUENCE:
1028             numIters = 3 * iterCount;
1029             op << "    ${COUNTER_PRECISION} int i = 0;\n";
1030             op << "    do\n";
1031             op << "    {\n";
1032             op << "        ${COUNTER_PRECISION} int j = 0;\n";
1033             op << "        do\n";
1034             op << "            res = res.yzwx;\n";
1035             op << "        while (++j < ${TWO});\n";
1036             op << "        do\n";
1037             op << "            res = res.yzwx;\n";
1038             op << "        while (++j < ${THREE});\n";
1039             op << "    } while (++i < ${ITER_COUNT});\n";
1040             break;
1041 
1042         case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1043             numIters = 2;
1044             op << "    ${DO_WHILE_PRE}\n";
1045             op << "    {\n";
1046             op << "        res = coords; // ignore outer loop effect \n";
1047             op << "        ${COUNTER_PRECISION} int j = 0;\n";
1048             op << "        do\n";
1049             op << "            res = res.yzwx;\n";
1050             op << "        while (++j < ${TWO});\n";
1051             op << "    } ${DO_WHILE_POST}\n";
1052             break;
1053 
1054         case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1055             numIters = iterCount;
1056             op << "    ${DO_WHILE_PRE}\n";
1057             op << "    {\n";
1058             op << "        res = coords.wxyz;\n";
1059             op << "        ${COUNTER_PRECISION} int j = 0;\n";
1060             op << "        while (j++ < ${TWO})\n";
1061             op << "            res = res.yzwx;\n";
1062             op << "        coords = res;\n";
1063             op << "    } ${DO_WHILE_POST}\n";
1064             break;
1065 
1066         default:
1067             DE_ASSERT(false);
1068         }
1069 
1070         doWhileLoopPreStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1071         if (loopCountType == LOOPCOUNT_CONSTANT)
1072             doWhileLoopPostStr = string(" while (++i < ") + de::toString(iterCount) + ");\n";
1073         else if (loopCountType == LOOPCOUNT_UNIFORM)
1074             doWhileLoopPostStr = string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1075         else if (loopCountType == LOOPCOUNT_DYNAMIC)
1076             doWhileLoopPostStr = string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1077         else
1078             DE_ASSERT(false);
1079     }
1080 
1081     // Shader footers.
1082     if (isVertexCase)
1083     {
1084         vtx << "    v_color = res.rgb;\n";
1085         frag << "    o_color = vec4(v_color.rgb, 1.0);\n";
1086     }
1087     else
1088     {
1089         vtx << "    v_coords = a_coords;\n";
1090         frag << "    o_color = vec4(res.rgb, 1.0);\n";
1091 
1092         if (loopCountType == LOOPCOUNT_DYNAMIC)
1093             vtx << "    v_one = a_one;\n";
1094     }
1095 
1096     vtx << "}\n";
1097     frag << "}\n";
1098 
1099     // Constants.
1100     string oneStr;
1101     string twoStr;
1102     string threeStr;
1103     string iterCountStr;
1104 
1105     if (loopCountType == LOOPCOUNT_CONSTANT)
1106     {
1107         oneStr       = "1";
1108         twoStr       = "2";
1109         threeStr     = "3";
1110         iterCountStr = de::toString(iterCount);
1111     }
1112     else if (loopCountType == LOOPCOUNT_UNIFORM)
1113     {
1114         oneStr       = "ui_one";
1115         twoStr       = "ui_two";
1116         threeStr     = "ui_three";
1117         iterCountStr = getIntUniformName(iterCount);
1118     }
1119     else if (loopCountType == LOOPCOUNT_DYNAMIC)
1120     {
1121         oneStr       = "one*ui_one";
1122         twoStr       = "one*ui_two";
1123         threeStr     = "one*ui_three";
1124         iterCountStr = string("one*") + getIntUniformName(iterCount);
1125     }
1126     else
1127         DE_ASSERT(false);
1128 
1129     // Fill in shader templates.
1130     map<string, string> params;
1131     params.insert(pair<string, string>("PRECISION", "mediump"));
1132     params.insert(pair<string, string>("ITER_COUNT", iterCountStr));
1133     params.insert(pair<string, string>("COUNTER_PRECISION", counterPrecisionStr));
1134     params.insert(pair<string, string>("FOR_LOOP", forLoopStr));
1135     params.insert(pair<string, string>("WHILE_LOOP", whileLoopStr));
1136     params.insert(pair<string, string>("DO_WHILE_PRE", doWhileLoopPreStr));
1137     params.insert(pair<string, string>("DO_WHILE_POST", doWhileLoopPostStr));
1138     params.insert(pair<string, string>("ONE", oneStr));
1139     params.insert(pair<string, string>("TWO", twoStr));
1140     params.insert(pair<string, string>("THREE", threeStr));
1141 
1142     StringTemplate vertTemplate(vtx.str().c_str());
1143     StringTemplate fragTemplate(frag.str().c_str());
1144     string vertexShaderSource   = vertTemplate.specialize(params);
1145     string fragmentShaderSource = fragTemplate.specialize(params);
1146 
1147     // Create the case.
1148     ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1149     return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(),
1150                               fragmentShaderSource.c_str());
1151 }
1152 
1153 // ShaderLoopTests.
1154 
ShaderLoopTests(Context & context)1155 ShaderLoopTests::ShaderLoopTests(Context &context) : TestCaseGroup(context, "loops", "Loop Tests")
1156 {
1157 }
1158 
~ShaderLoopTests(void)1159 ShaderLoopTests::~ShaderLoopTests(void)
1160 {
1161 }
1162 
init(void)1163 void ShaderLoopTests::init(void)
1164 {
1165     // Loop cases.
1166 
1167     static const ShaderType s_shaderTypes[] = {SHADERTYPE_VERTEX, SHADERTYPE_FRAGMENT};
1168 
1169     static const DataType s_countDataType[] = {TYPE_INT, TYPE_FLOAT};
1170 
1171     for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1172     {
1173         const char *loopTypeName = getLoopTypeName((LoopType)loopType);
1174 
1175         for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1176         {
1177             const char *loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1178 
1179             string groupName     = string(loopTypeName) + "_" + string(loopCountName) + "_iterations";
1180             string groupDesc     = string("Loop tests with ") + loopCountName + " loop counter.";
1181             TestCaseGroup *group = new TestCaseGroup(m_context, groupName.c_str(), groupDesc.c_str());
1182             addChild(group);
1183 
1184             // Generic cases.
1185 
1186             for (int precision = 0; precision < PRECISION_LAST; precision++)
1187             {
1188                 const char *precisionName = getPrecisionName((Precision)precision);
1189 
1190                 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1191                 {
1192                     DataType loopDataType    = s_countDataType[dataTypeNdx];
1193                     const char *dataTypeName = getDataTypeName(loopDataType);
1194 
1195                     for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1196                     {
1197                         ShaderType shaderType      = s_shaderTypes[shaderTypeNdx];
1198                         const char *shaderTypeName = getShaderTypeName(shaderType);
1199                         bool isVertexCase          = (shaderType == SHADERTYPE_VERTEX);
1200 
1201                         string name = string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1202                         string desc = string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " +
1203                                       loopCountName + " iteration count in " + shaderTypeName + " shader.";
1204                         group->addChild(createGenericLoopCase(m_context, name.c_str(), desc.c_str(), isVertexCase,
1205                                                               (LoopType)loopType, (LoopCountType)loopCountType,
1206                                                               (Precision)precision, loopDataType));
1207                     }
1208                 }
1209             }
1210 
1211             // Special cases.
1212 
1213             for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1214             {
1215                 const char *loopCaseName = getLoopCaseName((LoopCase)loopCase);
1216 
1217                 // no-iterations not possible with do-while.
1218                 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1219                     continue;
1220 
1221                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1222                 {
1223                     ShaderType shaderType      = s_shaderTypes[shaderTypeNdx];
1224                     const char *shaderTypeName = getShaderTypeName(shaderType);
1225                     bool isVertexCase          = (shaderType == SHADERTYPE_VERTEX);
1226 
1227                     string name = string(loopCaseName) + "_" + shaderTypeName;
1228                     string desc = string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " +
1229                                   shaderTypeName + " shader.";
1230                     group->addChild(createSpecialLoopCase(m_context, name.c_str(), desc.c_str(), isVertexCase,
1231                                                           (LoopCase)loopCase, (LoopType)loopType,
1232                                                           (LoopCountType)loopCountType));
1233                 }
1234             }
1235         }
1236     }
1237 
1238     // Additional smaller handwritten tests.
1239     const std::vector<tcu::TestNode *> children =
1240         gls::ShaderLibrary(m_context.getTestContext(), m_context.getRenderContext(), m_context.getContextInfo())
1241             .loadShaderFile("shaders/loops.test");
1242     for (int i = 0; i < (int)children.size(); i++)
1243         addChild(children[i]);
1244 }
1245 
1246 } // namespace Functional
1247 } // namespace gles3
1248 } // namespace deqp
1249