1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Shader loop tests.
24 *//*--------------------------------------------------------------------*/
26 #include "vktShaderRenderLoopTests.hpp"
28 #include "vktShaderRender.hpp"
29 #include "tcuStringTemplate.hpp"
30 #include "gluShaderUtil.hpp"
31 #include "deStringUtil.hpp"
42 static const char* getIntUniformName (int number)
46 case 0: return "ui_zero";
47 case 1: return "ui_one";
48 case 2: return "ui_two";
49 case 3: return "ui_three";
50 case 4: return "ui_four";
51 case 5: return "ui_five";
52 case 6: return "ui_six";
53 case 7: return "ui_seven";
54 case 8: return "ui_eight";
55 case 101: return "ui_oneHundredOne";
62 static BaseUniformType getIntUniformType(int number)
66 case 1: return UI_ONE;
67 case 2: return UI_TWO;
68 case 3: return UI_THREE;
69 case 4: return UI_FOUR;
70 case 5: return UI_FIVE;
71 case 6: return UI_SIX;
72 case 7: return UI_SEVEN;
73 case 8: return UI_EIGHT;
80 static const char* getFloatFractionUniformName (int number)
84 case 1: return "uf_one";
85 case 2: return "uf_half";
86 case 3: return "uf_third";
87 case 4: return "uf_fourth";
88 case 5: return "uf_fifth";
89 case 6: return "uf_sixth";
90 case 7: return "uf_seventh";
91 case 8: return "uf_eight";
98 static BaseUniformType getFloatFractionUniformType(int number)
102 case 1: return UF_ONE;
103 case 2: return UF_HALF;
104 case 3: return UF_THIRD;
105 case 4: return UF_FOURTH;
106 case 5: return UF_FIFTH;
107 case 6: return UF_SIXTH;
108 case 7: return UF_SEVENTH;
109 case 8: return UF_EIGHTH;
124 static const char* getLoopTypeName (LoopType loopType)
126 static const char* s_names[] =
133 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPTYPE_LAST);
134 DE_ASSERT(deInBounds32((int)loopType, 0, LOOPTYPE_LAST));
135 return s_names[(int)loopType];
140 LOOPCOUNT_CONSTANT = 0,
147 // Repeated with for, while, do-while. Examples given as 'for' loops.
148 // Repeated for const, uniform, dynamic loops.
151 LOOPCASE_EMPTY_BODY = 0, // for (...) { }
152 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST, // for (...) { break; <body>; }
153 LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST, // for (...) { <body>; break; }
154 LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK, // for (...) { <body>; if (cond) break; }
155 LOOPCASE_SINGLE_STATEMENT, // for (...) statement;
156 LOOPCASE_COMPOUND_STATEMENT, // for (...) { statement; statement; }
157 LOOPCASE_SEQUENCE_STATEMENT, // for (...) statement, statement;
158 LOOPCASE_NO_ITERATIONS, // for (i=0; i<0; i++) ...
159 LOOPCASE_SINGLE_ITERATION, // for (i=0; i<1; i++) ...
160 LOOPCASE_SELECT_ITERATION_COUNT, // for (i=0; i<a?b:c; i++) ...
161 LOOPCASE_CONDITIONAL_CONTINUE, // for (...) { if (cond) continue; }
162 LOOPCASE_UNCONDITIONAL_CONTINUE, // for (...) { <body>; continue; }
163 LOOPCASE_ONLY_CONTINUE, // for (...) { continue; }
164 LOOPCASE_DOUBLE_CONTINUE, // for (...) { if (cond) continue; <body>; $
165 LOOPCASE_CONDITIONAL_BREAK, // for (...) { if (cond) break; }
166 LOOPCASE_UNCONDITIONAL_BREAK, // for (...) { <body>; break; }
167 LOOPCASE_PRE_INCREMENT, // for (...; ++i) { <body>; }
168 LOOPCASE_POST_INCREMENT, // for (...; i++) { <body>; }
169 LOOPCASE_MIXED_BREAK_CONTINUE,
170 LOOPCASE_VECTOR_COUNTER, // for (ivec3 ndx = ...; ndx.x < ndx.y; ndx$
171 LOOPCASE_101_ITERATIONS, // loop for 101 iterations
172 LOOPCASE_SEQUENCE, // two loops in sequence
173 LOOPCASE_NESTED, // two nested loops
174 LOOPCASE_NESTED_SEQUENCE, // two loops in sequence nested inside a th$
175 LOOPCASE_NESTED_TRICKY_DATAFLOW_1, // nested loops with tricky data flow
176 LOOPCASE_NESTED_TRICKY_DATAFLOW_2, // nested loops with tricky data flow
178 //LOOPCASE_MULTI_DECLARATION, // for (int i,j,k; ...) ... -- illegal?
183 static const char* getLoopCaseName (LoopCase loopCase)
185 static const char* s_names[] =
188 "infinite_with_unconditional_break_first",
189 "infinite_with_unconditional_break_last",
190 "infinite_with_conditional_break",
192 "compound_statement",
193 "sequence_statement",
196 "select_iteration_count",
197 "conditional_continue",
198 "unconditional_continue",
202 "unconditional_break",
205 "mixed_break_continue",
211 "nested_tricky_dataflow_1",
212 "nested_tricky_dataflow_2"
213 //"multi_declaration",
216 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCASE_LAST);
217 DE_ASSERT(deInBounds32((int)loopCase, 0, LOOPCASE_LAST));
218 return s_names[(int)loopCase];
221 static const char* getLoopCountTypeName (LoopCountType countType)
223 static const char* s_names[] =
230 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == LOOPCOUNT_LAST);
231 DE_ASSERT(deInBounds32((int)countType, 0, LOOPCOUNT_LAST));
232 return s_names[(int)countType];
235 static void evalLoop0Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
236 static void evalLoop1Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(1,2,3); }
237 static void evalLoop2Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(2,3,0); }
238 static void evalLoop3Iters (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(3,0,1); }
240 static ShaderEvalFunc getLoopEvalFunc (int numIters)
242 switch (numIters % 4)
244 case 0: return evalLoop0Iters;
245 case 1: return evalLoop1Iters;
246 case 2: return evalLoop2Iters;
247 case 3: return evalLoop3Iters;
250 DE_FATAL("Invalid loop iteration count.");
256 class ShaderLoopCase : public ShaderRenderCase
259 ShaderLoopCase (tcu::TestContext& testCtx,
260 const std::string& name,
261 const std::string& description,
263 ShaderEvalFunc evalFunc,
264 UniformSetup* uniformSetup,
265 const std::string& vertexShaderSource,
266 const std::string& fragmentShaderSource)
267 : ShaderRenderCase (testCtx, name, description, isVertexCase, evalFunc, uniformSetup, DE_NULL)
269 m_vertShaderSource = vertexShaderSource;
270 m_fragShaderSource = fragmentShaderSource;
274 // Uniform setup tools
276 class LoopUniformSetup : public UniformSetup
279 LoopUniformSetup (std::vector<BaseUniformType>& types)
280 : m_uniformInformations(types)
283 virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
286 std::vector<BaseUniformType> m_uniformInformations;
289 void LoopUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
291 for (size_t i = 0; i < m_uniformInformations.size(); i++)
293 instance.useUniform((deUint32)i, m_uniformInformations[i]);
299 static de::MovePtr<ShaderLoopCase> createGenericLoopCase (tcu::TestContext& testCtx,
300 const std::string& caseName,
301 const std::string& description,
304 LoopCountType loopCountType,
305 glu::Precision loopCountPrecision,
306 glu::DataType loopCountDataType)
308 std::ostringstream vtx;
309 std::ostringstream frag;
310 std::ostringstream& op = isVertexCase ? vtx : frag;
312 vtx << "#version 310 es\n";
313 frag << "#version 310 es\n";
315 vtx << "layout(location=0) in highp vec4 a_position;\n";
316 vtx << "layout(location=1) in highp vec4 a_coords;\n";
317 frag << "layout(location=0) out mediump vec4 o_color;\n";
319 if (loopCountType == LOOPCOUNT_DYNAMIC)
320 vtx << "layout(location=3) in mediump float a_one;\n";
324 vtx << "layout(location=0) out mediump vec3 v_color;\n";
325 frag << "layout(location=0) in mediump vec3 v_color;\n";
329 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
330 frag << "layout(location=0) in mediump vec4 v_coords;\n";
332 if (loopCountType == LOOPCOUNT_DYNAMIC)
334 vtx << "layout(location=1) out mediump float v_one;\n";
335 frag << "layout(location=1) in mediump float v_one;\n";
339 const int numLoopIters = 3;
340 const bool isIntCounter = isDataTypeIntOrIVec(loopCountDataType);
341 deUint32 locationCounter = 0;
342 std::vector<BaseUniformType> uniformInformations;
346 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC)
348 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff"<< locationCounter <<" {\n";
349 op << " ${COUNTER_PRECISION} int " << getIntUniformName(numLoopIters) << ";\n";
351 uniformInformations.push_back(getIntUniformType(numLoopIters));
357 if (loopCountType == LOOPCOUNT_UNIFORM || loopCountType == LOOPCOUNT_DYNAMIC){
358 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
359 op << " ${COUNTER_PRECISION} float " << getFloatFractionUniformName(numLoopIters) << ";\n";
361 uniformInformations.push_back(getFloatFractionUniformType(numLoopIters));
365 if (numLoopIters != 1){
366 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
367 op << " ${COUNTER_PRECISION} float uf_one;\n";
369 uniformInformations.push_back(UF_ONE);
375 vtx << "void main()\n";
377 vtx << " gl_Position = a_position;\n";
380 frag << "void main()\n";
384 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
386 frag << " ${PRECISION} vec4 coords = v_coords;\n";
389 if (loopCountType == LOOPCOUNT_DYNAMIC)
394 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
396 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
401 vtx << " ${COUNTER_PRECISION} float one = a_one;\n";
403 frag << " ${COUNTER_PRECISION} float one = v_one;\n";
408 op << " ${PRECISION} vec4 res = coords;\n";
410 // Loop iteration count.
411 std::string iterMaxStr;
415 if (loopCountType == LOOPCOUNT_CONSTANT)
416 iterMaxStr = de::toString(numLoopIters);
417 else if (loopCountType == LOOPCOUNT_UNIFORM)
418 iterMaxStr = getIntUniformName(numLoopIters);
419 else if (loopCountType == LOOPCOUNT_DYNAMIC)
420 iterMaxStr = std::string(getIntUniformName(numLoopIters)) + "*one";
426 if (loopCountType == LOOPCOUNT_CONSTANT)
428 else if (loopCountType == LOOPCOUNT_UNIFORM)
429 iterMaxStr = "uf_one";
430 else if (loopCountType == LOOPCOUNT_DYNAMIC)
431 iterMaxStr = "uf_one*one";
437 std::string initValue = isIntCounter ? "0" : "0.05";
438 std::string loopCountDeclStr = "${COUNTER_PRECISION} ${LOOP_VAR_TYPE} ndx = " + initValue;
439 std::string loopCmpStr = ("ndx < " + iterMaxStr);
440 std::string incrementStr;
442 incrementStr = "ndx++";
445 if (loopCountType == LOOPCOUNT_CONSTANT)
446 incrementStr = std::string("ndx += ") + de::toString(1.0f / (float)numLoopIters);
447 else if (loopCountType == LOOPCOUNT_UNIFORM)
448 incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters);
449 else if (loopCountType == LOOPCOUNT_DYNAMIC)
450 incrementStr = std::string("ndx += ") + getFloatFractionUniformName(numLoopIters) + "*one";
456 std::string loopBody;
458 loopBody = " res = res.yzwx;\n";
460 if (loopType == LOOPTYPE_FOR)
462 op << " for (" + loopCountDeclStr + "; " + loopCmpStr + "; " + incrementStr + ")\n";
467 else if (loopType == LOOPTYPE_WHILE)
469 op << "\t" << loopCountDeclStr + ";\n";
470 op << " while (" + loopCmpStr + ")\n";
473 op << "\t\t" + incrementStr + ";\n";
476 else if (loopType == LOOPTYPE_DO_WHILE)
478 op << "\t" << loopCountDeclStr + ";\n";
482 op << "\t\t" + incrementStr + ";\n";
483 op << " } while (" + loopCmpStr + ");\n";
490 vtx << " v_color = res.rgb;\n";
491 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
495 vtx << " v_coords = a_coords;\n";
496 frag << " o_color = vec4(res.rgb, 1.0);\n";
498 if (loopCountType == LOOPCOUNT_DYNAMIC)
499 vtx << " v_one = a_one;\n";
505 // Fill in shader templates.
506 std::map<std::string, std::string> params;
507 params.insert(std::pair<std::string, std::string>("LOOP_VAR_TYPE", getDataTypeName(loopCountDataType)));
508 params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
509 params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", getPrecisionName(loopCountPrecision)));
511 tcu::StringTemplate vertTemplate(vtx.str());
512 tcu::StringTemplate fragTemplate(frag.str());
513 std::string vertexShaderSource = vertTemplate.specialize(params);
514 std::string fragmentShaderSource = fragTemplate.specialize(params);
517 ShaderEvalFunc evalFunc = getLoopEvalFunc(numLoopIters);
518 UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
519 return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
522 static de::MovePtr<ShaderLoopCase> createSpecialLoopCase (tcu::TestContext& testCtx,
523 const std::string& caseName,
524 const std::string& description,
528 LoopCountType loopCountType)
530 std::ostringstream vtx;
531 std::ostringstream frag;
532 std::ostringstream& op = isVertexCase ? vtx : frag;
534 std::vector<BaseUniformType> uniformInformations;
535 deUint32 locationCounter = 0;
537 vtx << "#version 310 es\n";
538 frag << "#version 310 es\n";
540 vtx << "layout(location=0) in highp vec4 a_position;\n";
541 vtx << "layout(location=1) in highp vec4 a_coords;\n";
542 frag << "layout(location=0) out mediump vec4 o_color;\n";
544 if (loopCountType == LOOPCOUNT_DYNAMIC)
545 vtx << "layout(location=3) in mediump float a_one;\n";
549 vtx << "layout(location=0) out mediump vec3 v_color;\n";
550 frag << "layout(location=0) in mediump vec3 v_color;\n";
554 vtx << "layout(location=0) out mediump vec4 v_coords;\n";
555 frag << "layout(location=0) in mediump vec4 v_coords;\n";
557 if (loopCountType == LOOPCOUNT_DYNAMIC)
559 vtx << "layout(location=1) out mediump float v_one;\n";
560 frag << "layout(location=1) in mediump float v_one;\n";
564 if (loopCase == LOOPCASE_SELECT_ITERATION_COUNT) {
565 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
566 op << " bool ub_true;\n";
568 uniformInformations.push_back(UB_TRUE);
575 BaseUniformType type;
578 { "ui_zero", UI_ZERO },
579 { "ui_one", UI_ONE },
580 { "ui_two", UI_TWO },
581 { "ui_three", UI_THREE },
582 { "ui_four", UI_FOUR },
583 { "ui_five", UI_FIVE },
584 { "ui_six", UI_SIX },
587 for (int i = 0; i < DE_LENGTH_OF_ARRAY(uniforms); ++i)
589 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
590 op << " ${COUNTER_PRECISION} int " << uniforms[i].name << ";\n";
592 uniformInformations.push_back(uniforms[i].type);
596 if (loopCase == LOOPCASE_101_ITERATIONS) {
598 op << "layout(std140, set=0, binding=" << locationCounter << ") uniform buff" << locationCounter << " {\n";
599 op << " ${COUNTER_PRECISION} int ui_oneHundredOne;\n";
601 uniformInformations.push_back(UI_ONEHUNDREDONE);
605 int iterCount = 3; // value to use in loop
606 int numIters = 3; // actual number of iterations
609 vtx << "void main()\n";
611 vtx << " gl_Position = a_position;\n";
614 frag << "void main()\n";
617 if (loopCountType == LOOPCOUNT_DYNAMIC)
620 vtx << " ${COUNTER_PRECISION} int one = int(a_one + 0.5);\n";
622 frag << " ${COUNTER_PRECISION} int one = int(v_one + 0.5);\n";
626 vtx << " ${PRECISION} vec4 coords = a_coords;\n";
628 frag << " ${PRECISION} vec4 coords = v_coords;\n";
631 op << " ${PRECISION} vec4 res = coords;\n";
633 // Handle all loop types.
634 std::string counterPrecisionStr = "mediump";
635 std::string forLoopStr;
636 std::string whileLoopStr;
637 std::string doWhileLoopPreStr;
638 std::string doWhileLoopPostStr;
640 if (loopType == LOOPTYPE_FOR)
644 case LOOPCASE_EMPTY_BODY:
646 op << " ${FOR_LOOP} {}\n";
649 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
651 op << " for (;;) { break; res = res.yzwx; }\n";
654 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
656 op << " for (;;) { res = res.yzwx; break; }\n";
659 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
661 op << " ${COUNTER_PRECISION} int i = 0;\n";
662 op << " for (;;) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
665 case LOOPCASE_SINGLE_STATEMENT:
666 op << " ${FOR_LOOP} res = res.yzwx;\n";
669 case LOOPCASE_COMPOUND_STATEMENT:
671 numIters = 2 * iterCount;
672 op << " ${FOR_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
675 case LOOPCASE_SEQUENCE_STATEMENT:
677 numIters = 2 * iterCount;
678 op << " ${FOR_LOOP} res = res.yzwx, res = res.yzwx;\n";
681 case LOOPCASE_NO_ITERATIONS:
684 op << " ${FOR_LOOP} res = res.yzwx;\n";
687 case LOOPCASE_SINGLE_ITERATION:
690 op << " ${FOR_LOOP} res = res.yzwx;\n";
693 case LOOPCASE_SELECT_ITERATION_COUNT:
694 op << " for (int i = 0; i < (ub_true ? ${ITER_COUNT} : 0); i++) res = res.yzwx;\n";
697 case LOOPCASE_CONDITIONAL_CONTINUE:
698 numIters = iterCount - 1;
699 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
702 case LOOPCASE_UNCONDITIONAL_CONTINUE:
703 op << " ${FOR_LOOP} { res = res.yzwx; continue; }\n";
706 case LOOPCASE_ONLY_CONTINUE:
708 op << " ${FOR_LOOP} { continue; }\n";
711 case LOOPCASE_DOUBLE_CONTINUE:
712 numIters = iterCount - 1;
713 op << " ${FOR_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; continue; }\n";
716 case LOOPCASE_CONDITIONAL_BREAK:
718 op << " ${FOR_LOOP} { if (i == ${TWO}) break; res = res.yzwx; }\n";
721 case LOOPCASE_UNCONDITIONAL_BREAK:
723 op << " ${FOR_LOOP} { res = res.yzwx; break; }\n";
726 case LOOPCASE_PRE_INCREMENT:
727 op << " for (int i = 0; i < ${ITER_COUNT}; ++i) { res = res.yzwx; }\n";
730 case LOOPCASE_POST_INCREMENT:
731 op << " ${FOR_LOOP} { res = res.yzwx; }\n";
734 case LOOPCASE_MIXED_BREAK_CONTINUE:
737 op << " ${FOR_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
740 case LOOPCASE_VECTOR_COUNTER:
741 op << " for (${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0); i.x < i.z; i.x += i.y) { res = res.yzwx; }\n";
744 case LOOPCASE_101_ITERATIONS:
745 numIters = iterCount = 101;
746 op << " ${FOR_LOOP} res = res.yzwx;\n";
749 case LOOPCASE_SEQUENCE:
752 op << " ${COUNTER_PRECISION} int i;\n";
753 op << " for (i = 0; i < ${TWO}; i++) { res = res.yzwx; }\n";
754 op << " for (; i < ${ITER_COUNT}; i++) { res = res.yzwx; }\n";
757 case LOOPCASE_NESTED:
758 numIters = 2 * iterCount;
759 op << " for (${COUNTER_PRECISION} int i = 0; i < ${TWO}; i++)\n";
761 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ITER_COUNT}; j++)\n";
762 op << " res = res.yzwx;\n";
766 case LOOPCASE_NESTED_SEQUENCE:
767 numIters = 3 * iterCount;
768 op << " for (${COUNTER_PRECISION} int i = 0; i < ${ITER_COUNT}; i++)\n";
770 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
771 op << " res = res.yzwx;\n";
772 op << " for (${COUNTER_PRECISION} int j = 0; j < ${ONE}; j++)\n";
773 op << " res = res.yzwx;\n";
777 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
779 op << " ${FOR_LOOP}\n";
781 op << " res = coords; // ignore outer loop effect \n";
782 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
783 op << " res = res.yzwx;\n";
787 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
788 numIters = iterCount;
789 op << " ${FOR_LOOP}\n";
791 op << " res = coords.wxyz;\n";
792 op << " for (${COUNTER_PRECISION} int j = 0; j < ${TWO}; j++)\n";
793 op << " res = res.yzwx;\n";
794 op << " coords = res;\n";
802 if (loopCountType == LOOPCOUNT_CONSTANT)
803 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + de::toString(iterCount) + "; i++)";
804 else if (loopCountType == LOOPCOUNT_UNIFORM)
805 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < " + getIntUniformName(iterCount) + "; i++)";
806 else if (loopCountType == LOOPCOUNT_DYNAMIC)
807 forLoopStr = std::string("for (") + counterPrecisionStr + " int i = 0; i < one*" + getIntUniformName(iterCount) + "; i++)";
811 else if (loopType == LOOPTYPE_WHILE)
815 case LOOPCASE_EMPTY_BODY:
817 op << " ${WHILE_LOOP} {}\n";
820 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
822 op << " while (true) { break; res = res.yzwx; }\n";
825 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
827 op << " while (true) { res = res.yzwx; break; }\n";
830 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
832 op << " ${COUNTER_PRECISION} int i = 0;\n";
833 op << " while (true) { res = res.yzwx; if (i == ${ONE}) break; i++; }\n";
836 case LOOPCASE_SINGLE_STATEMENT:
837 op << " ${WHILE_LOOP} res = res.yzwx;\n";
840 case LOOPCASE_COMPOUND_STATEMENT:
842 numIters = 2 * iterCount;
843 op << " ${WHILE_LOOP} { res = res.yzwx; res = res.yzwx; }\n";
846 case LOOPCASE_SEQUENCE_STATEMENT:
848 numIters = 2 * iterCount;
849 op << " ${WHILE_LOOP} res = res.yzwx, res = res.yzwx;\n";
852 case LOOPCASE_NO_ITERATIONS:
855 op << " ${WHILE_LOOP} res = res.yzwx;\n";
858 case LOOPCASE_SINGLE_ITERATION:
861 op << " ${WHILE_LOOP} res = res.yzwx;\n";
864 case LOOPCASE_SELECT_ITERATION_COUNT:
865 op << " ${COUNTER_PRECISION} int i = 0;\n";
866 op << " while (i < (ub_true ? ${ITER_COUNT} : 0)) { res = res.yzwx; i++; }\n";
869 case LOOPCASE_CONDITIONAL_CONTINUE:
870 numIters = iterCount - 1;
871 op << " ${WHILE_LOOP} { if (i == ${TWO}) continue; res = res.yzwx; }\n";
874 case LOOPCASE_UNCONDITIONAL_CONTINUE:
875 op << " ${WHILE_LOOP} { res = res.yzwx; continue; }\n";
878 case LOOPCASE_ONLY_CONTINUE:
880 op << " ${WHILE_LOOP} { continue; }\n";
883 case LOOPCASE_DOUBLE_CONTINUE:
884 numIters = iterCount - 1;
885 op << " ${WHILE_LOOP} { if (i == ${ONE}) continue; res = res.yzwx; continue; }\n";
888 case LOOPCASE_CONDITIONAL_BREAK:
890 op << " ${WHILE_LOOP} { if (i == ${THREE}) break; res = res.yzwx; }\n";
893 case LOOPCASE_UNCONDITIONAL_BREAK:
895 op << " ${WHILE_LOOP} { res = res.yzwx; break; }\n";
898 case LOOPCASE_PRE_INCREMENT:
899 numIters = iterCount - 1;
900 op << " ${COUNTER_PRECISION} int i = 0;\n";
901 op << " while (++i < ${ITER_COUNT}) { res = res.yzwx; }\n";
904 case LOOPCASE_POST_INCREMENT:
905 op << " ${COUNTER_PRECISION} int i = 0;\n";
906 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n";
909 case LOOPCASE_MIXED_BREAK_CONTINUE:
912 op << " ${WHILE_LOOP} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; }\n";
915 case LOOPCASE_VECTOR_COUNTER:
916 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
917 op << " while (i.x < i.z) { res = res.yzwx; i.x += i.y; }\n";
920 case LOOPCASE_101_ITERATIONS:
921 numIters = iterCount = 101;
922 op << " ${WHILE_LOOP} res = res.yzwx;\n";
925 case LOOPCASE_SEQUENCE:
927 numIters = iterCount - 1;
928 op << " ${COUNTER_PRECISION} int i = 0;\n";
929 op << " while (i++ < ${TWO}) { res = res.yzwx; }\n";
930 op << " while (i++ < ${ITER_COUNT}) { res = res.yzwx; }\n"; // \note skips one iteration
933 case LOOPCASE_NESTED:
934 numIters = 2 * iterCount;
935 op << " ${COUNTER_PRECISION} int i = 0;\n";
936 op << " while (i++ < ${TWO})\n";
938 op << " ${COUNTER_PRECISION} int j = 0;\n";
939 op << " while (j++ < ${ITER_COUNT})\n";
940 op << " res = res.yzwx;\n";
944 case LOOPCASE_NESTED_SEQUENCE:
945 numIters = 2 * iterCount;
946 op << " ${COUNTER_PRECISION} int i = 0;\n";
947 op << " while (i++ < ${ITER_COUNT})\n";
949 op << " ${COUNTER_PRECISION} int j = 0;\n";
950 op << " while (j++ < ${ONE})\n";
951 op << " res = res.yzwx;\n";
952 op << " while (j++ < ${THREE})\n"; // \note skips one iteration
953 op << " res = res.yzwx;\n";
957 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
959 op << " ${WHILE_LOOP}\n";
961 op << " res = coords; // ignore outer loop effect \n";
962 op << " ${COUNTER_PRECISION} int j = 0;\n";
963 op << " while (j++ < ${TWO})\n";
964 op << " res = res.yzwx;\n";
968 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
969 numIters = iterCount;
970 op << " ${WHILE_LOOP}\n";
972 op << " res = coords.wxyz;\n";
973 op << " ${COUNTER_PRECISION} int j = 0;\n";
974 op << " while (j++ < ${TWO})\n";
975 op << " res = res.yzwx;\n";
976 op << " coords = res;\n";
984 if (loopCountType == LOOPCOUNT_CONSTANT)
985 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + de::toString(iterCount) + ")";
986 else if (loopCountType == LOOPCOUNT_UNIFORM)
987 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < " + getIntUniformName(iterCount) + ")";
988 else if (loopCountType == LOOPCOUNT_DYNAMIC)
989 whileLoopStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + " while(i++ < one*" + getIntUniformName(iterCount) + ")";
995 DE_ASSERT(loopType == LOOPTYPE_DO_WHILE);
999 case LOOPCASE_EMPTY_BODY:
1001 op << " ${DO_WHILE_PRE} {} ${DO_WHILE_POST}\n";
1004 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_FIRST:
1006 op << " do { break; res = res.yzwx; } while (true);\n";
1009 case LOOPCASE_INFINITE_WITH_UNCONDITIONAL_BREAK_LAST:
1011 op << " do { res = res.yzwx; break; } while (true);\n";
1014 case LOOPCASE_INFINITE_WITH_CONDITIONAL_BREAK:
1016 op << " ${COUNTER_PRECISION} int i = 0;\n";
1017 op << " do { res = res.yzwx; if (i == ${ONE}) break; i++; } while (true);\n";
1020 case LOOPCASE_SINGLE_STATEMENT:
1021 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1024 case LOOPCASE_COMPOUND_STATEMENT:
1026 numIters = 2 * iterCount;
1027 op << " ${DO_WHILE_PRE} { res = res.yzwx; res = res.yzwx; } ${DO_WHILE_POST}\n";
1030 case LOOPCASE_SEQUENCE_STATEMENT:
1032 numIters = 2 * iterCount;
1033 op << " ${DO_WHILE_PRE} res = res.yzwx, res = res.yzwx; ${DO_WHILE_POST}\n";
1036 case LOOPCASE_NO_ITERATIONS:
1040 case LOOPCASE_SINGLE_ITERATION:
1043 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1046 case LOOPCASE_SELECT_ITERATION_COUNT:
1047 op << " ${COUNTER_PRECISION} int i = 0;\n";
1048 op << " do { res = res.yzwx; } while (++i < (ub_true ? ${ITER_COUNT} : 0));\n";
1051 case LOOPCASE_CONDITIONAL_CONTINUE:
1052 numIters = iterCount - 1;
1053 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; } ${DO_WHILE_POST}\n";
1056 case LOOPCASE_UNCONDITIONAL_CONTINUE:
1057 op << " ${DO_WHILE_PRE} { res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1060 case LOOPCASE_ONLY_CONTINUE:
1062 op << " ${DO_WHILE_PRE} { continue; } ${DO_WHILE_POST}\n";
1065 case LOOPCASE_DOUBLE_CONTINUE:
1066 numIters = iterCount - 1;
1067 op << " ${DO_WHILE_PRE} { if (i == ${TWO}) continue; res = res.yzwx; continue; } ${DO_WHILE_POST}\n";
1070 case LOOPCASE_CONDITIONAL_BREAK:
1072 op << " ${DO_WHILE_PRE} { res = res.yzwx; if (i == ${ONE}) break; } ${DO_WHILE_POST}\n";
1075 case LOOPCASE_UNCONDITIONAL_BREAK:
1077 op << " ${DO_WHILE_PRE} { res = res.yzwx; break; } ${DO_WHILE_POST}\n";
1080 case LOOPCASE_PRE_INCREMENT:
1081 op << " ${COUNTER_PRECISION} int i = 0;\n";
1082 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1085 case LOOPCASE_POST_INCREMENT:
1086 numIters = iterCount + 1;
1087 op << " ${COUNTER_PRECISION} int i = 0;\n";
1088 op << " do { res = res.yzwx; } while (i++ < ${ITER_COUNT});\n";
1091 case LOOPCASE_MIXED_BREAK_CONTINUE:
1094 op << " ${DO_WHILE_PRE} { if (i == 0) continue; else if (i == 3) break; res = res.yzwx; } ${DO_WHILE_POST}\n";
1097 case LOOPCASE_VECTOR_COUNTER:
1098 op << " ${COUNTER_PRECISION} ivec4 i = ivec4(0, 1, ${ITER_COUNT}, 0);\n";
1099 op << " do { res = res.yzwx; } while ((i.x += i.y) < i.z);\n";
1102 case LOOPCASE_101_ITERATIONS:
1103 numIters = iterCount = 101;
1104 op << " ${DO_WHILE_PRE} res = res.yzwx; ${DO_WHILE_POST}\n";
1107 case LOOPCASE_SEQUENCE:
1110 op << " ${COUNTER_PRECISION} int i = 0;\n";
1111 op << " do { res = res.yzwx; } while (++i < ${TWO});\n";
1112 op << " do { res = res.yzwx; } while (++i < ${ITER_COUNT});\n";
1115 case LOOPCASE_NESTED:
1116 numIters = 2 * iterCount;
1117 op << " ${COUNTER_PRECISION} int i = 0;\n";
1120 op << " ${COUNTER_PRECISION} int j = 0;\n";
1122 op << " res = res.yzwx;\n";
1123 op << " while (++j < ${ITER_COUNT});\n";
1124 op << " } while (++i < ${TWO});\n";
1127 case LOOPCASE_NESTED_SEQUENCE:
1128 numIters = 3 * iterCount;
1129 op << " ${COUNTER_PRECISION} int i = 0;\n";
1132 op << " ${COUNTER_PRECISION} int j = 0;\n";
1134 op << " res = res.yzwx;\n";
1135 op << " while (++j < ${TWO});\n";
1137 op << " res = res.yzwx;\n";
1138 op << " while (++j < ${THREE});\n";
1139 op << " } while (++i < ${ITER_COUNT});\n";
1142 case LOOPCASE_NESTED_TRICKY_DATAFLOW_1:
1144 op << " ${DO_WHILE_PRE}\n";
1146 op << " res = coords; // ignore outer loop effect \n";
1147 op << " ${COUNTER_PRECISION} int j = 0;\n";
1149 op << " res = res.yzwx;\n";
1150 op << " while (++j < ${TWO});\n";
1151 op << " } ${DO_WHILE_POST}\n";
1154 case LOOPCASE_NESTED_TRICKY_DATAFLOW_2:
1155 numIters = iterCount;
1156 op << " ${DO_WHILE_PRE}\n";
1158 op << " res = coords.wxyz;\n";
1159 op << " ${COUNTER_PRECISION} int j = 0;\n";
1160 op << " while (j++ < ${TWO})\n";
1161 op << " res = res.yzwx;\n";
1162 op << " coords = res;\n";
1163 op << " } ${DO_WHILE_POST}\n";
1170 doWhileLoopPreStr = std::string("\t") + counterPrecisionStr + " int i = 0;\n" + "\tdo ";
1171 if (loopCountType == LOOPCOUNT_CONSTANT)
1172 doWhileLoopPostStr = std::string(" while (++i < ") + de::toString(iterCount) + ");\n";
1173 else if (loopCountType == LOOPCOUNT_UNIFORM)
1174 doWhileLoopPostStr = std::string(" while (++i < ") + getIntUniformName(iterCount) + ");\n";
1175 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1176 doWhileLoopPostStr = std::string(" while (++i < one*") + getIntUniformName(iterCount) + ");\n";
1184 vtx << " v_color = res.rgb;\n";
1185 frag << " o_color = vec4(v_color.rgb, 1.0);\n";
1189 vtx << " v_coords = a_coords;\n";
1190 frag << " o_color = vec4(res.rgb, 1.0);\n";
1192 if (loopCountType == LOOPCOUNT_DYNAMIC)
1193 vtx << " v_one = a_one;\n";
1202 std::string threeStr;
1203 std::string iterCountStr;
1205 if (loopCountType == LOOPCOUNT_CONSTANT)
1210 iterCountStr = de::toString(iterCount);
1212 else if (loopCountType == LOOPCOUNT_UNIFORM)
1216 threeStr = "ui_three";
1217 iterCountStr = getIntUniformName(iterCount);
1219 else if (loopCountType == LOOPCOUNT_DYNAMIC)
1221 oneStr = "one*ui_one";
1222 twoStr = "one*ui_two";
1223 threeStr = "one*ui_three";
1224 iterCountStr = std::string("one*") + getIntUniformName(iterCount);
1226 else DE_ASSERT(false);
1228 // Fill in shader templates.
1229 std::map<std::string, std::string> params;
1230 params.insert(std::pair<std::string, std::string>("PRECISION", "mediump"));
1231 params.insert(std::pair<std::string, std::string>("ITER_COUNT", iterCountStr));
1232 params.insert(std::pair<std::string, std::string>("COUNTER_PRECISION", counterPrecisionStr));
1233 params.insert(std::pair<std::string, std::string>("FOR_LOOP", forLoopStr));
1234 params.insert(std::pair<std::string, std::string>("WHILE_LOOP", whileLoopStr));
1235 params.insert(std::pair<std::string, std::string>("DO_WHILE_PRE", doWhileLoopPreStr));
1236 params.insert(std::pair<std::string, std::string>("DO_WHILE_POST", doWhileLoopPostStr));
1237 params.insert(std::pair<std::string, std::string>("ONE", oneStr));
1238 params.insert(std::pair<std::string, std::string>("TWO", twoStr));
1239 params.insert(std::pair<std::string, std::string>("THREE", threeStr));
1241 tcu::StringTemplate vertTemplate(vtx.str());
1242 tcu::StringTemplate fragTemplate(frag.str());
1243 std::string vertexShaderSource = vertTemplate.specialize(params);
1244 std::string fragmentShaderSource = fragTemplate.specialize(params);
1247 UniformSetup* uniformSetup = new LoopUniformSetup(uniformInformations);
1248 ShaderEvalFunc evalFunc = getLoopEvalFunc(numIters);
1249 return de::MovePtr<ShaderLoopCase>(new ShaderLoopCase(testCtx, caseName, description, isVertexCase, evalFunc, uniformSetup, vertexShaderSource, fragmentShaderSource));
1252 class ShaderLoopTests : public tcu::TestCaseGroup
1255 ShaderLoopTests (tcu::TestContext& testCtx);
1256 virtual ~ShaderLoopTests (void);
1258 virtual void init (void);
1261 ShaderLoopTests (const ShaderLoopTests&); // not allowed!
1262 ShaderLoopTests& operator= (const ShaderLoopTests&); // not allowed!
1265 ShaderLoopTests::ShaderLoopTests(tcu::TestContext& testCtx)
1266 : TestCaseGroup(testCtx, "loops", "Loop Tests")
1270 ShaderLoopTests::~ShaderLoopTests (void)
1274 void ShaderLoopTests::init (void)
1278 static const glu::ShaderType s_shaderTypes[] =
1280 glu::SHADERTYPE_VERTEX,
1281 glu::SHADERTYPE_FRAGMENT
1284 static const glu::DataType s_countDataType[] =
1290 TestCaseGroup* genericGroup = new TestCaseGroup(m_testCtx, "generic", "Generic loop tests.");
1291 TestCaseGroup* specialGroup = new TestCaseGroup(m_testCtx, "special", "Special loop tests.");
1292 addChild(genericGroup);
1293 addChild(specialGroup);
1295 for (int loopType = 0; loopType < LOOPTYPE_LAST; loopType++)
1297 const char* loopTypeName = getLoopTypeName((LoopType)loopType);
1299 for (int loopCountType = 0; loopCountType < LOOPCOUNT_LAST; loopCountType++)
1301 const char* loopCountName = getLoopCountTypeName((LoopCountType)loopCountType);
1303 std::string groupName = std::string(loopTypeName) + "_" + std::string(loopCountName) + "_iterations";
1304 std::string groupDesc = std::string("Loop tests with ") + loopCountName + " loop counter.";
1305 TestCaseGroup* genericSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1306 TestCaseGroup* specialSubGroup = new TestCaseGroup(m_testCtx, groupName.c_str(), groupDesc.c_str());
1307 genericGroup->addChild(genericSubGroup);
1308 specialGroup->addChild(specialSubGroup);
1312 for (int precision = glu::PRECISION_MEDIUMP; precision < glu::PRECISION_LAST; precision++)
1314 const char* precisionName = getPrecisionName((glu::Precision)precision);
1316 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_countDataType); dataTypeNdx++)
1318 glu::DataType loopDataType = s_countDataType[dataTypeNdx];
1319 const char* dataTypeName = getDataTypeName(loopDataType);
1321 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1323 glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1324 const char* shaderTypeName = getShaderTypeName(shaderType);
1325 bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
1327 std::string testName = std::string("basic_") + precisionName + "_" + dataTypeName + "_" + shaderTypeName;
1328 std::string testDesc = std::string(loopTypeName) + " loop with " + precisionName + dataTypeName + " " + loopCountName + " iteration count in " + shaderTypeName + " shader.";
1329 de::MovePtr<ShaderLoopCase> testCase(createGenericLoopCase(m_testCtx, testName.c_str(), testDesc.c_str(), isVertexCase, (LoopType)loopType, (LoopCountType)loopCountType, (glu::Precision)precision, loopDataType));
1330 genericSubGroup->addChild(testCase.release());
1337 for (int loopCase = 0; loopCase < LOOPCASE_LAST; loopCase++)
1339 const char* loopCaseName = getLoopCaseName((LoopCase)loopCase);
1341 // no-iterations not possible with do-while.
1342 if ((loopCase == LOOPCASE_NO_ITERATIONS) && (loopType == LOOPTYPE_DO_WHILE))
1345 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(s_shaderTypes); shaderTypeNdx++)
1347 glu::ShaderType shaderType = s_shaderTypes[shaderTypeNdx];
1348 const char* shaderTypeName = getShaderTypeName(shaderType);
1349 bool isVertexCase = (shaderType == glu::SHADERTYPE_VERTEX);
1351 std::string name = std::string(loopCaseName) + "_" + shaderTypeName;
1352 std::string desc = std::string(loopCaseName) + " loop with " + loopTypeName + " iteration count in " + shaderTypeName + " shader.";
1353 de::MovePtr<ShaderLoopCase> testCase(createSpecialLoopCase(m_testCtx, name.c_str(), desc.c_str(), isVertexCase, (LoopCase)loopCase, (LoopType)loopType, (LoopCountType)loopCountType));
1354 specialSubGroup->addChild(testCase.release());
1363 tcu::TestCaseGroup* createLoopTests (tcu::TestContext& testCtx)
1365 return new ShaderLoopTests(testCtx);