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