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