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