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