1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Texture wrap mode test case
24 * - loop body cases (do different operations inside the loops)
25 * - more complex nested loops
27 * * dataflow variations
30 *//*--------------------------------------------------------------------*/
32 #include "es3fShaderLoopTests.hpp"
33 #include "glsShaderLibrary.hpp"
34 #include "glsShaderRenderCase.hpp"
35 #include "gluShaderUtil.hpp"
36 #include "tcuStringTemplate.hpp"
38 #include "deStringUtil.hpp"
47 using namespace deqp::gls;
56 // Repeated with for, while, do-while. Examples given as 'for' loops.
57 // Repeated for const, uniform, dynamic loops.
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
87 //LOOPCASE_MULTI_DECLARATION, // for (int i,j,k; ...) ... -- illegal?
92 static const char* getLoopCaseName (LoopCase loopCase)
94 static const char* s_names[] =
97 "infinite_with_unconditional_break_first",
98 "infinite_with_unconditional_break_last",
99 "infinite_with_conditional_break",
101 "compound_statement",
102 "sequence_statement",
105 "select_iteration_count",
106 "conditional_continue",
107 "unconditional_continue",
111 "unconditional_break",
114 "mixed_break_continue",
120 "nested_tricky_dataflow_1",
121 "nested_tricky_dataflow_2"
122 //"multi_declaration",
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];
130 // Complex loop cases.
134 LOOPBODY_READ_UNIFORM = 0,
135 LOOPBODY_READ_UNIFORM_ARRAY,
148 static const char* getLoopTypeName (LoopType loopType)
150 static const char* s_names[] =
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];
164 LOOPCOUNT_CONSTANT = 0,
171 static const char* getLoopCountTypeName (LoopCountType countType)
173 static const char* s_names[] =
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];
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); }
190 static ShaderEvalFunc getLoopEvalFunc (int numIters)
192 switch (numIters % 4)
194 case 0: return evalLoop0Iters;
195 case 1: return evalLoop1Iters;
196 case 2: return evalLoop2Iters;
197 case 3: return evalLoop3Iters;
200 DE_FATAL("Invalid loop iteration count.");
206 class ShaderLoopCase : public ShaderRenderCase
209 ShaderLoopCase (Context& context, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, const char* vertShaderSource, const char* fragShaderSource);
210 virtual ~ShaderLoopCase (void);
213 ShaderLoopCase (const ShaderLoopCase&); // not allowed!
214 ShaderLoopCase& operator= (const ShaderLoopCase&); // not allowed!
216 virtual void setup (int programID);
217 virtual void setupUniforms (int programID, const Vec4& constCoords);
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)
223 m_vertShaderSource = vertShaderSource;
224 m_fragShaderSource = fragShaderSource;
227 ShaderLoopCase::~ShaderLoopCase (void)
231 void ShaderLoopCase::setup (int programID)
236 void ShaderLoopCase::setupUniforms (int programID, const Vec4& constCoords)
239 DE_UNREF(constCoords);
242 // Test case creation.
244 static ShaderLoopCase* createGenericLoopCase (Context& context, const char* caseName, const char* description, bool isVertexCase, LoopType loopType, LoopCountType loopCountType, Precision loopCountPrecision, DataType loopCountDataType)
246 std::ostringstream vtx;
247 std::ostringstream frag;
248 std::ostringstream& op = isVertexCase ? vtx : frag;
250 vtx << "#version 300 es\n";
251 frag << "#version 300 es\n";
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";
257 if (loopCountType == LOOPCOUNT_DYNAMIC)
258 vtx << "in mediump float a_one;\n";
262 vtx << "out mediump vec3 v_color;\n";
263 frag << "in mediump vec3 v_color;\n";
267 vtx << "out mediump vec4 v_coords;\n";
268 frag << "in mediump vec4 v_coords;\n";
270 if (loopCountType == LOOPCOUNT_DYNAMIC)
272 vtx << "out mediump float v_one;\n";
273 frag << "in mediump float v_one;\n";
277 // \todo [petri] Pass numLoopIters from outside?
278 int numLoopIters = 3;
279 bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
283 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
284 op << "uniform ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
288 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
289 op << "uniform ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
291 if (numLoopIters != 1)
292 op << "uniform ${COUNTER_PRECISION} float uf_one;\n";
296 vtx << "void main()\n";
298 vtx << " gl_Position = a_position;\n";
301 frag << "void main()\n";
305 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
307 frag << " ${PRECISION} vec4 coords = v_coords;\n";
309 if (loopCountType == LOOPCOUNT_DYNAMIC)
314 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
316 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
321 vtx << " ${COUNTER_PRECISION} float one = a_one;\n";
323 frag << " ${COUNTER_PRECISION} float one = v_one;\n";
328 op << " ${PRECISION} vec4 res = coords;\n";
330 // Loop iteration count.
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";
346 if (loopCountType == LOOPCOUNT_CONSTANT)
348 else if (loopCountType == LOOPCOUNT_UNIFORM)
349 iterMaxStr = "uf_one";
350 else if (loopCountType == LOOPCOUNT_DYNAMIC)
351 iterMaxStr = "uf_one*one";
357 string initValue = isIntCounter ? "0" : "0.05";
358 string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
359 string loopCmpStr = ("ndx < " + iterMaxStr);
362 incrementStr = "ndx++";
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";
378 loopBody = " res = res.yzwx;\n";
380 if (loopType == LOOPTYPE_FOR)
382 op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
387 else if (loopType == LOOPTYPE_WHILE)
389 op << "\t" << loopCountDeclStr + ";\n";
390 op << " while (" + loopCmpStr + ")\n";
393 op << "\t\t" + incrementStr + ";\n";
396 else if (loopType == LOOPTYPE_DO_WHILE)
398 op << "\t" << loopCountDeclStr + ";\n";
402 op << "\t\t" + incrementStr + ";\n";
403 op << " } while (" + loopCmpStr + ");\n";
410 vtx << " v_color = res.rgb;\n";
411 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
415 vtx << " v_coords = a_coords;\n";
416 frag << " o_color = vec4(res.rgb, 1.0);\n";
418 if (loopCountType == LOOPCOUNT_DYNAMIC)
419 vtx << " v_one = a_one;\n";
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)));
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);
437 ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
438 return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
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)
444 std::ostringstream vtx;
445 std::ostringstream frag;
446 std::ostringstream& op = isVertexCase ? vtx : frag;
448 vtx << "#version 300 es\n";
449 frag << "#version 300 es\n";
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";
455 if (loopCountType == LOOPCOUNT_DYNAMIC)
456 vtx << "in mediump float a_one;\n";
458 // Attribute and varyings.
461 vtx << "out mediump vec3 v_color;\n";
462 frag << "in mediump vec3 v_color;\n";
466 vtx << "out mediump vec4 v_coords;\n";
467 frag << "in mediump vec4 v_coords;\n";
469 if (loopCountType == LOOPCOUNT_DYNAMIC)
471 vtx << "out mediump float v_one;\n";
472 frag << "in mediump float v_one;\n";
476 if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT)
477 op << "uniform bool ub_true;\n";
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";
483 int iterCount = 3; // value to use in loop
484 int numIters = 3; // actual number of iterations
487 vtx << "void main()\n";
489 vtx << " gl_Position = a_position;\n";
492 frag << "void main()\n";
495 if (loopCountType == LOOPCOUNT_DYNAMIC)
498 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
500 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
504 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
506 frag << " ${PRECISION} vec4 coords = v_coords;\n";
509 op << " ${PRECISION} vec4 res = coords;\n";
511 // Handle all loop types.
512 string counterPrecisionStr = "mediump";
515 string doWhileLoopPreStr;
516 string doWhileLoopPostStr;
518 if (loopType == LOOPTYPE_FOR)
522 case LOOPCASE_EMPTY_BODY:
524 op << " ${FOR_LOOP} {}\n";
527 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
529 op << " for (;;) { break; res = res.yzwx; }\n";
532 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
534 op << " for (;;) { res = res.yzwx; break; }\n";
537 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
539 op << " ${COUNTER_PRECISION} int i = 0;\n";
540 op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
543 case LOOPCASE_SINGLE_STATEMENT:
544 op << " ${FOR_LOOP} res = res.yzwx;\n";
547 case LOOPCASE_COMPOUND_STATEMENT:
549 numIters = 2 * iterCount;
550 op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
553 case LOOPCASE_SEQUENCE_STATEMENT:
555 numIters = 2 * iterCount;
556 op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
559 case LOOPCASE_NO_ITERATIONS:
562 op << " ${FOR_LOOP} res = res.yzwx;\n";
565 case LOOPCASE_SINGLE_ITERATION:
568 op << " ${FOR_LOOP} res = res.yzwx;\n";
571 case LOOPCASE_SELECT_ITERATION_COUNT:
572 op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
575 case LOOPCASE_CONDITIONAL_CONTINUE:
576 numIters = iterCount - 1;
577 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
580 case LOOPCASE_UNCONDITIONAL_CONTINUE:
581 op << " ${FOR_LOOP} { res = res.yzwx; continue; }\n";
584 case LOOPCASE_ONLY_CONTINUE:
586 op << " ${FOR_LOOP} { continue; }\n";
589 case LOOPCASE_DOUBLE_CONTINUE:
590 numIters = iterCount - 1;
591 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
594 case LOOPCASE_CONDITIONAL_BREAK:
596 op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
599 case LOOPCASE_UNCONDITIONAL_BREAK:
601 op << " ${FOR_LOOP} { res = res.yzwx; break; }\n";
604 case LOOPCASE_PRE_INCREMENT:
605 op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
608 case LOOPCASE_POST_INCREMENT:
609 op << " ${FOR_LOOP} { res = res.yzwx; }\n";
612 case LOOPCASE_MIXED_BREAK_CONTINUE:
615 op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
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";
622 case LOOPCASE_101_ITERATIONS:
623 numIters = iterCount = 101;
624 op << " ${FOR_LOOP} res = res.yzwx;\n";
627 case LOOPCASE_SEQUENCE:
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";
635 case LOOPCASE_NESTED:
636 numIters = 2 * iterCount;
637 op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
639 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
640 op << " res = res.yzwx;\n";
644 case LOOPCASE_NESTED_SEQUENCE:
645 numIters = 3 * iterCount;
646 op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\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";
655 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
657 op << " ${FOR_LOOP}\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";
665 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
666 numIters = iterCount;
667 op << " ${FOR_LOOP}\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";
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++)";
689 else if (loopType == LOOPTYPE_WHILE)
693 case LOOPCASE_EMPTY_BODY:
695 op << " ${WHILE_LOOP} {}\n";
698 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
700 op << " while (true) { break; res = res.yzwx; }\n";
703 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
705 op << " while (true) { res = res.yzwx; break; }\n";
708 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
710 op << " ${COUNTER_PRECISION} int i = 0;\n";
711 op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
714 case LOOPCASE_SINGLE_STATEMENT:
715 op << " ${WHILE_LOOP} res = res.yzwx;\n";
718 case LOOPCASE_COMPOUND_STATEMENT:
720 numIters = 2 * iterCount;
721 op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
724 case LOOPCASE_SEQUENCE_STATEMENT:
726 numIters = 2 * iterCount;
727 op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
730 case LOOPCASE_NO_ITERATIONS:
733 op << " ${WHILE_LOOP} res = res.yzwx;\n";
736 case LOOPCASE_SINGLE_ITERATION:
739 op << " ${WHILE_LOOP} res = res.yzwx;\n";
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";
747 case LOOPCASE_CONDITIONAL_CONTINUE:
748 numIters = iterCount - 1;
749 op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
752 case LOOPCASE_UNCONDITIONAL_CONTINUE:
753 op << " ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
756 case LOOPCASE_ONLY_CONTINUE:
758 op << " ${WHILE_LOOP} { continue; }\n";
761 case LOOPCASE_DOUBLE_CONTINUE:
762 numIters = iterCount - 1;
763 op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
766 case LOOPCASE_CONDITIONAL_BREAK:
768 op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
771 case LOOPCASE_UNCONDITIONAL_BREAK:
773 op << " ${WHILE_LOOP} { res = res.yzwx; break; }\n";
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";
782 case LOOPCASE_POST_INCREMENT:
783 op << " ${COUNTER_PRECISION} int i = 0;\n";
784 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
787 case LOOPCASE_MIXED_BREAK_CONTINUE:
790 op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
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";
798 case LOOPCASE_101_ITERATIONS:
799 numIters = iterCount = 101;
800 op << " ${WHILE_LOOP} res = res.yzwx;\n";
803 case LOOPCASE_SEQUENCE:
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
811 case LOOPCASE_NESTED:
812 numIters = 2 * iterCount;
813 op << " ${COUNTER_PRECISION} int i = 0;\n";
814 op << " while (i++ < ${TWO})\n";
816 op << " ${COUNTER_PRECISION} int j = 0;\n";
817 op << " while (j++ < ${ITER_COUNT})\n";
818 op << " res = res.yzwx;\n";
822 case LOOPCASE_NESTED_SEQUENCE:
823 numIters = 2 * iterCount;
824 op << " ${COUNTER_PRECISION} int i = 0;\n";
825 op << " while (i++ < ${ITER_COUNT})\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";
835 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
837 op << " ${WHILE_LOOP}\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";
846 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
847 numIters = iterCount;
848 op << " ${WHILE_LOOP}\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";
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) + ")";
873 DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
877 case LOOPCASE_EMPTY_BODY:
879 op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
882 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
884 op << " do { break; res = res.yzwx; } while (true);\n";
887 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
889 op << " do { res = res.yzwx; break; } while (true);\n";
892 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
894 op << " ${COUNTER_PRECISION} int i = 0;\n";
895 op << " do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
898 case LOOPCASE_SINGLE_STATEMENT:
899 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
902 case LOOPCASE_COMPOUND_STATEMENT:
904 numIters = 2 * iterCount;
905 op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
908 case LOOPCASE_SEQUENCE_STATEMENT:
910 numIters = 2 * iterCount;
911 op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
914 case LOOPCASE_NO_ITERATIONS:
918 case LOOPCASE_SINGLE_ITERATION:
921 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
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";
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";
934 case LOOPCASE_UNCONDITIONAL_CONTINUE:
935 op << " ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
938 case LOOPCASE_ONLY_CONTINUE:
940 op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
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";
948 case LOOPCASE_CONDITIONAL_BREAK:
950 op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
953 case LOOPCASE_UNCONDITIONAL_BREAK:
955 op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
958 case LOOPCASE_PRE_INCREMENT:
959 op << " ${COUNTER_PRECISION} int i = 0;\n";
960 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
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";
969 case LOOPCASE_MIXED_BREAK_CONTINUE:
972 op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } ${DO_WHILE_POST}\n";
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";
980 case LOOPCASE_101_ITERATIONS:
981 numIters = iterCount = 101;
982 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
985 case LOOPCASE_SEQUENCE:
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";
993 case LOOPCASE_NESTED:
994 numIters = 2 * iterCount;
995 op << " ${COUNTER_PRECISION} int i = 0;\n";
998 op << " ${COUNTER_PRECISION} int j = 0;\n";
1000 op << " res = res.yzwx;\n";
1001 op << " while (++j < ${ITER_COUNT});\n";
1002 op << " } while (++i < ${TWO});\n";
1005 case LOOPCASE_NESTED_SEQUENCE:
1006 numIters = 3 * iterCount;
1007 op << " ${COUNTER_PRECISION} int i = 0;\n";
1010 op << " ${COUNTER_PRECISION} int j = 0;\n";
1012 op << " res = res.yzwx;\n";
1013 op << " while (++j < ${TWO});\n";
1015 op << " res = res.yzwx;\n";
1016 op << " while (++j < ${THREE});\n";
1017 op << " } while (++i < ${ITER_COUNT});\n";
1020 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1022 op << " ${DO_WHILE_PRE}\n";
1024 op << " res = coords; // ignore outer loop effect \n";
1025 op << " ${COUNTER_PRECISION} int j = 0;\n";
1027 op << " res = res.yzwx;\n";
1028 op << " while (++j < ${TWO});\n";
1029 op << " } ${DO_WHILE_POST}\n";
1032 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1033 numIters = iterCount;
1034 op << " ${DO_WHILE_PRE}\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";
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";
1062 vtx << " v_color = res.rgb;\n";
1063 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
1067 vtx << " v_coords = a_coords;\n";
1068 frag << " o_color = vec4(res.rgb, 1.0);\n";
1070 if (loopCountType == LOOPCOUNT_DYNAMIC)
1071 vtx << " v_one = a_one;\n";
1081 string iterCountStr;
1083 if (loopCountType == LOOPCOUNT_CONSTANT)
1088 iterCountStr = de::toString(iterCount);
1090 else if (loopCountType == LOOPCOUNT_UNIFORM)
1094 threeStr = "ui_three";
1095 iterCountStr = getIntUniformName(iterCount);
1097 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1099 oneStr = "one*ui_one";
1100 twoStr = "one*ui_two";
1101 threeStr = "one*ui_three";
1102 iterCountStr = string("one*") + getIntUniformName(iterCount);
1104 else DE_ASSERT(false);
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));
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);
1125 ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1126 return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
1131 ShaderLoopTests::ShaderLoopTests(Context& context)
1132 : TestCaseGroup(context, "loops", "Loop Tests")
1136 ShaderLoopTests::~ShaderLoopTests (void)
1140 void ShaderLoopTests::init (void)
1144 static const ShaderType s_shaderTypes[] =
1150 static const DataType s_countDataType[] =
1156 for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1158 const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1160 for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1162 const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
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());
1171 for (int precision = 0; precision < PRECISION_LAST; precision++)
1173 const char* precisionName = getPrecisionName((Precision)precision);
1175 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1177 DataType loopDataType = s_countDataType[dataTypeNdx];
1178 const char* dataTypeName = getDataTypeName(loopDataType);
1180 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1182 ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1183 const char* shaderTypeName = getShaderTypeName(shaderType);
1184 bool isVertexCase = (shaderType == SHADERTYPE_VERTEX);
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));
1195 for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1197 const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1199 // no-iterations not possible with do-while.
1200 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1203 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1205 ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1206 const char* shaderTypeName = getShaderTypeName(shaderType);
1207 bool isVertexCase = (shaderType == SHADERTYPE_VERTEX);
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));
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]);