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