Merge branch 'jekstrand_renderpass_transfer_bit_fix' into 'master'
[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         vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
324         vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
325
326         frag << "#version 310 es\n";
327         frag << "#extension GL_ARB_separate_shader_objects : enable\n";
328         frag << "#extension GL_ARB_shading_language_420pack : enable\n";
329
330         vtx << "layout(location=0) in highp vec4 a_position;\n";
331         vtx << "layout(location=1) in highp vec4 a_coords;\n";
332         frag << "layout(location=0) out mediump vec4 o_color;\n";
333
334         if (loopCountType == LOOPCOUNT_DYNAMIC)
335                 vtx << "layout(location=3) in mediump float a_one;\n";
336
337         if (isVertexCase)
338         {
339                 vtx << "layout(location=0) out mediump vec3 v_color;\n";
340                 frag << "layout(location=0) in mediump vec3 v_color;\n";
341         }
342         else
343         {
344                 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
345                 frag << "layout(location=0) in mediump vec4 v_coords;\n";
346
347                 if (loopCountType == LOOPCOUNT_DYNAMIC)
348                 {
349                         vtx << "layout(location=1) out mediump float v_one;\n";
350                         frag << "layout(location=1) in mediump float v_one;\n";
351                 }
352         }
353
354         const int       numLoopIters = 3;
355         const bool      isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
356         deUint32        locationCounter = 0;
357         std::vector<BaseUniformType> uniformInformations;
358
359         if (isIntCounter)
360         {
361                 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
362                 {
363                         op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff"<< locationCounter <<" {\n";
364                         op << " ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
365                         op << "};\n";
366                         uniformInformations.push_back(getIntUniformType(numLoopIters));
367                         locationCounter++;
368                 }
369         }
370         else
371         {
372                 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC){
373                         op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
374                         op << " ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
375                         op << "};\n";
376                         uniformInformations.push_back(getFloatFractionUniformType(numLoopIters));
377                         locationCounter++;
378                 }
379
380                 if (numLoopIters != 1){
381                         op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
382                         op << " ${COUNTER_PRECISION} float uf_one;\n";
383                         op << "};\n";
384                         uniformInformations.push_back(UF_ONE);
385                         locationCounter++;
386                 }
387         }
388
389         vtx << "\n";
390         vtx << "void main()\n";
391         vtx << "{\n";
392         vtx << "        gl_Position = a_position;\n";
393
394         frag << "\n";
395         frag << "void main()\n";
396         frag << "{\n";
397
398         if (isVertexCase)
399                 vtx << "        ${PRECISION} vec4 coords = a_coords;\n";
400         else
401                 frag << "       ${PRECISION} vec4 coords = v_coords;\n";
402
403
404         if (loopCountType == LOOPCOUNT_DYNAMIC)
405         {
406                 if (isIntCounter)
407                 {
408                         if (isVertexCase)
409                                 vtx << "        ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
410                         else
411                                 frag << "       ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
412                 }
413                 else
414                 {
415                         if (isVertexCase)
416                                 vtx << "        ${COUNTER_PRECISION} float one = a_one;\n";
417                         else
418                                 frag << "       ${COUNTER_PRECISION} float one = v_one;\n";
419                 }
420         }
421
422         // Read array.
423         op << " ${PRECISION} vec4 res = coords;\n";
424
425         // Loop iteration count.
426         std::string     iterMaxStr;
427
428         if (isIntCounter)
429         {
430                 if (loopCountType == LOOPCOUNT_CONSTANT)
431                         iterMaxStr = de::toString(numLoopIters);
432                 else if (loopCountType == LOOPCOUNT_UNIFORM)
433                         iterMaxStr = getIntUniformName(numLoopIters);
434                 else if (loopCountType == LOOPCOUNT_DYNAMIC)
435                         iterMaxStr = std::string(getIntUniformName(numLoopIters)) + "*one";
436                 else
437                         DE_ASSERT(false);
438         }
439         else
440         {
441                 if (loopCountType == LOOPCOUNT_CONSTANT)
442                         iterMaxStr = "1.0";
443                 else if (loopCountType == LOOPCOUNT_UNIFORM)
444                         iterMaxStr = "uf_one";
445                 else if (loopCountType == LOOPCOUNT_DYNAMIC)
446                         iterMaxStr = "uf_one*one";
447                 else
448                         DE_ASSERT(false);
449         }
450
451         // Loop operations.
452         std::string initValue                   = isIntCounter ? "0" : "0.05";
453         std::string loopCountDeclStr    = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
454         std::string loopCmpStr                  = ("ndx < " + iterMaxStr);
455         std::string incrementStr;
456         if (isIntCounter)
457                 incrementStr = "ndx++";
458         else
459         {
460                 if (loopCountType == LOOPCOUNT_CONSTANT)
461                         incrementStr = std::string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
462                 else if (loopCountType == LOOPCOUNT_UNIFORM)
463                         incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters);
464                 else if (loopCountType == LOOPCOUNT_DYNAMIC)
465                         incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
466                 else
467                         DE_ASSERT(false);
468         }
469
470         // Loop body.
471         std::string loopBody;
472
473         loopBody = "            res = res.yzwx;\n";
474
475         if (loopType == LOOPTYPE_FOR)
476         {
477                 op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
478                 op << " {\n";
479                 op << loopBody;
480                 op << " }\n";
481         }
482         else if (loopType == LOOPTYPE_WHILE)
483         {
484                 op << "\t" << loopCountDeclStr + ";\n";
485                 op << " while (" + loopCmpStr + ")\n";
486                 op << " {\n";
487                 op << loopBody;
488                 op << "\t\t" + incrementStr + ";\n";
489                 op << " }\n";
490         }
491         else if (loopType == LOOPTYPE_DO_WHILE)
492         {
493                 op << "\t" << loopCountDeclStr + ";\n";
494                 op << " do\n";
495                 op << " {\n";
496                 op << loopBody;
497                 op << "\t\t" + incrementStr + ";\n";
498                 op << " } while (" + loopCmpStr + ");\n";
499         }
500         else
501                 DE_ASSERT(false);
502
503         if (isVertexCase)
504         {
505                 vtx << "        v_color = res.rgb;\n";
506                 frag << "       o_color = vec4(v_color.rgb, 1.0);\n";
507         }
508         else
509         {
510                 vtx << "        v_coords = a_coords;\n";
511                 frag << "       o_color = vec4(res.rgb, 1.0);\n";
512
513                 if (loopCountType == LOOPCOUNT_DYNAMIC)
514                         vtx << "        v_one = a_one;\n";
515         }
516
517         vtx << "}\n";
518         frag << "}\n";
519
520         // Fill in shader templates.
521         std::map<std::string, std::string> params;
522         params.insert(std::pair<std::string, std::string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
523         params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
524         params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
525
526         tcu::StringTemplate vertTemplate(vtx.str());
527         tcu::StringTemplate fragTemplate(frag.str());
528         std::string vertexShaderSource = vertTemplate.specialize(params);
529         std::string fragmentShaderSource = fragTemplate.specialize(params);
530
531         // Create the case.
532         ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
533         UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
534         return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
535 }
536
537 static de::MovePtr<ShaderLoopCase> createSpecialLoopCase (tcu::TestContext&     testCtx,
538                                                                                                                 const std::string&      caseName,
539                                                                                                                 const std::string&      description,
540                                                                                                                 bool                            isVertexCase,
541                                                                                                                 LoopCase                        loopCase,
542                                                                                                                 LoopType                        loopType,
543                                                                                                                 LoopCountType           loopCountType)
544 {
545         std::ostringstream vtx;
546         std::ostringstream frag;
547         std::ostringstream& op = isVertexCase ? vtx : frag;
548
549         std::vector<BaseUniformType>    uniformInformations;
550         deUint32                                                locationCounter = 0;
551
552         vtx << "#version 310 es\n";
553         vtx << "#extension GL_ARB_separate_shader_objects : enable\n";
554         vtx << "#extension GL_ARB_shading_language_420pack : enable\n";
555
556         frag << "#version 310 es\n";
557         frag << "#extension GL_ARB_separate_shader_objects : enable\n";
558         frag << "#extension GL_ARB_shading_language_420pack : enable\n";
559
560         vtx << "layout(location=0) in highp vec4 a_position;\n";
561         vtx << "layout(location=1) in highp vec4 a_coords;\n";
562         frag << "layout(location=0) out mediump vec4 o_color;\n";
563
564         if (loopCountType == LOOPCOUNT_DYNAMIC)
565                 vtx << "layout(location=3) in mediump float a_one;\n";
566
567         if (isVertexCase)
568         {
569                 vtx << "layout(location=0) out mediump vec3 v_color;\n";
570                 frag << "layout(location=0) in mediump vec3 v_color;\n";
571         }
572         else
573         {
574                 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
575                 frag << "layout(location=0) in mediump vec4 v_coords;\n";
576
577                 if (loopCountType == LOOPCOUNT_DYNAMIC)
578                 {
579                         vtx << "layout(location=1) out mediump float v_one;\n";
580                         frag << "layout(location=1) in mediump float v_one;\n";
581                 }
582         }
583
584         if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) {
585                 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
586                 op << "  bool ub_true;\n";
587                 op << "};\n";
588                 uniformInformations.push_back(UB_TRUE);
589                 locationCounter++;
590         }
591
592         struct
593         {
594                 char const*             name;
595                 BaseUniformType type;
596         } uniforms[] =
597         {
598                 { "ui_zero",    UI_ZERO },
599                 { "ui_one",             UI_ONE },
600                 { "ui_two",             UI_TWO },
601                 { "ui_three",   UI_THREE },
602                 { "ui_four",    UI_FOUR },
603                 { "ui_five",    UI_FIVE },
604                 { "ui_six",             UI_SIX  },
605         };
606
607         for (int i = 0; i < DE_LENGTH_OF_ARRAY(uniforms); ++i)
608         {
609                 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
610                 op << "  ${COUNTER_PRECISION} int " << uniforms[i].name << ";\n";
611                 op << "};\n";
612                 uniformInformations.push_back(uniforms[i].type);
613                 locationCounter++;
614         }
615
616         if (loopCase == LOOPCASE_101_ITERATIONS) {
617
618                 op << "layout(std140, set=0, binding=" << locationCounter <<  ") uniform buff" << locationCounter << " {\n";
619                 op << "  ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
620                 op << "};\n";
621                 uniformInformations.push_back(UI_ONEHUNDREDONE);
622                 locationCounter++;
623         }
624
625         int iterCount   = 3;    // value to use in loop
626         int numIters    = 3;    // actual number of iterations
627
628         vtx << "\n";
629         vtx << "void main()\n";
630         vtx << "{\n";
631         vtx << "        gl_Position = a_position;\n";
632
633         frag << "\n";
634         frag << "void main()\n";
635         frag << "{\n";
636
637         if (loopCountType == LOOPCOUNT_DYNAMIC)
638         {
639                 if (isVertexCase)
640                         vtx << "        ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
641                 else
642                         frag << "       ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
643         }
644
645         if (isVertexCase)
646                 vtx << "        ${PRECISION} vec4 coords = a_coords;\n";
647         else
648                 frag << "       ${PRECISION} vec4 coords = v_coords;\n";
649
650         // Read array.
651         op << " ${PRECISION} vec4 res = coords;\n";
652
653         // Handle all loop types.
654         std::string counterPrecisionStr = "mediump";
655         std::string forLoopStr;
656         std::string whileLoopStr;
657         std::string doWhileLoopPreStr;
658         std::string doWhileLoopPostStr;
659
660         if (loopType == LOOPTYPE_FOR)
661         {
662                 switch (loopCase)
663                 {
664                         case LOOPCASE_EMPTY_BODY:
665                                 numIters = 0;
666                                 op << " ${FOR_LOOP} {}\n";
667                                 break;
668
669                         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
670                                 numIters = 0;
671                                 op << " for (;;) { break; res = res.yzwx; }\n";
672                                 break;
673
674                         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
675                                 numIters = 1;
676                                 op << " for (;;) { res = res.yzwx; break; }\n";
677                                 break;
678
679                         case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
680                                 numIters = 2;
681                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
682                                 op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
683                                 break;
684
685                         case LOOPCASE_SINGLE_STATEMENT:
686                                 op << " ${FOR_LOOP} res = res.yzwx;\n";
687                                 break;
688
689                         case LOOPCASE_COMPOUND_STATEMENT:
690                                 iterCount       = 2;
691                                 numIters        = 2 * iterCount;
692                                 op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
693                                 break;
694
695                         case LOOPCASE_SEQUENCE_STATEMENT:
696                                 iterCount       = 2;
697                                 numIters        = 2 * iterCount;
698                                 op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
699                                 break;
700
701                         case LOOPCASE_NO_ITERATIONS:
702                                 iterCount       = 0;
703                                 numIters        = 0;
704                                 op << " ${FOR_LOOP} res = res.yzwx;\n";
705                                 break;
706
707                         case LOOPCASE_SINGLE_ITERATION:
708                                 iterCount       = 1;
709                                 numIters        = 1;
710                                 op << " ${FOR_LOOP} res = res.yzwx;\n";
711                                 break;
712
713                         case LOOPCASE_SELECT_ITERATION_COUNT:
714                                 op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
715                                 break;
716
717                         case LOOPCASE_CONDITIONAL_CONTINUE:
718                                 numIters = iterCount - 1;
719                                 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
720                                 break;
721
722                         case LOOPCASE_UNCONDITIONAL_CONTINUE:
723                                 op << " ${FOR_LOOP} { res = res.yzwx; continue; }\n";
724                                 break;
725
726                         case LOOPCASE_ONLY_CONTINUE:
727                                 numIters = 0;
728                                 op << " ${FOR_LOOP} { continue; }\n";
729                                 break;
730
731                         case LOOPCASE_DOUBLE_CONTINUE:
732                                 numIters = iterCount - 1;
733                                 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
734                                 break;
735
736                         case LOOPCASE_CONDITIONAL_BREAK:
737                                 numIters = 2;
738                                 op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
739                                 break;
740
741                         case LOOPCASE_UNCONDITIONAL_BREAK:
742                                 numIters = 1;
743                                 op << " ${FOR_LOOP} { res = res.yzwx; break; }\n";
744                                 break;
745
746                         case LOOPCASE_PRE_INCREMENT:
747                                 op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
748                                 break;
749
750                         case LOOPCASE_POST_INCREMENT:
751                                 op << " ${FOR_LOOP} { res = res.yzwx; }\n";
752                                 break;
753
754                         case LOOPCASE_MIXED_BREAK_CONTINUE:
755                                 numIters        = 2;
756                                 iterCount       = 5;
757                                 op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
758                                 break;
759
760                         case LOOPCASE_VECTOR_COUNTER:
761                                 op << " for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res = res.yzwx; }\n";
762                                 break;
763
764                         case LOOPCASE_101_ITERATIONS:
765                                 numIters = iterCount = 101;
766                                 op << " ${FOR_LOOP} res = res.yzwx;\n";
767                                 break;
768
769                         case LOOPCASE_SEQUENCE:
770                                 iterCount       = 5;
771                                 numIters        = 5;
772                                 op << " ${COUNTER_PRECISION} int i;\n";
773                                 op << " for (i = 0; i < ${TWO}; i++) { res = res.yzwx; }\n";
774                                 op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\n";
775                                 break;
776
777                         case LOOPCASE_NESTED:
778                                 numIters = 2 * iterCount;
779                                 op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
780                                 op << " {\n";
781                                 op << "         for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
782                                 op << "                 res = res.yzwx;\n";
783                                 op << " }\n";
784                                 break;
785
786                         case LOOPCASE_NESTED_SEQUENCE:
787                                 numIters = 3 * iterCount;
788                                 op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
789                                 op << " {\n";
790                                 op << "         for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
791                                 op << "                 res = res.yzwx;\n";
792                                 op << "         for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
793                                 op << "                 res = res.yzwx;\n";
794                                 op << " }\n";
795                                 break;
796
797                         case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
798                                 numIters = 2;
799                                 op << " ${FOR_LOOP}\n";
800                                 op << " {\n";
801                                 op << "         res = coords; // ignore outer loop effect \n";
802                                 op << "         for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
803                                 op << "                 res = res.yzwx;\n";
804                                 op << " }\n";
805                                 break;
806
807                         case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
808                                 numIters = iterCount;
809                                 op << " ${FOR_LOOP}\n";
810                                 op << " {\n";
811                                 op << "         res = coords.wxyz;\n";
812                                 op << "         for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
813                                 op << "                 res = res.yzwx;\n";
814                                 op << "         coords = res;\n";
815                                 op << " }\n";
816                                 break;
817
818                         default:
819                                 DE_ASSERT(false);
820                 }
821
822                 if (loopCountType == LOOPCOUNT_CONSTANT)
823                         forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
824                 else if (loopCountType == LOOPCOUNT_UNIFORM)
825                         forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
826                 else if (loopCountType == LOOPCOUNT_DYNAMIC)
827                         forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) + "; i++)";
828                 else
829                         DE_ASSERT(false);
830         }
831         else if (loopType == LOOPTYPE_WHILE)
832         {
833                 switch (loopCase)
834                 {
835                         case LOOPCASE_EMPTY_BODY:
836                                 numIters = 0;
837                                 op << " ${WHILE_LOOP} {}\n";
838                                 break;
839
840                         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
841                                 numIters = 0;
842                                 op << " while (true) { break; res = res.yzwx; }\n";
843                                 break;
844
845                         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
846                                 numIters = 1;
847                                 op << " while (true) { res = res.yzwx; break; }\n";
848                                 break;
849
850                         case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
851                                 numIters = 2;
852                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
853                                 op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
854                                 break;
855
856                         case LOOPCASE_SINGLE_STATEMENT:
857                                 op << " ${WHILE_LOOP} res = res.yzwx;\n";
858                                 break;
859
860                         case LOOPCASE_COMPOUND_STATEMENT:
861                                 iterCount       = 2;
862                                 numIters        = 2 * iterCount;
863                                 op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
864                                 break;
865
866                         case LOOPCASE_SEQUENCE_STATEMENT:
867                                 iterCount       = 2;
868                                 numIters        = 2 * iterCount;
869                                 op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
870                                 break;
871
872                         case LOOPCASE_NO_ITERATIONS:
873                                 iterCount       = 0;
874                                 numIters        = 0;
875                                 op << " ${WHILE_LOOP} res = res.yzwx;\n";
876                                 break;
877
878                         case LOOPCASE_SINGLE_ITERATION:
879                                 iterCount       = 1;
880                                 numIters        = 1;
881                                 op << " ${WHILE_LOOP} res = res.yzwx;\n";
882                                 break;
883
884                         case LOOPCASE_SELECT_ITERATION_COUNT:
885                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
886                                 op << " while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx; i++; }\n";
887                                 break;
888
889                         case LOOPCASE_CONDITIONAL_CONTINUE:
890                                 numIters = iterCount - 1;
891                                 op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
892                                 break;
893
894                         case LOOPCASE_UNCONDITIONAL_CONTINUE:
895                                 op << " ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
896                                 break;
897
898                         case LOOPCASE_ONLY_CONTINUE:
899                                 numIters = 0;
900                                 op << " ${WHILE_LOOP} { continue; }\n";
901                                 break;
902
903                         case LOOPCASE_DOUBLE_CONTINUE:
904                                 numIters = iterCount - 1;
905                                 op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
906                                 break;
907
908                         case LOOPCASE_CONDITIONAL_BREAK:
909                                 numIters = 2;
910                                 op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
911                                 break;
912
913                         case LOOPCASE_UNCONDITIONAL_BREAK:
914                                 numIters = 1;
915                                 op << " ${WHILE_LOOP} { res = res.yzwx; break; }\n";
916                                 break;
917
918                         case LOOPCASE_PRE_INCREMENT:
919                                 numIters = iterCount - 1;
920                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
921                                 op << " while (++i < ${ITER_COUNT}) { res = res.yzwx; }\n";
922                                 break;
923
924                         case LOOPCASE_POST_INCREMENT:
925                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
926                                 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
927                                 break;
928
929                         case LOOPCASE_MIXED_BREAK_CONTINUE:
930                                 numIters        = 2;
931                                 iterCount       = 5;
932                                 op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
933                                 break;
934
935                         case LOOPCASE_VECTOR_COUNTER:
936                                 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
937                                 op << " while (i.x < i.z) { res = res.yzwx; i.x += i.y; }\n";
938                                 break;
939
940                         case LOOPCASE_101_ITERATIONS:
941                                 numIters = iterCount = 101;
942                                 op << " ${WHILE_LOOP} res = res.yzwx;\n";
943                                 break;
944
945                         case LOOPCASE_SEQUENCE:
946                                 iterCount       = 6;
947                                 numIters        = iterCount - 1;
948                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
949                                 op << " while (i++ < ${TWO}) { res = res.yzwx; }\n";
950                                 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n"; // \note skips one iteration
951                                 break;
952
953                         case LOOPCASE_NESTED:
954                                 numIters = 2 * iterCount;
955                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
956                                 op << " while (i++ < ${TWO})\n";
957                                 op << " {\n";
958                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
959                                 op << "         while (j++ < ${ITER_COUNT})\n";
960                                 op << "                 res = res.yzwx;\n";
961                                 op << " }\n";
962                                 break;
963
964                         case LOOPCASE_NESTED_SEQUENCE:
965                                 numIters = 2 * iterCount;
966                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
967                                 op << " while (i++ < ${ITER_COUNT})\n";
968                                 op << " {\n";
969                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
970                                 op << "         while (j++ < ${ONE})\n";
971                                 op << "                 res = res.yzwx;\n";
972                                 op << "         while (j++ < ${THREE})\n"; // \note skips one iteration
973                                 op << "                 res = res.yzwx;\n";
974                                 op << " }\n";
975                                 break;
976
977                         case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
978                                 numIters = 2;
979                                 op << " ${WHILE_LOOP}\n";
980                                 op << " {\n";
981                                 op << "         res = coords; // ignore outer loop effect \n";
982                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
983                                 op << "         while (j++ < ${TWO})\n";
984                                 op << "                 res = res.yzwx;\n";
985                                 op << " }\n";
986                                 break;
987
988                         case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
989                                 numIters = iterCount;
990                                 op << " ${WHILE_LOOP}\n";
991                                 op << " {\n";
992                                 op << "         res = coords.wxyz;\n";
993                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
994                                 op << "         while (j++ < ${TWO})\n";
995                                 op << "                 res = res.yzwx;\n";
996                                 op << "         coords = res;\n";
997                                 op << " }\n";
998                                 break;
999
1000                         default:
1001                                 DE_ASSERT(false);
1002                 }
1003
1004                 if (loopCountType == LOOPCOUNT_CONSTANT)
1005                         whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "    while(i++ < " + de::toString(iterCount) + ")";
1006                 else if (loopCountType == LOOPCOUNT_UNIFORM)
1007                         whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "    while(i++ < " + getIntUniformName(iterCount) + ")";
1008                 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1009                         whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "    while(i++ < one*" + getIntUniformName(iterCount) + ")";
1010                 else
1011                         DE_ASSERT(false);
1012         }
1013         else
1014         {
1015                 DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
1016
1017                 switch (loopCase)
1018                 {
1019                         case LOOPCASE_EMPTY_BODY:
1020                                 numIters = 0;
1021                                 op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
1022                                 break;
1023
1024                         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
1025                                 numIters = 0;
1026                                 op << " do { break; res = res.yzwx; } while (true);\n";
1027                                 break;
1028
1029                         case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
1030                                 numIters = 1;
1031                                 op << " do { res = res.yzwx; break; } while (true);\n";
1032                                 break;
1033
1034                         case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
1035                                 numIters = 2;
1036                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
1037                                 op << " do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
1038                                 break;
1039
1040                         case LOOPCASE_SINGLE_STATEMENT:
1041                                 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1042                                 break;
1043
1044                         case LOOPCASE_COMPOUND_STATEMENT:
1045                                 iterCount       = 2;
1046                                 numIters        = 2 * iterCount;
1047                                 op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
1048                                 break;
1049
1050                         case LOOPCASE_SEQUENCE_STATEMENT:
1051                                 iterCount       = 2;
1052                                 numIters        = 2 * iterCount;
1053                                 op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
1054                                 break;
1055
1056                         case LOOPCASE_NO_ITERATIONS:
1057                                 DE_ASSERT(false);
1058                                 break;
1059
1060                         case LOOPCASE_SINGLE_ITERATION:
1061                                 iterCount       = 1;
1062                                 numIters        = 1;
1063                                 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1064                                 break;
1065
1066                         case LOOPCASE_SELECT_ITERATION_COUNT:
1067                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
1068                                 op << " do { res = res.yzwx; } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
1069                                 break;
1070
1071                         case LOOPCASE_CONDITIONAL_CONTINUE:
1072                                 numIters = iterCount - 1;
1073                                 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; } ${DO_WHILE_POST}\n";
1074                                 break;
1075
1076                         case LOOPCASE_UNCONDITIONAL_CONTINUE:
1077                                 op << " ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1078                                 break;
1079
1080                         case LOOPCASE_ONLY_CONTINUE:
1081                                 numIters = 0;
1082                                 op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
1083                                 break;
1084
1085                         case LOOPCASE_DOUBLE_CONTINUE:
1086                                 numIters = iterCount - 1;
1087                                 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1088                                 break;
1089
1090                         case LOOPCASE_CONDITIONAL_BREAK:
1091                                 numIters = 2;
1092                                 op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
1093                                 break;
1094
1095                         case LOOPCASE_UNCONDITIONAL_BREAK:
1096                                 numIters = 1;
1097                                 op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
1098                                 break;
1099
1100                         case LOOPCASE_PRE_INCREMENT:
1101                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
1102                                 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1103                                 break;
1104
1105                         case LOOPCASE_POST_INCREMENT:
1106                                 numIters = iterCount + 1;
1107                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
1108                                 op << " do { res = res.yzwx; } while (i++ < ${ITER_COUNT});\n";
1109                                 break;
1110
1111                         case LOOPCASE_MIXED_BREAK_CONTINUE:
1112                                 numIters        = 2;
1113                                 iterCount       = 5;
1114                                 op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } ${DO_WHILE_POST}\n";
1115                                 break;
1116
1117                         case LOOPCASE_VECTOR_COUNTER:
1118                                 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
1119                                 op << " do { res = res.yzwx; } while ((i.x += i.y) < i.z);\n";
1120                                 break;
1121
1122                         case LOOPCASE_101_ITERATIONS:
1123                                 numIters = iterCount = 101;
1124                                 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1125                                 break;
1126
1127                         case LOOPCASE_SEQUENCE:
1128                                 iterCount       = 5;
1129                                 numIters        = 5;
1130                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
1131                                 op << " do { res = res.yzwx; } while (++i < ${TWO});\n";
1132                                 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1133                                 break;
1134
1135                         case LOOPCASE_NESTED:
1136                                 numIters = 2 * iterCount;
1137                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
1138                                 op << " do\n";
1139                                 op << " {\n";
1140                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
1141                                 op << "         do\n";
1142                                 op << "                 res = res.yzwx;\n";
1143                                 op << "         while (++j < ${ITER_COUNT});\n";
1144                                 op << " } while (++i < ${TWO});\n";
1145                                 break;
1146
1147                         case LOOPCASE_NESTED_SEQUENCE:
1148                                 numIters = 3 * iterCount;
1149                                 op << " ${COUNTER_PRECISION} int i = 0;\n";
1150                                 op << " do\n";
1151                                 op << " {\n";
1152                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
1153                                 op << "         do\n";
1154                                 op << "                 res = res.yzwx;\n";
1155                                 op << "         while (++j < ${TWO});\n";
1156                                 op << "         do\n";
1157                                 op << "                 res = res.yzwx;\n";
1158                                 op << "         while (++j < ${THREE});\n";
1159                                 op << " } while (++i < ${ITER_COUNT});\n";
1160                                 break;
1161
1162                         case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1163                                 numIters = 2;
1164                                 op << " ${DO_WHILE_PRE}\n";
1165                                 op << " {\n";
1166                                 op << "         res = coords; // ignore outer loop effect \n";
1167                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
1168                                 op << "         do\n";
1169                                 op << "                 res = res.yzwx;\n";
1170                                 op << "         while (++j < ${TWO});\n";
1171                                 op << " } ${DO_WHILE_POST}\n";
1172                                 break;
1173
1174                         case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1175                                 numIters = iterCount;
1176                                 op << " ${DO_WHILE_PRE}\n";
1177                                 op << " {\n";
1178                                 op << "         res = coords.wxyz;\n";
1179                                 op << "         ${COUNTER_PRECISION} int j = 0;\n";
1180                                 op << "         while (j++ < ${TWO})\n";
1181                                 op << "                 res = res.yzwx;\n";
1182                                 op << "         coords = res;\n";
1183                                 op << " } ${DO_WHILE_POST}\n";
1184                                 break;
1185
1186                         default:
1187                                 DE_ASSERT(false);
1188                 }
1189
1190                 doWhileLoopPreStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1191                 if (loopCountType == LOOPCOUNT_CONSTANT)
1192                         doWhileLoopPostStr = std::string(" while (++i < ") + de::toString(iterCount) + ");\n";
1193                 else if (loopCountType == LOOPCOUNT_UNIFORM)
1194                         doWhileLoopPostStr = std::string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1195                 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1196                         doWhileLoopPostStr = std::string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1197                 else
1198                         DE_ASSERT(false);
1199         }
1200
1201         // Shader footers.
1202         if (isVertexCase)
1203         {
1204                 vtx << "        v_color = res.rgb;\n";
1205                 frag << "       o_color = vec4(v_color.rgb, 1.0);\n";
1206         }
1207         else
1208         {
1209                 vtx << "        v_coords = a_coords;\n";
1210                 frag << "       o_color = vec4(res.rgb, 1.0);\n";
1211
1212                 if (loopCountType == LOOPCOUNT_DYNAMIC)
1213                         vtx << "        v_one = a_one;\n";
1214         }
1215
1216         vtx << "}\n";
1217         frag << "}\n";
1218
1219         // Constants.
1220         std::string oneStr;
1221         std::string twoStr;
1222         std::string threeStr;
1223         std::string iterCountStr;
1224
1225         if (loopCountType == LOOPCOUNT_CONSTANT)
1226         {
1227                 oneStr                  = "1";
1228                 twoStr                  = "2";
1229                 threeStr                = "3";
1230                 iterCountStr    = de::toString(iterCount);
1231         }
1232         else if (loopCountType == LOOPCOUNT_UNIFORM)
1233         {
1234                 oneStr                  = "ui_one";
1235                 twoStr                  = "ui_two";
1236                 threeStr                = "ui_three";
1237                 iterCountStr    = getIntUniformName(iterCount);
1238         }
1239         else if (loopCountType == LOOPCOUNT_DYNAMIC)
1240         {
1241                 oneStr                  = "one*ui_one";
1242                 twoStr                  = "one*ui_two";
1243                 threeStr                = "one*ui_three";
1244                 iterCountStr    = std::string("one*") + getIntUniformName(iterCount);
1245         }
1246         else DE_ASSERT(false);
1247
1248         // Fill in shader templates.
1249         std::map<std::string, std::string> params;
1250         params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
1251         params.insert(std::pair<std::string, std::string>("ITER_COUNT", iterCountStr));
1252         params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", counterPrecisionStr));
1253         params.insert(std::pair<std::string, std::string>("FOR_LOOP", forLoopStr));
1254         params.insert(std::pair<std::string, std::string>("WHILE_LOOP", whileLoopStr));
1255         params.insert(std::pair<std::string, std::string>("DO_WHILE_PRE", doWhileLoopPreStr));
1256         params.insert(std::pair<std::string, std::string>("DO_WHILE_POST", doWhileLoopPostStr));
1257         params.insert(std::pair<std::string, std::string>("ONE", oneStr));
1258         params.insert(std::pair<std::string, std::string>("TWO", twoStr));
1259         params.insert(std::pair<std::string, std::string>("THREE", threeStr));
1260
1261         tcu::StringTemplate vertTemplate(vtx.str());
1262         tcu::StringTemplate fragTemplate(frag.str());
1263         std::string vertexShaderSource = vertTemplate.specialize(params);
1264         std::string fragmentShaderSource = fragTemplate.specialize(params);
1265
1266         // Create the case.
1267         UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
1268         ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1269         return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
1270 }
1271
1272 class ShaderLoopTests : public tcu::TestCaseGroup
1273 {
1274 public:
1275                                                         ShaderLoopTests                 (tcu::TestContext& testCtx);
1276         virtual                                 ~ShaderLoopTests                (void);
1277
1278         virtual void                    init                                    (void);
1279
1280 private:
1281                                                         ShaderLoopTests                 (const ShaderLoopTests&);               // not allowed!
1282         ShaderLoopTests&                operator=                               (const ShaderLoopTests&);               // not allowed!
1283 };
1284
1285 ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
1286                 : TestCaseGroup(testCtx, "loops", "Loop Tests")
1287 {
1288 }
1289
1290 ShaderLoopTests::~ShaderLoopTests (void)
1291 {
1292 }
1293
1294 void ShaderLoopTests::init (void)
1295 {
1296         // Loop cases.
1297
1298         static const glu::ShaderType s_shaderTypes[] =
1299         {
1300                 glu::SHADERTYPE_VERTEX,
1301                 glu::SHADERTYPE_FRAGMENT
1302         };
1303
1304         static const glu::DataType s_countDataType[] =
1305         {
1306                 glu::TYPE_INT,
1307                 glu::TYPE_FLOAT
1308         };
1309
1310         TestCaseGroup* genericGroup = new TestCaseGroup(m_testCtx, "generic", "Generic loop tests.");
1311         TestCaseGroup* specialGroup = new TestCaseGroup(m_testCtx, "special", "Special loop tests.");
1312         addChild(genericGroup);
1313         addChild(specialGroup);
1314
1315         for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1316         {
1317                 const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1318
1319                 for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1320                 {
1321                         const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1322
1323                         std::string groupName = std::string(loopTypeName) + "_" + std::string(loopCountName) + "_iterations";
1324                         std::string groupDesc = std::string("Loop tests with ") + loopCountName + " loop counter.";
1325                         TestCaseGroup* genericSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1326                         TestCaseGroup* specialSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1327                         genericGroup->addChild(genericSubGroup);
1328                         specialGroup->addChild(specialSubGroup);
1329
1330                         // Generic cases.
1331
1332                         for (int precision = 0; precision < glu::PRECISION_LAST; precision++)
1333                         {
1334                                 const char* precisionName = getPrecisionName((glu::Precision)precision);
1335
1336                                 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1337                                 {
1338                                         glu::DataType loopDataType = s_countDataType[dataTypeNdx];
1339                                         const char* dataTypeName = getDataTypeName(loopDataType);
1340
1341                                         for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1342                                         {
1343                                                 glu::ShaderType shaderType              = s_shaderTypes[shaderTypeNdx];
1344                                                 const char*     shaderTypeName  = getShaderTypeName(shaderType);
1345                                                 bool            isVertexCase    = (shaderType == glu::SHADERTYPE_VERTEX);
1346
1347                                                 std::string testName = std::string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1348                                                 std::string testDesc = std::string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " + loopCountName + " iteration count in " + shaderTypeName + " shader.";
1349                                                 de::MovePtr<ShaderLoopCase> testCase(createGenericLoopCase(m_testCtx, testName.c_str(), testDesc.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (glu::Precision)precision, loopDataType));
1350                                                 genericSubGroup->addChild(testCase.release());
1351                                         }
1352                                 }
1353                         }
1354
1355                         // Special cases.
1356
1357                         for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1358                         {
1359                                 const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1360
1361                                 // no-iterations not possible with do-while.
1362                                 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1363                                         continue;
1364
1365                                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1366                                 {
1367                                         glu::ShaderType shaderType              = s_shaderTypes[shaderTypeNdx];
1368                                         const char*     shaderTypeName  = getShaderTypeName(shaderType);
1369                                         bool            isVertexCase    = (shaderType == glu::SHADERTYPE_VERTEX);
1370
1371                                         std::string name = std::string(loopCaseName) + "_" + shaderTypeName;
1372                                         std::string desc = std::string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " + shaderTypeName + " shader.";
1373                                         de::MovePtr<ShaderLoopCase> testCase(createSpecialLoopCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType));
1374                                         specialSubGroup->addChild(testCase.release());
1375                                 }
1376                         }
1377                 }
1378         }
1379 }
1380
1381 } // anonymous
1382
1383 tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
1384 {
1385         return new ShaderLoopTests(testCtx);
1386 }
1387
1388
1389 } // sr
1390 } // vkt