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