1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 * \brief Shader loop tests.
23 */ /*-------------------------------------------------------------------*/
25 #include "glcShaderLoopTests.hpp"
26 #include "glcShaderRenderCase.hpp"
27 #include "gluShaderUtil.hpp"
28 #include "tcuStringTemplate.hpp"
32 #include "deStringUtil.hpp"
43 // Repeated with for, while, do-while. Examples given as 'for' loops.
44 // Repeated for const, uniform, dynamic loops.
47 LOOPCASE_EMPTY_BODY = 0, // for (...) { }
48 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST, // for (...) { break; <body>; }
49 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST, // for (...) { <body>; break; }
50 LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK, // for (...) { <body>; if (cond) break; }
51 LOOPCASE_SINGLE_STATEMENT, // for (...) statement;
52 LOOPCASE_COMPOUND_STATEMENT, // for (...) { statement; statement; }
53 LOOPCASE_SEQUENCE_STATEMENT, // for (...) statement, statement;
54 LOOPCASE_NO_ITERATIONS, // for (i=0; i<0; i++) ...
55 LOOPCASE_SINGLE_ITERATION, // for (i=0; i<1; i++) ...
56 LOOPCASE_SELECT_ITERATION_COUNT, // for (i=0; i<a?b:c; i++) ...
57 LOOPCASE_CONDITIONAL_CONTINUE, // for (...) { if (cond) continue; }
58 LOOPCASE_UNCONDITIONAL_CONTINUE, // for (...) { <body>; continue; }
59 LOOPCASE_ONLY_CONTINUE, // for (...) { continue; }
60 LOOPCASE_DOUBLE_CONTINUE, // for (...) { if (cond) continue; <body>; continue; }
61 LOOPCASE_CONDITIONAL_BREAK, // for (...) { if (cond) break; }
62 LOOPCASE_UNCONDITIONAL_BREAK, // for (...) { <body>; break; }
63 LOOPCASE_PRE_INCREMENT, // for (...; ++i) { <body>; }
64 LOOPCASE_POST_INCREMENT, // for (...; i++) { <body>; }
65 LOOPCASE_MIXED_BREAK_CONTINUE,
66 LOOPCASE_VECTOR_COUNTER, // for (ivec3 ndx = ...; ndx.x < ndx.y; ndx.x += ndx.z) { ... }
67 LOOPCASE_101_ITERATIONS, // loop for 101 iterations
68 LOOPCASE_SEQUENCE, // two loops in sequence
69 LOOPCASE_NESTED, // two nested loops
70 LOOPCASE_NESTED_SEQUENCE, // two loops in sequence nested inside a third
71 LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow
72 LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow
74 //LOOPCASE_MULTI_DECLARATION, // for (int i,j,k; ...) ... -- illegal?
79 static const char* getLoopCaseName(LoopCase loopCase)
81 static const char* s_names[] = {
82 "empty_body", "infinite_with_unconditional_break_first", "infinite_with_unconditional_break_last",
83 "infinite_with_conditional_break", "single_statement", "compound_statement", "sequence_statement",
84 "no_iterations", "single_iteration", "select_iteration_count", "conditional_continue", "unconditional_continue",
85 "only_continue", "double_continue", "conditional_break", "unconditional_break", "pre_increment",
86 "post_increment", "mixed_break_continue", "vector_counter", "101_iterations", "sequence", "nested",
87 "nested_sequence", "nested_tricky_dataflow_1", "nested_tricky_dataflow_2"
88 //"multi_declaration",
91 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
92 DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
93 return s_names[(int)loopCase];
96 // Complex loop cases.
100 LOOPBODY_READ_UNIFORM = 0,
101 LOOPBODY_READ_UNIFORM_ARRAY,
114 static const char* getLoopTypeName(LoopType loopType)
116 static const char* s_names[] = { "for", "while", "do_while" };
118 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
119 DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
120 return s_names[(int)loopType];
125 LOOPCOUNT_CONSTANT = 0,
132 static const char* getLoopCountTypeName(LoopCountType countType)
134 static const char* s_names[] = { "constant", "uniform", "dynamic" };
136 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
137 DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
138 return s_names[(int)countType];
141 static void evalLoop0Iters(ShaderEvalContext& c)
143 c.color.xyz() = c.coords.swizzle(0, 1, 2);
145 static void evalLoop1Iters(ShaderEvalContext& c)
147 c.color.xyz() = c.coords.swizzle(1, 2, 3);
149 static void evalLoop2Iters(ShaderEvalContext& c)
151 c.color.xyz() = c.coords.swizzle(2, 3, 0);
153 static void evalLoop3Iters(ShaderEvalContext& c)
155 c.color.xyz() = c.coords.swizzle(3, 0, 1);
158 static ShaderEvalFunc getLoopEvalFunc(int numIters)
160 switch (numIters % 4)
163 return evalLoop0Iters;
165 return evalLoop1Iters;
167 return evalLoop2Iters;
169 return evalLoop3Iters;
172 DE_ASSERT(DE_FALSE && "Invalid loop iteration count.");
178 class ShaderLoopCase : public ShaderRenderCase
181 ShaderLoopCase(Context& context, const char* name, const char* description, bool isVertexCase,
182 ShaderEvalFunc evalFunc, const char* vertShaderSource, const char* fragShaderSource);
183 virtual ~ShaderLoopCase(void);
186 ShaderLoopCase(const ShaderLoopCase&); // not allowed!
187 ShaderLoopCase& operator=(const ShaderLoopCase&); // not allowed!
189 virtual void setup(deUint32 programID);
190 virtual void setupUniforms(deUint32 programID, const Vec4& constCoords);
193 ShaderLoopCase::ShaderLoopCase(Context& context, const char* name, const char* description, bool isVertexCase,
194 ShaderEvalFunc evalFunc, const char* vertShaderSource, const char* fragShaderSource)
195 : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
196 description, isVertexCase, evalFunc)
198 m_vertShaderSource = vertShaderSource;
199 m_fragShaderSource = fragShaderSource;
202 ShaderLoopCase::~ShaderLoopCase(void)
206 void ShaderLoopCase::setup(deUint32 programID)
211 void ShaderLoopCase::setupUniforms(deUint32 programID, const Vec4& constCoords)
214 DE_UNREF(constCoords);
217 // Test case creation.
219 static ShaderLoopCase* createGenericLoopCase(Context& context, glu::GLSLVersion glslVersion, const char* caseName,
220 const char* description, bool isVertexCase, LoopType loopType,
221 LoopCountType loopCountType, Precision loopCountPrecision,
222 DataType loopCountDataType)
224 std::ostringstream vtx;
225 std::ostringstream frag;
226 std::ostringstream& op = isVertexCase ? vtx : frag;
228 vtx << getGLSLVersionDeclaration(glslVersion) << "\n";
229 frag << getGLSLVersionDeclaration(glslVersion) << "\n";
231 vtx << "in highp vec4 a_position;\n";
232 vtx << "in highp vec4 a_coords;\n";
233 frag << "layout(location = 0) out mediump vec4 o_color;\n";
235 if (loopCountType == LOOPCOUNT_DYNAMIC)
236 vtx << "in mediump float a_one;\n";
240 vtx << "out mediump vec3 v_color;\n";
241 frag << "in mediump vec3 v_color;\n";
245 vtx << "out mediump vec4 v_coords;\n";
246 frag << "in mediump vec4 v_coords;\n";
248 if (loopCountType == LOOPCOUNT_DYNAMIC)
250 vtx << "out mediump float v_one;\n";
251 frag << "in mediump float v_one;\n";
255 // \todo [petri] Pass numLoopIters from outside?
256 int numLoopIters = 3;
257 bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
261 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
262 op << "uniform ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
266 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
267 op << "uniform ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
269 if (numLoopIters != 1)
270 op << "uniform ${COUNTER_PRECISION} float uf_one;\n";
274 vtx << "void main()\n";
276 vtx << " gl_Position = a_position;\n";
279 frag << "void main()\n";
283 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
285 frag << " ${PRECISION} vec4 coords = v_coords;\n";
287 if (loopCountType == LOOPCOUNT_DYNAMIC)
292 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
294 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
299 vtx << " ${COUNTER_PRECISION} float one = a_one;\n";
301 frag << " ${COUNTER_PRECISION} float one = v_one;\n";
306 op << " ${PRECISION} vec4 res = coords;\n";
308 // Loop iteration count.
313 if (loopCountType == LOOPCOUNT_CONSTANT)
314 iterMaxStr = de::toString(numLoopIters);
315 else if (loopCountType == LOOPCOUNT_UNIFORM)
316 iterMaxStr = getIntUniformName(numLoopIters);
317 else if (loopCountType == LOOPCOUNT_DYNAMIC)
318 iterMaxStr = string(getIntUniformName(numLoopIters)) + "*one";
324 if (loopCountType == LOOPCOUNT_CONSTANT)
326 else if (loopCountType == LOOPCOUNT_UNIFORM)
327 iterMaxStr = "uf_one";
328 else if (loopCountType == LOOPCOUNT_DYNAMIC)
329 iterMaxStr = "uf_one*one";
335 string initValue = isIntCounter ? "0" : "0.05";
336 string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
337 string loopCmpStr = ("ndx < " + iterMaxStr);
340 incrementStr = "ndx++";
343 if (loopCountType == LOOPCOUNT_CONSTANT)
344 incrementStr = string("ndx += ") + de::toString(1.0f / static_cast<float>(numLoopIters));
345 else if (loopCountType == LOOPCOUNT_UNIFORM)
346 incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters);
347 else if (loopCountType == LOOPCOUNT_DYNAMIC)
348 incrementStr = string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
359 loopBody = " res = res.yzwx;\n";
361 if (loopType == LOOPTYPE_FOR)
363 op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
368 else if (loopType == LOOPTYPE_WHILE)
370 op << "\t" << loopCountDeclStr + ";\n";
371 op << " while (" + loopCmpStr + ")\n";
374 op << "\t\t" + incrementStr + ";\n";
377 else if (loopType == LOOPTYPE_DO_WHILE)
379 op << "\t" << loopCountDeclStr + ";\n";
383 op << "\t\t" + incrementStr + ";\n";
384 op << " } while (" + loopCmpStr + ");\n";
391 vtx << " v_color = res.rgb;\n";
392 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
396 vtx << " v_coords = a_coords;\n";
397 frag << " o_color = vec4(res.rgb, 1.0);\n";
399 if (loopCountType == LOOPCOUNT_DYNAMIC)
400 vtx << " v_one = a_one;\n";
406 // Fill in shader templates.
407 map<string, string> params;
408 params.insert(pair<string, string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
409 params.insert(pair<string, string>("PRECISION", "mediump"));
410 params.insert(pair<string, string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
412 StringTemplate vertTemplate(vtx.str().c_str());
413 StringTemplate fragTemplate(frag.str().c_str());
414 string vertexShaderSource = vertTemplate.specialize(params);
415 string fragmentShaderSource = fragTemplate.specialize(params);
418 ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
419 return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(),
420 fragmentShaderSource.c_str());
423 // \todo [petri] Generalize to float as well?
424 static ShaderLoopCase* createSpecialLoopCase(Context& context, glu::GLSLVersion glslVersion, const char* caseName,
425 const char* description, bool isVertexCase, LoopCase loopCase,
426 LoopType loopType, LoopCountType loopCountType)
428 std::ostringstream vtx;
429 std::ostringstream frag;
430 std::ostringstream& op = isVertexCase ? vtx : frag;
432 vtx << getGLSLVersionDeclaration(glslVersion) << "\n";
433 frag << getGLSLVersionDeclaration(glslVersion) << "\n";
435 vtx << "in highp vec4 a_position;\n";
436 vtx << "in highp vec4 a_coords;\n";
437 frag << "layout(location = 0) out mediump vec4 o_color;\n";
439 if (loopCountType == LOOPCOUNT_DYNAMIC)
440 vtx << "in mediump float a_one;\n";
442 // Attribute and varyings.
445 vtx << "out mediump vec3 v_color;\n";
446 frag << "in mediump vec3 v_color;\n";
450 vtx << "out mediump vec4 v_coords;\n";
451 frag << "in mediump vec4 v_coords;\n";
453 if (loopCountType == LOOPCOUNT_DYNAMIC)
455 vtx << "out mediump float v_one;\n";
456 frag << "in mediump float v_one;\n";
460 if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT)
461 op << "uniform bool ub_true;\n";
463 op << "uniform ${COUNTER_PRECISION} int ui_zero, ui_one, ui_two, ui_three, ui_four, ui_five, ui_six;\n";
464 if (loopCase == LOOPCASE_101_ITERATIONS)
465 op << "uniform ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
467 int iterCount = 3; // value to use in loop
468 int numIters = 3; // actual number of iterations
471 vtx << "void main()\n";
473 vtx << " gl_Position = a_position;\n";
476 frag << "void main()\n";
479 if (loopCountType == LOOPCOUNT_DYNAMIC)
482 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
484 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
488 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
490 frag << " ${PRECISION} vec4 coords = v_coords;\n";
493 op << " ${PRECISION} vec4 res = coords;\n";
495 // Handle all loop types.
496 string counterPrecisionStr = "mediump";
499 string doWhileLoopPreStr;
500 string doWhileLoopPostStr;
502 if (loopType == LOOPTYPE_FOR)
506 case LOOPCASE_EMPTY_BODY:
508 op << " ${FOR_LOOP} {}\n";
511 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
513 op << " for (;;) { break; res = res.yzwx; }\n";
516 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
518 op << " for (;;) { res = res.yzwx; break; }\n";
521 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
523 op << " ${COUNTER_PRECISION} int i = 0;\n";
524 op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
527 case LOOPCASE_SINGLE_STATEMENT:
528 op << " ${FOR_LOOP} res = res.yzwx;\n";
531 case LOOPCASE_COMPOUND_STATEMENT:
533 numIters = 2 * iterCount;
534 op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
537 case LOOPCASE_SEQUENCE_STATEMENT:
539 numIters = 2 * iterCount;
540 op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
543 case LOOPCASE_NO_ITERATIONS:
546 op << " ${FOR_LOOP} res = res.yzwx;\n";
549 case LOOPCASE_SINGLE_ITERATION:
552 op << " ${FOR_LOOP} res = res.yzwx;\n";
555 case LOOPCASE_SELECT_ITERATION_COUNT:
556 op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
559 case LOOPCASE_CONDITIONAL_CONTINUE:
560 numIters = iterCount - 1;
561 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
564 case LOOPCASE_UNCONDITIONAL_CONTINUE:
565 op << " ${FOR_LOOP} { res = res.yzwx; continue; }\n";
568 case LOOPCASE_ONLY_CONTINUE:
570 op << " ${FOR_LOOP} { continue; }\n";
573 case LOOPCASE_DOUBLE_CONTINUE:
574 numIters = iterCount - 1;
575 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
578 case LOOPCASE_CONDITIONAL_BREAK:
580 op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
583 case LOOPCASE_UNCONDITIONAL_BREAK:
585 op << " ${FOR_LOOP} { res = res.yzwx; break; }\n";
588 case LOOPCASE_PRE_INCREMENT:
589 op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
592 case LOOPCASE_POST_INCREMENT:
593 op << " ${FOR_LOOP} { res = res.yzwx; }\n";
596 case LOOPCASE_MIXED_BREAK_CONTINUE:
599 op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
602 case LOOPCASE_VECTOR_COUNTER:
603 op << " for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res = "
607 case LOOPCASE_101_ITERATIONS:
608 numIters = iterCount = 101;
609 op << " ${FOR_LOOP} res = res.yzwx;\n";
612 case LOOPCASE_SEQUENCE:
615 op << " ${COUNTER_PRECISION} int i;\n";
616 op << " for (i = 0; i < ${TWO}; i++) { res = res.yzwx; }\n";
617 op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\n";
620 case LOOPCASE_NESTED:
621 numIters = 2 * iterCount;
622 op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
624 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
625 op << " res = res.yzwx;\n";
629 case LOOPCASE_NESTED_SEQUENCE:
630 numIters = 3 * iterCount;
631 op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
633 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
634 op << " res = res.yzwx;\n";
635 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
636 op << " res = res.yzwx;\n";
640 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
642 op << " ${FOR_LOOP}\n";
644 op << " res = coords; // ignore outer loop effect \n";
645 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
646 op << " res = res.yzwx;\n";
650 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
651 numIters = iterCount;
652 op << " ${FOR_LOOP}\n";
654 op << " res = coords.wxyz;\n";
655 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
656 op << " res = res.yzwx;\n";
657 op << " coords = res;\n";
665 if (loopCountType == LOOPCOUNT_CONSTANT)
667 string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
668 else if (loopCountType == LOOPCOUNT_UNIFORM)
670 string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
671 else if (loopCountType == LOOPCOUNT_DYNAMIC)
672 forLoopStr = string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) +
677 else if (loopType == LOOPTYPE_WHILE)
681 case LOOPCASE_EMPTY_BODY:
683 op << " ${WHILE_LOOP} {}\n";
686 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
688 op << " while (true) { break; res = res.yzwx; }\n";
691 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
693 op << " while (true) { res = res.yzwx; break; }\n";
696 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
698 op << " ${COUNTER_PRECISION} int i = 0;\n";
699 op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
702 case LOOPCASE_SINGLE_STATEMENT:
703 op << " ${WHILE_LOOP} res = res.yzwx;\n";
706 case LOOPCASE_COMPOUND_STATEMENT:
708 numIters = 2 * iterCount;
709 op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
712 case LOOPCASE_SEQUENCE_STATEMENT:
714 numIters = 2 * iterCount;
715 op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
718 case LOOPCASE_NO_ITERATIONS:
721 op << " ${WHILE_LOOP} res = res.yzwx;\n";
724 case LOOPCASE_SINGLE_ITERATION:
727 op << " ${WHILE_LOOP} res = res.yzwx;\n";
730 case LOOPCASE_SELECT_ITERATION_COUNT:
731 op << " ${COUNTER_PRECISION} int i = 0;\n";
732 op << " while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx; i++; }\n";
735 case LOOPCASE_CONDITIONAL_CONTINUE:
736 numIters = iterCount - 1;
737 op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
740 case LOOPCASE_UNCONDITIONAL_CONTINUE:
741 op << " ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
744 case LOOPCASE_ONLY_CONTINUE:
746 op << " ${WHILE_LOOP} { continue; }\n";
749 case LOOPCASE_DOUBLE_CONTINUE:
750 numIters = iterCount - 1;
751 op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
754 case LOOPCASE_CONDITIONAL_BREAK:
756 op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
759 case LOOPCASE_UNCONDITIONAL_BREAK:
761 op << " ${WHILE_LOOP} { res = res.yzwx; break; }\n";
764 case LOOPCASE_PRE_INCREMENT:
765 numIters = iterCount - 1;
766 op << " ${COUNTER_PRECISION} int i = 0;\n";
767 op << " while (++i < ${ITER_COUNT}) { res = res.yzwx; }\n";
770 case LOOPCASE_POST_INCREMENT:
771 op << " ${COUNTER_PRECISION} int i = 0;\n";
772 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
775 case LOOPCASE_MIXED_BREAK_CONTINUE:
778 op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
781 case LOOPCASE_VECTOR_COUNTER:
782 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
783 op << " while (i.x < i.z) { res = res.yzwx; i.x += i.y; }\n";
786 case LOOPCASE_101_ITERATIONS:
787 numIters = iterCount = 101;
788 op << " ${WHILE_LOOP} res = res.yzwx;\n";
791 case LOOPCASE_SEQUENCE:
793 numIters = iterCount - 1;
794 op << " ${COUNTER_PRECISION} int i = 0;\n";
795 op << " while (i++ < ${TWO}) { res = res.yzwx; }\n";
796 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n"; // \note skips one iteration
799 case LOOPCASE_NESTED:
800 numIters = 2 * iterCount;
801 op << " ${COUNTER_PRECISION} int i = 0;\n";
802 op << " while (i++ < ${TWO})\n";
804 op << " ${COUNTER_PRECISION} int j = 0;\n";
805 op << " while (j++ < ${ITER_COUNT})\n";
806 op << " res = res.yzwx;\n";
810 case LOOPCASE_NESTED_SEQUENCE:
811 numIters = 2 * iterCount;
812 op << " ${COUNTER_PRECISION} int i = 0;\n";
813 op << " while (i++ < ${ITER_COUNT})\n";
815 op << " ${COUNTER_PRECISION} int j = 0;\n";
816 op << " while (j++ < ${ONE})\n";
817 op << " res = res.yzwx;\n";
818 op << " while (j++ < ${THREE})\n"; // \note skips one iteration
819 op << " res = res.yzwx;\n";
823 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
825 op << " ${WHILE_LOOP}\n";
827 op << " res = coords; // ignore outer loop effect \n";
828 op << " ${COUNTER_PRECISION} int j = 0;\n";
829 op << " while (j++ < ${TWO})\n";
830 op << " res = res.yzwx;\n";
834 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
835 numIters = iterCount;
836 op << " ${WHILE_LOOP}\n";
838 op << " res = coords.wxyz;\n";
839 op << " ${COUNTER_PRECISION} int j = 0;\n";
840 op << " while (j++ < ${TWO})\n";
841 op << " res = res.yzwx;\n";
842 op << " coords = res;\n";
850 if (loopCountType == LOOPCOUNT_CONSTANT)
852 string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + de::toString(iterCount) + ")";
853 else if (loopCountType == LOOPCOUNT_UNIFORM)
854 whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " +
855 getIntUniformName(iterCount) + ")";
856 else if (loopCountType == LOOPCOUNT_DYNAMIC)
857 whileLoopStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < one*" +
858 getIntUniformName(iterCount) + ")";
864 DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
868 case LOOPCASE_EMPTY_BODY:
870 op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
873 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
875 op << " do { break; res = res.yzwx; } while (true);\n";
878 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
880 op << " do { res = res.yzwx; break; } while (true);\n";
883 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
885 op << " ${COUNTER_PRECISION} int i = 0;\n";
886 op << " do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
889 case LOOPCASE_SINGLE_STATEMENT:
890 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
893 case LOOPCASE_COMPOUND_STATEMENT:
895 numIters = 2 * iterCount;
896 op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
899 case LOOPCASE_SEQUENCE_STATEMENT:
901 numIters = 2 * iterCount;
902 op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
905 case LOOPCASE_NO_ITERATIONS:
909 case LOOPCASE_SINGLE_ITERATION:
912 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
915 case LOOPCASE_SELECT_ITERATION_COUNT:
916 op << " ${COUNTER_PRECISION} int i = 0;\n";
917 op << " do { res = res.yzwx; } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
920 case LOOPCASE_CONDITIONAL_CONTINUE:
921 numIters = iterCount - 1;
922 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; } ${DO_WHILE_POST}\n";
925 case LOOPCASE_UNCONDITIONAL_CONTINUE:
926 op << " ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
929 case LOOPCASE_ONLY_CONTINUE:
931 op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
934 case LOOPCASE_DOUBLE_CONTINUE:
935 numIters = iterCount - 1;
936 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
939 case LOOPCASE_CONDITIONAL_BREAK:
941 op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
944 case LOOPCASE_UNCONDITIONAL_BREAK:
946 op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
949 case LOOPCASE_PRE_INCREMENT:
950 op << " ${COUNTER_PRECISION} int i = 0;\n";
951 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
954 case LOOPCASE_POST_INCREMENT:
955 numIters = iterCount + 1;
956 op << " ${COUNTER_PRECISION} int i = 0;\n";
957 op << " do { res = res.yzwx; } while (i++ < ${ITER_COUNT});\n";
960 case LOOPCASE_MIXED_BREAK_CONTINUE:
963 op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } "
964 "${DO_WHILE_POST}\n";
967 case LOOPCASE_VECTOR_COUNTER:
968 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
969 op << " do { res = res.yzwx; } while ((i.x += i.y) < i.z);\n";
972 case LOOPCASE_101_ITERATIONS:
973 numIters = iterCount = 101;
974 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
977 case LOOPCASE_SEQUENCE:
980 op << " ${COUNTER_PRECISION} int i = 0;\n";
981 op << " do { res = res.yzwx; } while (++i < ${TWO});\n";
982 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
985 case LOOPCASE_NESTED:
986 numIters = 2 * iterCount;
987 op << " ${COUNTER_PRECISION} int i = 0;\n";
990 op << " ${COUNTER_PRECISION} int j = 0;\n";
992 op << " res = res.yzwx;\n";
993 op << " while (++j < ${ITER_COUNT});\n";
994 op << " } while (++i < ${TWO});\n";
997 case LOOPCASE_NESTED_SEQUENCE:
998 numIters = 3 * iterCount;
999 op << " ${COUNTER_PRECISION} int i = 0;\n";
1002 op << " ${COUNTER_PRECISION} int j = 0;\n";
1004 op << " res = res.yzwx;\n";
1005 op << " while (++j < ${TWO});\n";
1007 op << " res = res.yzwx;\n";
1008 op << " while (++j < ${THREE});\n";
1009 op << " } while (++i < ${ITER_COUNT});\n";
1012 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1014 op << " ${DO_WHILE_PRE}\n";
1016 op << " res = coords; // ignore outer loop effect \n";
1017 op << " ${COUNTER_PRECISION} int j = 0;\n";
1019 op << " res = res.yzwx;\n";
1020 op << " while (++j < ${TWO});\n";
1021 op << " } ${DO_WHILE_POST}\n";
1024 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1025 numIters = iterCount;
1026 op << " ${DO_WHILE_PRE}\n";
1028 op << " res = coords.wxyz;\n";
1029 op << " ${COUNTER_PRECISION} int j = 0;\n";
1030 op << " while (j++ < ${TWO})\n";
1031 op << " res = res.yzwx;\n";
1032 op << " coords = res;\n";
1033 op << " } ${DO_WHILE_POST}\n";
1040 doWhileLoopPreStr = string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1041 if (loopCountType == LOOPCOUNT_CONSTANT)
1042 doWhileLoopPostStr = string(" while (++i < ") + de::toString(iterCount) + ");\n";
1043 else if (loopCountType == LOOPCOUNT_UNIFORM)
1044 doWhileLoopPostStr = string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1045 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1046 doWhileLoopPostStr = string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1054 vtx << " v_color = res.rgb;\n";
1055 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
1059 vtx << " v_coords = a_coords;\n";
1060 frag << " o_color = vec4(res.rgb, 1.0);\n";
1062 if (loopCountType == LOOPCOUNT_DYNAMIC)
1063 vtx << " v_one = a_one;\n";
1073 string iterCountStr;
1075 if (loopCountType == LOOPCOUNT_CONSTANT)
1080 iterCountStr = de::toString(iterCount);
1082 else if (loopCountType == LOOPCOUNT_UNIFORM)
1086 threeStr = "ui_three";
1087 iterCountStr = getIntUniformName(iterCount);
1089 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1091 oneStr = "one*ui_one";
1092 twoStr = "one*ui_two";
1093 threeStr = "one*ui_three";
1094 iterCountStr = string("one*") + getIntUniformName(iterCount);
1099 // Fill in shader templates.
1100 map<string, string> params;
1101 params.insert(pair<string, string>("PRECISION", "mediump"));
1102 params.insert(pair<string, string>("ITER_COUNT", iterCountStr));
1103 params.insert(pair<string, string>("COUNTER_PRECISION", counterPrecisionStr));
1104 params.insert(pair<string, string>("FOR_LOOP", forLoopStr));
1105 params.insert(pair<string, string>("WHILE_LOOP", whileLoopStr));
1106 params.insert(pair<string, string>("DO_WHILE_PRE", doWhileLoopPreStr));
1107 params.insert(pair<string, string>("DO_WHILE_POST", doWhileLoopPostStr));
1108 params.insert(pair<string, string>("ONE", oneStr));
1109 params.insert(pair<string, string>("TWO", twoStr));
1110 params.insert(pair<string, string>("THREE", threeStr));
1112 StringTemplate vertTemplate(vtx.str().c_str());
1113 StringTemplate fragTemplate(frag.str().c_str());
1114 string vertexShaderSource = vertTemplate.specialize(params);
1115 string fragmentShaderSource = fragTemplate.specialize(params);
1118 ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1119 return new ShaderLoopCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(),
1120 fragmentShaderSource.c_str());
1125 ShaderLoopTests::ShaderLoopTests(Context& context, glu::GLSLVersion glslVersion)
1126 : TestCaseGroup(context, "loops", "Loop Tests"), m_glslVersion(glslVersion)
1130 ShaderLoopTests::~ShaderLoopTests(void)
1134 void ShaderLoopTests::init(void)
1138 static const DataType s_countDataType[] = { TYPE_INT, TYPE_FLOAT };
1140 static const ShaderType s_shaderTypes[] = { SHADERTYPE_VERTEX, SHADERTYPE_FRAGMENT };
1142 for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1144 const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1146 for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1148 const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1150 string groupName = string(loopTypeName) + "_" + string(loopCountName) + "_iterations";
1151 string groupDesc = string("Loop tests with ") + loopCountName + " loop counter.";
1152 TestCaseGroup* group = new TestCaseGroup(m_context, groupName.c_str(), groupDesc.c_str());
1157 for (int precision = 0; precision < PRECISION_LAST; precision++)
1159 const char* precisionName = getPrecisionName((Precision)precision);
1161 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1163 DataType loopDataType = s_countDataType[dataTypeNdx];
1164 const char* dataTypeName = getDataTypeName(loopDataType);
1166 if (precision == PRECISION_LOWP && loopDataType == TYPE_FLOAT)
1169 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1171 ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1172 const char* shaderTypeName = getShaderTypeName((ShaderType)shaderType);
1173 bool isVertexCase = (shaderType == SHADERTYPE_VERTEX);
1175 string name = string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1176 string desc = string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " +
1177 loopCountName + " iteration count in " + shaderTypeName + " shader.";
1178 group->addChild(createGenericLoopCase(
1179 m_context, m_glslVersion, name.c_str(), desc.c_str(), isVertexCase, (LoopType)loopType,
1180 (LoopCountType)loopCountType, (Precision)precision, loopDataType));
1187 for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1189 const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1191 // no-iterations not possible with do-while.
1192 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1195 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1197 ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1198 const char* shaderTypeName = getShaderTypeName((ShaderType)shaderType);
1199 bool isVertexCase = (shaderType == SHADERTYPE_VERTEX);
1201 string name = string(loopCaseName) + "_" + shaderTypeName;
1202 string desc = string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " +
1203 shaderTypeName + " shader.";
1204 group->addChild(createSpecialLoopCase(m_context, m_glslVersion, name.c_str(), desc.c_str(),
1205 isVertexCase, (LoopCase)loopCase, (LoopType)loopType,
1206 (LoopCountType)loopCountType));