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